/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// set offset in source file - should be zero due to crc32 should // only be needed to be created for new entries, gets loaded with old // ones if (osl::File::E_None == rCandidate->setPos(osl_Pos_Absolut, sal_Int64(nOffset)))
{ while (nSize != 0)
{ const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
if (osl::File::E_None == rCandidate->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) && nBytesTransfer == nToTransfer)
{ // add to crc and reduce size
nCrc32 = rtl_crc32(nCrc32, static_cast<void*>(aArray), static_cast<sal_uInt32>(nBytesTransfer));
nSize -= nToTransfer;
} else
{ // error - reset to zero again
nSize = nCrc32 = 0;
}
}
}
if (!aAttrUrl.isEmpty())
{ for (constauto& enable : rToBeEnabled)
{ if (-1 != aAttrUrl.indexOf(enable.getName()))
{ if (!bEnabled)
{ // needs to be enabled
rElement->removeAttribute(u"revoked"_ustr);
bChanged = true;
}
}
}
for (constauto& disable : rToBeDisabled)
{ if (-1 != aAttrUrl.indexOf(disable.getName()))
{ if (bEnabled)
{ // needs to be disabled
rElement->setAttribute(u"revoked"_ustr, u"true"_ustr);
bChanged = true;
}
}
}
}
} else
{
uno::Reference< xml::dom::XNodeList > aList = rElement->getChildNodes();
if (aList.is())
{ const sal_Int32 nLength(aList->getLength());
for (sal_Int32 a(0); a < nLength; a++)
{ const uno::Reference< xml::dom::XElement > aChild(aList->item(a), uno::UNO_QUERY);
// set output stream and do the serialization
xSaxWriter->setOutputStream(xOutStrm);
xSerializer->serialize(xSaxWriter, uno::Sequence< beans::StringPair >());
// get URL from temp file
OUString aTempURL = xTempFile->getUri();
// copy back file if (aTempURL.isEmpty() || !DirectoryHelper::fileExists(aTempURL)) return;
if (DirectoryHelper::fileExists(rUnoPackagReg))
{
osl::File::remove(rUnoPackagReg);
}
// create current configuration if (maEntries.empty())
{
createUsingXExtensionManager();
}
// open target temp file and write current configuration to it - it exists until deleted if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, &aHandle, &rTempFileName))
{
bRetval = write_entries(aHandle);
// close temp file - it exists until deleted
osl_closeFile(aHandle);
}
return bRetval;
}
bool areThereEnabledExtensions() const
{ for (constauto& a : maEntries)
{ if (a.isEnabled())
{ returntrue;
}
}
returnfalse;
}
};
}
namespace
{ class PackedFileEntry
{ private:
sal_uInt32 mnFullFileSize; // size in bytes of unpacked original file
sal_uInt32 mnPackFileSize; // size in bytes in file backup package (smaller if compressed, same if not)
sal_uInt32 mnOffset; // offset in File (zero identifies new file)
sal_uInt32 mnCrc32; // checksum
FileSharedPtr maFile; // file where to find the data (at offset) boolconst mbDoCompress; // flag if this file is scheduled to be compressed when written
// set offset in source file - when this is zero, a new file is to be added if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
{ while (nSize != 0)
{ const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
if (Z_OK == deflateInit(&zstream, Z_BEST_COMPRESSION))
{ // set offset in source file - when this is zero, a new file is to be added if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
{ bool bOkay(true);
if (Z_OK == inflateInit(&zstream))
{ // set offset in source file - when this is zero, a new file is to be added if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
{ bool bOkay(true);
if (osl::File::E_None == aSourceFile->open(osl_File_OpenFlag_Read))
{
sal_uInt64 nBaseLen(0);
aSourceFile->getSize(nBaseLen);
// we need at least File_ID and num entries -> 8byte if (8 < nBaseLen)
{
sal_uInt8 aArray[4];
sal_uInt64 nBaseRead(0);
// read and check File_ID if (osl::File::E_None == aSourceFile->read(static_cast< void* >(aArray), 4, nBaseRead) && 4 == nBaseRead)
{ if ('P' == aArray[0] && 'A' == aArray[1] && 'C' == aArray[2] && 'K' == aArray[3])
{ // read and compute num entries in this file if (osl::File::E_None == aSourceFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
{
sal_uInt32 nEntries((sal_uInt32(aArray[0]) << 24) + (sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + sal_uInt32(aArray[3]));
// if there are entries (and less than max), read them if (nEntries >= 1 && nEntries <= 10)
{ for (sal_uInt32 a(0); a < nEntries; a++)
{ // create new entry, read header (size, crc and PackedSize), // set offset and source file
PackedFileEntry aEntry;
if (aEntry.read_header(aSourceFile))
{ // add to local data
maPackedFileEntryVector.push_back(aEntry);
} else
{ // error
nEntries = 0;
}
}
if (0 == nEntries)
{ // on read error clear local data
maPackedFileEntryVector.clear();
} else
{ // calculate and set offsets to file binary content
sal_uInt32 nHeaderSize(8);
for (auto& b : maPackedFileEntryVector)
{
b.setOffset(nOffset);
nOffset += b.getPackFileSize();
}
}
}
}
}
}
}
aSourceFile->close();
}
if (maPackedFileEntryVector.empty())
{ // on error or no data get rid of pack file
osl::File::remove(maURL);
}
}
void flush()
{ bool bRetval(true);
if (maPackedFileEntryVector.empty())
{ // get rid of (now?) empty pack file
osl::File::remove(maURL);
} elseif (mbChanged)
{ // need to create a new pack file, do this in a temp file to which data // will be copied from local file (so keep it here until this is done)
oslFileHandle aHandle = nullptr;
OUString aTempURL;
// open target temp file - it exists until deleted if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
{
sal_uInt8 aArray[4];
sal_uInt64 nBaseWritten(0);
// write number of entries if (write_sal_uInt32(aHandle, nSize))
{ // write placeholder for headers. Due to the fact that // PackFileSize for newly added files gets set during // writing the content entry, write headers after content // is written. To do so, write placeholders here
sal_uInt32 nWriteSize(0);
for (sal_uInt32 a(0); bRetval && a < nWriteSize; a++)
{ if (osl_File_E_None != osl_writeFile(aHandle, static_cast<constvoid*>(aArray), 1, &nBaseWritten) || 1 != nBaseWritten)
{
bRetval = false;
}
}
if (bRetval)
{ // write contents - this may adapt PackFileSize for new // files for (auto& candidate : maPackedFileEntryVector)
{ if (!candidate.copy_content(aHandle, false))
{
bRetval = false; break;
}
}
}
if (bRetval)
{ // seek back to header start (at position 8) if (osl_File_E_None != osl_setFilePos(aHandle, osl_Pos_Absolut, sal_Int64(8)))
{
bRetval = false;
}
}
if (bRetval)
{ // write headers for (constauto& candidate : maPackedFileEntryVector)
{ if (!candidate.write_header(aHandle))
{ // error
bRetval = false; break;
}
}
}
}
}
}
// close temp file (in all cases) - it exists until deleted
osl_closeFile(aHandle);
if (bRetval)
{ // copy over existing file by first deleting original // and moving the temp file to old original
osl::File::remove(maURL);
osl::File::move(aTempURL, maURL);
}
// delete temp file (in all cases - it may be moved already)
osl::File::remove(aTempURL);
}
}
if (maPackedFileEntryVector.empty())
{ // no backup yet, add as 1st backup
bNeedToAdd = true;
} else
{ // already backups there, check if different from last entry const PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
// check if file is different if (aLastEntry.getFullFileSize() != static_cast<sal_uInt32>(nFileSize))
{ // different size, different file
bNeedToAdd = true;
} else
{ // same size, check crc32
nCrc32 = createCrc32(rFileCandidate, 0);
if (nCrc32 != aLastEntry.getCrc32())
{ // different crc, different file
bNeedToAdd = true;
}
}
}
if (bNeedToAdd)
{ // create crc32 if not yet done if (0 == nCrc32)
{
nCrc32 = createCrc32(rFileCandidate, 0);
}
// create a file entry for a new file. Offset is set automatically // to 0 to mark the entry as new file entry
maPackedFileEntryVector.emplace_back( static_cast< sal_uInt32 >(nFileSize),
nCrc32,
rFileCandidate,
bCompress);
mbChanged = true;
}
return bNeedToAdd;
}
bool tryPop(oslFileHandle& rHandle)
{ if (maPackedFileEntryVector.empty()) returnfalse;
// already backups there, check if different from last entry
PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
// here the uncompress flag has to be determined, true // means to add the file compressed, false means to add it // uncompressed bool bRetval = aLastEntry.copy_content(rHandle, true);
if (bRetval)
{
maPackedFileEntryVector.pop_back();
mbChanged = true;
}
const OUString& BackupFileHelper::getInitialBaseURL()
{ if (maInitialBaseURL.isEmpty())
{ // try to access user layer configuration file URL, the one that // points to registrymodifications.xcu
OUString conf(u"${CONFIGURATION_LAYERS}"_ustr);
rtl::Bootstrap::expandMacros(conf); static constexpr OUString aTokenUser(u"user:"_ustr);
sal_Int32 nStart(conf.indexOf(aTokenUser));
if (!maInitialBaseURL.isEmpty())
{ // split URL at extension and at last path separator
maUserConfigBaseURL = DirectoryHelper::splitAtLastToken(
DirectoryHelper::splitAtLastToken(maInitialBaseURL, '.', maExt), '/',
maRegModName);
}
if (!maUserConfigBaseURL.isEmpty())
{ // check if SafeModeDir exists
mbSafeModeDirExists = DirectoryHelper::dirExists(maUserConfigBaseURL + "/" + getSafeModeName());
}
maUserConfigWorkURL = maUserConfigBaseURL;
if (mbSafeModeDirExists)
{ // adapt work URL to do all repair op's in the correct directory
maUserConfigWorkURL += "/" + getSafeModeName();
}
}
if (mbActive)
{ // ensure existence
getInitialBaseURL();
// if not found, we are out of business (maExt may be empty)
mbActive = !maInitialBaseURL.isEmpty() && !maUserConfigBaseURL.isEmpty() && !maRegModName.isEmpty();
}
if (mbActive && rtl::Bootstrap::get(u"SecureUserConfigNumCopies"_ustr, sTokenOut))
{ const sal_uInt16 nConfigNumCopies(static_cast<sal_uInt16>(sTokenOut.toUInt32()));
// limit to range [1..mnMaxAllowedBackups]
mnNumBackups = std::clamp(mnNumBackups, nConfigNumCopies, mnMaxAllowedBackups);
}
if (mbActive && rtl::Bootstrap::get(u"SecureUserConfigMode"_ustr, 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(u"SecureUserConfigExtensions"_ustr, sTokenOut))
{
mbExtensions = sTokenOut.toBoolean();
}
void BackupFileHelper::reactOnSafeMode(bool bSafeMode)
{ // ensure existence of needed paths
getInitialBaseURL();
if (maUserConfigBaseURL.isEmpty()) return;
if (bSafeMode)
{ if (!mbSafeModeDirExists)
{
std::set< OUString > aExcludeList;
// do not move SafeMode directory itself
aExcludeList.insert(getSafeModeName());
// init SafeMode by creating the 'SafeMode' directory and moving // all stuff there. All repairs will happen there. Both Dirs have to exist. // extend maUserConfigWorkURL as needed
maUserConfigWorkURL = maUserConfigBaseURL + "/" + getSafeModeName();
// switch local flag, maUserConfigWorkURL is already reset
mbSafeModeDirExists = true;
}
} else
{ if (mbSafeModeDirExists)
{ // SafeMode has ended, return to normal mode by moving all content // from 'SafeMode' directory back to UserDirectory and deleting it. // Both Dirs have to exist
std::set< OUString > aExcludeList;
// switch local flag and reset maUserConfigWorkURL
mbSafeModeDirExists = false;
maUserConfigWorkURL = maUserConfigBaseURL;
}
}
}
void BackupFileHelper::tryPush()
{ // no push when SafeModeDir exists, it may be Office's exit after SafeMode // where SafeMode flag is already deleted, but SafeModeDir cleanup is not // done yet (is done at next startup) if (!mbActive || mbSafeModeDirExists) return;
const OUString aPackURL(getPackURL());
// ensure dir and file vectors
fillDirFileInfo();
// process all files in question recursively if (!maDirs.empty() || !maFiles.empty())
{
tryPush_Files(
maDirs,
maFiles,
maUserConfigWorkURL,
aPackURL);
}
}
void BackupFileHelper::tryPushExtensionInfo()
{ // no push when SafeModeDir exists, it may be Office's exit after SafeMode // where SafeMode flag is already deleted, but SafeModeDir cleanup is not // done yet (is done at next startup) if (mbActive && mbExtensions && !mbSafeModeDirExists)
{ const OUString aPackURL(getPackURL());
// process all files in question recursively if (!maDirs.empty() || !maFiles.empty())
{
bDidPop = tryPop_files(
maDirs,
maFiles,
maUserConfigWorkURL,
aPackURL);
}
if (bDidPop)
{ // try removal of evtl. empty directory
osl::Directory::remove(aPackURL);
}
}
if (bDidPop)
{ // try removal of evtl. empty directory
osl::Directory::remove(aPackURL);
}
}
bool BackupFileHelper::isTryDisableAllExtensionsPossible()
{ // check if there are still enabled extension which can be disabled, // but as we are now in SafeMode, use XML infos for this since the // extensions are not loaded from XExtensionManager class ExtensionInfo aExtensionInfo;
void BackupFileHelper::tryDisableAllExtensions()
{ // disable all still enabled extensions, // but as we are now in SafeMode, use XML infos for this since the // extensions are not loaded from XExtensionManager
ExtensionInfo aCurrentExtensionInfo; const ExtensionInfoEntryVector aToBeEnabled{};
ExtensionInfoEntryVector aToBeDisabled;
const std::vector< OUString >& BackupFileHelper::getCustomizationDirNames()
{ static std::vector< OUString > aDirNames =
{
u"config"_ustr, // UI config stuff
u"registry"_ustr, // most of the registry stuff
u"psprint"_ustr, // not really needed, can be abandoned
u"store"_ustr, // not really needed, can be abandoned
u"temp"_ustr, // not really needed, can be abandoned
u"pack"_ustr // own backup dir
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.