[Libreoffice-commits] core.git: Branch 'feature/profilesafemode' - 222 commits - basctl/source basctl/uiconfig basegfx/source basegfx/test basic/qa basic/source bin/check-elf-dynamic-objects bin/test-hid-vs-ui.py chart2/source chart2/uiconfig comphelper/Library_comphelper.mk comphelper/source compilerplugins/clang configmgr/source configure.ac cui/source cui/uiconfig dbaccess/source dbaccess/uiconfig desktop/Executable_unopkg_com.mk desktop/inc desktop/source desktop/uiconfig dictionaries download.lst drawinglayer/source editeng/source extensions/source extensions/uiconfig external/clucene external/nss extras/source filter/source formula/source framework/source framework/uiconfig helpcontent2 i18nlangtag/qa i18npool/qa icon-themes/breeze icon-themes/breeze_dark idlc/inc idlc/source idl/inc idl/source include/basegfx include/basic include/comphelper include/editeng include/o3tl include/postwin.h include/rtl include/sfx2 include/svl include/svtools include/svx include/tools include/unotools include /vcl include/xmloff include/xmlreader instsetoo_native/CustomTarget_setup.mk libreofficekit/source lingucomponent/source offapi/com officecfg/registry oox/source postprocess/CustomTarget_images.mk qadevOOo/Jar_OOoRunner.mk qadevOOo/JunitTest_qadevOOo_unoapi.mk qadevOOo/Module_qadevOOo.mk qadevOOo/objdsc qadevOOo/qa qadevOOo/runner qadevOOo/tests README.md registry/Library_reg.mk reportdesign/source reportdesign/uiconfig rsc/inc rsc/source sal/Library_sal.mk sal/Library_sal_textenc.mk sal/Library_uwinapi.mk sal/rtl sal/StaticLibrary_salcpprt.mk sc/inc sc/qa scripting/source sc/source sc/uiconfig sc/UIConfig_scalc.mk sdext/source sd/inc sd/qa sd/sdi sd/source sd/uiconfig sfx2/sdi sfx2/source sfx2/uiconfig sfx2/UIConfig_sfx.mk solenv/gbuild sot/source starmath/qa starmath/source starmath/uiconfig store/Library_store.mk svl/source svl/unx svtools/inc svtools/source svx/Library_svx.mk svx/qa svx/sdi svx/source svx/uiconfig svx/UIConfig_svx.mk svx/util sw/CppunitTest_sw_ooxmlexport8.mk sw /CppunitTest_sw_ooxmlexport9.mk sw/inc sw/Library_sw.mk sw/Module_sw.mk sw/ooxmlexport_setup.mk sw/qa sw/sdi sw/source sw/uiconfig test/source tools/source translations ucb/source uitest/calc_tests uitest/demo_ui uitest/libreoffice uitest/test_main.py uitest/uitest unotools/source vcl/backendtest vcl/inc vcl/qa vcl/quartz vcl/source vcl/unx vcl/win vcl/workben winaccessibility/source writerperfect/source xmloff/CppunitTest_xmloff_tokenmap.mk xmloff/CppunitTest_xmloff_uxmloff.mk xmloff/inc xmloff/Module_xmloff.mk xmloff/qa xmloff/source xmlsecurity/source

Tue, 11 Oct 2016 01:58:36 -0700

Rebased ref, commits from common ancestor:
commit aac3d62c0bf4ed6a09b03aec9111ec42619ccc24
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Thu Sep 29 18:00:35 2016 +0200

    profilesafe: Add values for SecureUserConfig
    
    Added default values for SecureUserConfig values
    to soffice.ini/rc which enable the mechanism,
    enable by default and set a maximum of three backups
    file in packed form. Added more handy flag for easy
    decision to add compressed/uncompressed.
    
    Change-Id: I5a624c09fec4e4278314e13fc5f693ac085d5e61

diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
index e02a855..5270306 100644
--- a/comphelper/source/misc/backupfilehelper.cxx
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -103,7 +103,7 @@ namespace
             {
                 sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
                 sal_uInt64 nBytesTransfer(0);
-                sal_uInt64 nSize(getFullFileSize());
+                sal_uInt64 nSize(getPackFileSize());
 
                 // 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())))
@@ -140,7 +140,7 @@ namespace
                 sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
                 sal_uInt8 aBuffer[BACKUP_FILE_HELPER_BLOCK_SIZE];
                 sal_uInt64 nBytesTransfer(0);
-                sal_uInt64 nSize(getFullFileSize());
+                sal_uInt64 nSize(getPackFileSize());
                 std::unique_ptr< z_stream > zstream(new z_stream);
                 memset(zstream.get(), 0, sizeof(*zstream));
 
@@ -294,21 +294,22 @@ namespace
 
 
     public:
+        // create new, uncompressed entry
         PackedFileEntry(
             sal_uInt32 nFullFileSize,
-            sal_uInt32 nOffset,
             sal_uInt32 nCrc32,
             FileSharedPtr& rFile,
             bool bDoCompress)
         :   mnFullFileSize(nFullFileSize),
             mnPackFileSize(nFullFileSize),
-            mnOffset(nOffset),
+            mnOffset(0),
             mnCrc32(nCrc32),
             maFile(rFile),
             mbDoCompress(bDoCompress)
         {
         }
 
+        // create entry to be loaded as header (read_header)
         PackedFileEntry()
         :   mnFullFileSize(0),
             mnPackFileSize(0),
@@ -669,7 +670,7 @@ namespace
             return bRetval;
         }
 
-        bool tryPush(FileSharedPtr& rFileCandidate)
+        bool tryPush(FileSharedPtr& rFileCandidate, bool bCompress)
         {
             sal_uInt64 nFileSize(0);
 
@@ -724,19 +725,14 @@ namespace
                     nCrc32 = createCrc32(rFileCandidate, 0);
                 }
 
-                // create a file entry for a new file. Offset is set to 0 to 
mark
-                // the entry as new file entry
-                // the compress flag decides if entries should be compressed 
when
-                // they get written to the target package
-                static bool bUseCompression(true);
-
+                // create a file entry for a new file. Offset is set 
automatically
+                // to 0 to mark the entry as new file entry
                 maPackedFileEntryVector.push_back(
                     PackedFileEntry(
                         static_cast< sal_uInt32 >(nFileSize),
-                        0,
                         nCrc32,
                         rFileCandidate,
-                        bUseCompression));
+                        bCompress));
 
                 mbChanged = true;
             }
@@ -837,14 +833,14 @@ namespace comphelper
         return OUString(maBase + "/." + maName + ".pack");
     }
 
-    bool BackupFileHelper::tryPush()
+    bool BackupFileHelper::tryPush(bool bCompress)
     {
         if (splitBaseURL() && baseFileExists())
         {
             PackedFile aPackedFile(getName());
             FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
 
-            if (aPackedFile.tryPush(aBaseFile))
+            if (aPackedFile.tryPush(aBaseFile, bCompress))
             {
                 // reduce to allowed number and flush
                 aPackedFile.tryReduceToNumBackups(mnNumBackups);
diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx
index 206d346..17f09a3 100644
--- a/configmgr/source/components.cxx
+++ b/configmgr/source/components.cxx
@@ -613,8 +613,6 @@ Components::Components(
 
 Components::~Components()
 {
-    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());
 
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 798d60d..a9d10c3 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -569,11 +569,14 @@ void Desktop::Init()
             SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message );
         }
 
+        // test code for ProfileSafeMode to allow testing the fail
+        // of loading the office configuration initially. To use,
+        // either set to true and compile, or set a breakpoint
+        // in debugger and change the local bool
         static bool bTryHardOfficeconfigBroken(false);
 
         if (bTryHardOfficeconfigBroken)
         {
-            SAL_WARN("configmgr", "################# Desktop::Init() 
#####################");
             SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString());
         }
     }
diff --git a/include/comphelper/backupfilehelper.hxx 
b/include/comphelper/backupfilehelper.hxx
index 2c6cc25..7cb2023 100644
--- a/include/comphelper/backupfilehelper.hxx
+++ b/include/comphelper/backupfilehelper.hxx
@@ -21,10 +21,23 @@ namespace comphelper
 {
     /** Helper class to backup/restore a single file
      *
+     *  This is a general class to manage backups/restore of the file
+     *  given by the URL. The container holding the backups is created
+     *  aside the original file, e.g for 'test.txt' a container
+     *  called '.test.pack' will be used. If it was not yet backed-up
+     *  this container file will be created at the 1st backup and deleted
+     *  when the last gets removed. The container holds a stack with a
+     *  maximum given number (in the constructor) of copies, these are by
+     *  default compressed, but don't have to be (see tryPush).
+     *
+     *  Due to being on a low system level here, no UNO API and not much
+     *  other tooling can be used, as a consequence for the container a
+     *  own simple format is used and e.g. the zip lib directly.
+     *
      *  You need to hand over the URL of the file to look at and
      *  a maximum number of allowed copies. That number is internally
-     *  limited to a max of 10 (see implementation). The number of
-     *  allowed copies is limited to [1..max].
+     *  limited to a absolute max of 10 (see implementation). The number
+     *  of allowed copies is limited to [1..max].
      *
      *  Calling tryPush() will check if there is no backup yet or if
      *  there is one that the file has changed. If yes, a new copy is
@@ -102,10 +115,14 @@ namespace comphelper
          *  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 tryPush(bool bCompress = true);
 
         /** finds out if a restore is possible
          *
diff --git a/instsetoo_native/CustomTarget_setup.mk 
b/instsetoo_native/CustomTarget_setup.mk
index 173a8c6..26fc427 100644
--- a/instsetoo_native/CustomTarget_setup.mk
+++ b/instsetoo_native/CustomTarget_setup.mk
@@ -104,6 +104,7 @@ $(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
 $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call 
gb_Helper_get_rcfile,soffice) :
        $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),ECH,1)
        ( \
@@ -118,6 +119,8 @@ $(call 
gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_
                && echo 'ProgressTextBaseline=145' \
                && echo 'ProgressTextColor=255,255,255' \
                && echo 'URE_BOOTSTRAP=$${ORIGIN}/$(call 
gb_Helper_get_rcfile,fundamental)' \
+               && echo 'SecureUserConfig=true' \
+               && echo 'SecureUserConfigNumCopies=3' \
        ) > $@
 
 $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call 
gb_Helper_get_rcfile,uno) :
commit 48871a0ad3251641f1160eee85f70f07417b9f0b
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Wed Sep 28 18:14:51 2016 +0200

    profilesafe: Added zip deflate/inflate
    
    Stack of files can now deflate/inflate using zip
    library, unfortunately have to use direct due to
    Deflater/Inflater not being available, had to add
    linking against zip.lib. Checked compressed and
    uncompressed creation/usage of backup stack. Also
    warnings and clang errors corrected.
    
    Change-Id: Ieb059baeea323bb48ec5b1cf6b8df09da97cfb93

diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk
index 59869a7..344e186 100644
--- a/comphelper/Library_comphelper.mk
+++ b/comphelper/Library_comphelper.mk
@@ -40,6 +40,7 @@ $(eval $(call gb_Library_use_externals,comphelper,\
     boost_headers \
     icuuc \
     icu_headers \
+    zlib \
 ))
 
 $(eval $(call gb_Library_use_libraries,comphelper,\
diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
index 8fed178..e02a855 100644
--- a/comphelper/source/misc/backupfilehelper.cxx
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -14,9 +14,10 @@
 #include <comphelper/backupfilehelper.hxx>
 #include <rtl/crc.h>
 #include <deque>
+#include <zlib.h>
 
 typedef std::shared_ptr< osl::File > FileSharedPtr;
-static const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 1024;
+static const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 16384;
 
 namespace
 {
@@ -86,38 +87,246 @@ namespace
 
 namespace
 {
-    struct PackedFileEntry
+    class PackedFileEntry
     {
     private:
-        sal_uInt32          mnSize;     // size in bytes
-        sal_uInt32          mnOffset;   // offset in File (zero identifies new 
file)
-        sal_uInt32          mnCrc32;    // checksum
-        FileSharedPtr       maFile;     // file where to find the data (at 
offset)
+        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)
+        bool                mbDoCompress;   // flag if this file is scheduled 
to be compredded when written
+
+        bool copy_content_straight(oslFileHandle& rTargetHandle)
+        {
+            if (maFile && osl::File::E_None == 
maFile->open(osl_File_OpenFlag_Read))
+            {
+                sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt64 nBytesTransfer(0);
+                sal_uInt64 nSize(getFullFileSize());
+
+                // 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 (osl::File::E_None != 
maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                        {
+                            break;
+                        }
+
+                        if (osl_File_E_None != osl_writeFile(rTargetHandle, 
static_cast<const void*>(aArray), nToTransfer, &nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                        {
+                            break;
+                        }
+
+                        nSize -= nToTransfer;
+                    }
+                }
+
+                maFile->close();
+                return (0 == nSize);
+            }
+
+            return false;
+        }
+
+        bool copy_content_compress(oslFileHandle& rTargetHandle)
+        {
+            if (maFile && osl::File::E_None == 
maFile->open(osl_File_OpenFlag_Read))
+            {
+                sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt8 aBuffer[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt64 nBytesTransfer(0);
+                sal_uInt64 nSize(getFullFileSize());
+                std::unique_ptr< z_stream > zstream(new z_stream);
+                memset(zstream.get(), 0, sizeof(*zstream));
+
+                if (Z_OK == deflateInit(zstream.get(), 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);
+
+                        while (bOkay && nSize != 0)
+                        {
+                            const sal_uInt64 nToTransfer(std::min(nSize, 
(sal_uInt64)BACKUP_FILE_HELPER_BLOCK_SIZE));
+
+                            if (osl::File::E_None != 
maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                            {
+                                break;
+                            }
+
+                            zstream->avail_in = nToTransfer;
+                            zstream->next_in = reinterpret_cast<unsigned 
char*>(aArray);
+
+                            do {
+                                zstream->avail_out = 
BACKUP_FILE_HELPER_BLOCK_SIZE;
+                                zstream->next_out = reinterpret_cast<unsigned 
char*>(aBuffer);
+#if !defined Z_PREFIX
+                                const sal_Int64 nRetval(deflate(zstream.get(), 
nSize == nToTransfer ? Z_FINISH : Z_NO_FLUSH));
+#else
+                                const sal_Int64 
nRetval(z_deflate(zstream.get(), nSize == nToTransfer ? Z_FINISH : Z_NO_FLUSH));
+#endif
+                                if (Z_STREAM_ERROR == nRetval)
+                                {
+                                    bOkay = false;
+                                }
+                                else
+                                {
+                                    const sal_uInt64 
nAvailable(BACKUP_FILE_HELPER_BLOCK_SIZE - zstream->avail_out);
+
+                                    if (osl_File_E_None != 
osl_writeFile(rTargetHandle, static_cast<const void*>(aBuffer), nAvailable, 
&nBytesTransfer) || nBytesTransfer != nAvailable)
+                                    {
+                                        bOkay = false;
+                                    }
+                                }
+                            } while (bOkay && 0 == zstream->avail_out);
+
+                            if (!bOkay)
+                            {
+                                break;
+                            }
+
+                            nSize -= nToTransfer;
+                        }
+
+#if !defined Z_PREFIX
+                        deflateEnd(zstream.get());
+#else
+                        z_deflateEnd(zstream.get());
+#endif
+                    }
+                }
+
+                maFile->close();
+
+                // get compressed size and add to entry
+                if (mnFullFileSize == mnPackFileSize && mnFullFileSize == 
zstream->total_in)
+                {
+                    mnPackFileSize = zstream->total_out;
+                }
+
+                return (0 == nSize);
+            }
+
+            return false;
+        }
+
+        bool copy_content_uncompress(oslFileHandle& rTargetHandle)
+        {
+            if (maFile && osl::File::E_None == 
maFile->open(osl_File_OpenFlag_Read))
+            {
+                sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt8 aBuffer[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt64 nBytesTransfer(0);
+                sal_uInt64 nSize(getPackFileSize());
+                std::unique_ptr< z_stream > zstream(new z_stream);
+                memset(zstream.get(), 0, sizeof(*zstream));
+
+                if (Z_OK == inflateInit(zstream.get()))
+                {
+                    // 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);
+
+                        while (bOkay && nSize != 0)
+                        {
+                            const sal_uInt64 nToTransfer(std::min(nSize, 
(sal_uInt64)BACKUP_FILE_HELPER_BLOCK_SIZE));
+
+                            if (osl::File::E_None != 
maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                            {
+                                break;
+                            }
+
+                            zstream->avail_in = nToTransfer;
+                            zstream->next_in = reinterpret_cast<unsigned 
char*>(aArray);
+
+                            do {
+                                zstream->avail_out = 
BACKUP_FILE_HELPER_BLOCK_SIZE;
+                                zstream->next_out = reinterpret_cast<unsigned 
char*>(aBuffer);
+#if !defined Z_PREFIX
+                                const sal_Int64 nRetval(inflate(zstream.get(), 
Z_NO_FLUSH));
+#else
+                                const sal_Int64 
nRetval(z_inflate(zstream.get(), Z_NO_FLUSH));
+#endif
+                                if (Z_STREAM_ERROR == nRetval)
+                                {
+                                    bOkay = false;
+                                }
+                                else
+                                {
+                                    const sal_uInt64 
nAvailable(BACKUP_FILE_HELPER_BLOCK_SIZE - zstream->avail_out);
+
+                                    if (osl_File_E_None != 
osl_writeFile(rTargetHandle, static_cast<const void*>(aBuffer), nAvailable, 
&nBytesTransfer) || nBytesTransfer != nAvailable)
+                                    {
+                                        bOkay = false;
+                                    }
+                                }
+                            } while (bOkay && 0 == zstream->avail_out);
+
+                            if (!bOkay)
+                            {
+                                break;
+                            }
+
+                            nSize -= nToTransfer;
+                        }
+
+#if !defined Z_PREFIX
+                        deflateEnd(zstream.get());
+#else
+                        z_deflateEnd(zstream.get());
+#endif
+                    }
+                }
+
+                maFile->close();
+                return (0 == nSize);
+            }
+
+            return false;
+        }
+
 
     public:
         PackedFileEntry(
-            sal_uInt32 nSize,
+            sal_uInt32 nFullFileSize,
             sal_uInt32 nOffset,
             sal_uInt32 nCrc32,
-            FileSharedPtr& rFile)
-        :   mnSize(nSize),
+            FileSharedPtr& rFile,
+            bool bDoCompress)
+        :   mnFullFileSize(nFullFileSize),
+            mnPackFileSize(nFullFileSize),
             mnOffset(nOffset),
             mnCrc32(nCrc32),
-            maFile(rFile)
+            maFile(rFile),
+            mbDoCompress(bDoCompress)
         {
         }
 
         PackedFileEntry()
-        :   mnSize(0),
+        :   mnFullFileSize(0),
+            mnPackFileSize(0),
             mnOffset(0),
             mnCrc32(0),
-            maFile()
+            maFile(),
+            mbDoCompress(false)
+        {
+        }
+
+        sal_uInt32 getFullFileSize() const
         {
+            return  mnFullFileSize;
         }
 
-        sal_uInt32 getSize() const
+        sal_uInt32 getPackFileSize() const
         {
-            return  mnSize;
+            return  mnPackFileSize;
         }
 
         sal_uInt32 getOffset() const
@@ -142,10 +351,10 @@ namespace
                 sal_uInt8 aArray[4];
                 sal_uInt64 nBaseRead(0);
 
-                // read and compute entry size
+                // read and compute full file size
                 if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
                 {
-                    mnSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
+                    mnFullFileSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
                 }
                 else
                 {
@@ -157,6 +366,20 @@ namespace
                 {
                     mnCrc32 = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
                 }
+                else
+                {
+                    return false;
+                }
+
+                // read and compute packed size
+                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
+                {
+                    mnPackFileSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
+                }
+                else
+                {
+                    return false;
+                }
 
                 return true;
             }
@@ -169,18 +392,18 @@ namespace
             sal_uInt8 aArray[4];
             sal_uInt64 nBaseWritten(0);
 
-            // write size
-            aArray[0] = sal_uInt8((mnSize & 0xff000000) >> 24);
-            aArray[1] = sal_uInt8((mnSize & 0x00ff0000) >> 16);
-            aArray[2] = sal_uInt8((mnSize & 0x0000ff00) >> 8);
-            aArray[3] = sal_uInt8(mnSize & 0x000000ff);
+            // write full file size
+            aArray[0] = sal_uInt8((mnFullFileSize & 0xff000000) >> 24);
+            aArray[1] = sal_uInt8((mnFullFileSize & 0x00ff0000) >> 16);
+            aArray[2] = sal_uInt8((mnFullFileSize & 0x0000ff00) >> 8);
+            aArray[3] = sal_uInt8(mnFullFileSize & 0x000000ff);
 
             if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
             {
                 return false;
             }
 
-            // for each entry, write crc32
+            // write crc32
             aArray[0] = sal_uInt8((mnCrc32 & 0xff000000) >> 24);
             aArray[1] = sal_uInt8((mnCrc32 & 0x00ff0000) >> 16);
             aArray[2] = sal_uInt8((mnCrc32 & 0x0000ff00) >> 8);
@@ -191,55 +414,51 @@ namespace
                 return false;
             }
 
+            // write packed file size
+            aArray[0] = sal_uInt8((mnPackFileSize & 0xff000000) >> 24);
+            aArray[1] = sal_uInt8((mnPackFileSize & 0x00ff0000) >> 16);
+            aArray[2] = sal_uInt8((mnPackFileSize & 0x0000ff00) >> 8);
+            aArray[3] = sal_uInt8(mnPackFileSize & 0x000000ff);
+
+            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            {
+                return false;
+            }
+
             return true;
         }
 
-        bool copy_content(oslFileHandle& rTargetHandle, bool bInflate)
+        bool copy_content(oslFileHandle& rTargetHandle, bool bUncompress)
         {
-            if (maFile && osl::File::E_None == 
maFile->open(osl_File_OpenFlag_Read))
+            if (bUncompress)
             {
-                sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
-                sal_uInt64 nBytesTransfer(0);
-                sal_uInt64 nSize(getSize());
-                const bool bNewFile(0 == getOffset());
-
-                // 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())))
+                if (getFullFileSize() == getPackFileSize())
                 {
-                    if (!bInflate)
-                    {
-                        // copy-back, deflate file
-                    }
-                    else if (bNewFile)
-                    {
-                        // new file gets added, inflate initially
-                    }
-
-                    while (nSize != 0)
-                    {
-                        const sal_uInt64 nToTransfer(std::min(nSize, 
(sal_uInt64)BACKUP_FILE_HELPER_BLOCK_SIZE));
-
-                        if (osl::File::E_None != 
maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || 
nBytesTransfer != nToTransfer)
-                        {
-                            break;
-                        }
-
-                        if (osl_File_E_None != osl_writeFile(rTargetHandle, 
static_cast<const void*>(aArray), nToTransfer, &nBytesTransfer) || 
nBytesTransfer != nToTransfer)
-                        {
-                            break;
-                        }
-
-                        nSize -= nToTransfer;
-                    }
+                    // not compressed, just copy
+                    return copy_content_straight(rTargetHandle);
+                }
+                else
+                {
+                    // compressed, need to uncompress on copy
+                    return copy_content_uncompress(rTargetHandle);
+                }
+            }
+            else if (0 == getOffset())
+            {
+                if (mbDoCompress)
+                {
+                    // compressed wanted, need to compress on copy
+                    return copy_content_compress(rTargetHandle);
+                }
+                else
+                {
+                    // not compressed, straight copy
+                    return copy_content_straight(rTargetHandle);
                 }
-
-                maFile->close();
-
-                return (0 == nSize);
             }
             else
             {
-                return false;
+                return copy_content_straight(rTargetHandle);
             }
         }
     };
@@ -288,13 +507,13 @@ namespace
                                 // if there are entries (and less than max), 
read them
                                 if (nEntries >= 1 && nEntries <= 10)
                                 {
-                                    // offset in souce file starts with 8Byte 
for header+numEntries and
-                                    // 8byte for each entry (size and crc32)
-                                    sal_uInt32 nOffset(8 + (8 * nEntries));
+                                    // offset in souce file starts with 8 Byte 
for header + numEntries and
+                                    // 12 byte for each entry (size, crc32 and 
PackedSize)
+                                    sal_uInt32 nOffset(8 + (12 * nEntries));
 
                                     for (sal_uInt32 a(0); a < nEntries; a++)
                                     {
-                                        // create new entry, read header (size 
and crc) and
+                                        // create new entry, read header 
(size, crc and PackedSize),
                                         // set offset and source file
                                         PackedFileEntry aEntry;
 
@@ -304,7 +523,7 @@ namespace
                                             
maPackedFileEntryVector.push_back(aEntry);
 
                                             // increase offset for next entry
-                                            nOffset += aEntry.getSize();
+                                            nOffset += 
aEntry.getPackFileSize();
                                         }
                                         else
                                         {
@@ -373,24 +592,56 @@ namespace
                         // write number of entries
                         if (osl_File_E_None == osl_writeFile(aHandle, 
static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
                         {
-                            // write headers
-                            for (auto& candidateA : maPackedFileEntryVector)
+                            if (bRetval)
+                            {
+                                // 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. We know
+                                // the number of entries to write
+                                const sal_uInt32 nWriteSize(3 * 
maPackedFileEntryVector.size());
+                                aArray[0] = aArray[1] = aArray[2] = aArray[3] 
= 0;
+
+                                for (sal_uInt32 a(0); bRetval && a < 
nWriteSize; a++)
+                                {
+                                    if (osl_File_E_None != 
osl_writeFile(aHandle, static_cast<const void*>(aArray), 4, &nBaseWritten) || 4 
!= 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)
                             {
-                                if (!candidateA.write_header(aHandle))
+                                // seek back to header start (at position 8)
+                                if (osl_File_E_None != osl_setFilePos(aHandle, 
osl_Pos_Absolut, sal_Int64(8)))
                                 {
-                                    // error
                                     bRetval = false;
-                                    break;
                                 }
                             }
 
                             if (bRetval)
                             {
-                                // write contents
-                                for (auto& candidateB : 
maPackedFileEntryVector)
+                                // write headers
+                                for (auto& candidate : maPackedFileEntryVector)
                                 {
-                                    if (!candidateB.copy_content(aHandle, 
true))
+                                    if (!candidate.write_header(aHandle))
                                     {
+                                        // error
                                         bRetval = false;
                                         break;
                                     }
@@ -442,7 +693,7 @@ namespace
                 // already backups there, check if different from last entry
                 const PackedFileEntry& aLastEntry = 
maPackedFileEntryVector.back();
 
-                if (aLastEntry.getSize() != static_cast<sal_uInt32>(nFileSize))
+                if (aLastEntry.getFullFileSize() != 
static_cast<sal_uInt32>(nFileSize))
                 {
                     // different size, different file
                     bNeedToAdd = true;
@@ -475,12 +726,17 @@ namespace
 
                 // create a file entry for a new file. Offset is set to 0 to 
mark
                 // the entry as new file entry
+                // the compress flag decides if entries should be compressed 
when
+                // they get written to the target package
+                static bool bUseCompression(true);
+
                 maPackedFileEntryVector.push_back(
                     PackedFileEntry(
                         static_cast< sal_uInt32 >(nFileSize),
                         0,
                         nCrc32,
-                        rFileCandidate));
+                        rFileCandidate,
+                        bUseCompression));
 
                 mbChanged = true;
             }
@@ -497,7 +753,10 @@ namespace
                 // already backups there, check if different from last entry
                 PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
 
-                bRetval = aLastEntry.copy_content(rHandle, false);
+                // here the uncompress flag has to be determined, true
+                // means to add the file compressed, false means to add it
+                // uncompressed
+                bRetval = aLastEntry.copy_content(rHandle, true);
 
                 if (bRetval)
                 {
commit 358e09d19531e5685b222c8cf6f47bd7eb15506b
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Fri Sep 23 18:21:54 2016 +0200

    profilesafe: Collect copies in single *.pack file
    
    Enhanced helper classes for BackupFileHelper to
    allow writing a stack of rescued last valid
    configuration files to a single file package.
    Added configuration values for enabling this and
    defining the number of entries, added max entry
    limitation. Using FileSize and CRC32 now to dectect
    if config file did change. To make this work I added
    sorting to writing the configuration so that with no
    change the same configuration file is written.
    Use std::vector for better mem performance for sorting,
    defined static const for buffer size of manipulation,
    prepare inflate/deflate usages. Fixes to setPos, warnings
    
    Change-Id: Ib286e2a3f25b0085a1e3ae4f50c9ff1ff3a5dcf5

diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
index 7a353b8..8fed178 100644
--- a/comphelper/source/misc/backupfilehelper.cxx
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -9,232 +9,670 @@
 
 #include <sal/config.h>
 
-#include <comphelper/backupfilehelper.hxx>
 #include <rtl/ustring.hxx>
+#include <rtl/bootstrap.hxx>
+#include <comphelper/backupfilehelper.hxx>
+#include <rtl/crc.h>
+#include <deque>
 
-namespace comphelper
-{
-    sal_uInt16 BackupFileHelper::mnMaxAllowedBackups = 10;
-    bool BackupFileHelper::mbExitWasCalled = false;
+typedef std::shared_ptr< osl::File > FileSharedPtr;
+static const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 1024;
 
-    BackupFileHelper::BackupFileHelper(
-        const OUString& rBaseURL,
-        sal_uInt16 nNumBackups)
-        : mrBaseURL(rBaseURL),
-        mnNumBackups(::std::min(::std::max(nNumBackups, sal_uInt16(1)), 
mnMaxAllowedBackups)),
-        maBase(),
-        maExt(),
-        maBaseFile(rBaseURL),
-        mbBaseFileIsOpen(false)
+namespace
+{
+    OUString splitAtLastToken(const OUString& rSrc, sal_Unicode aToken, 
OUString& rRight)
     {
-    }
+        const sal_Int32 nIndex(rSrc.lastIndexOf(aToken));
+        OUString aRetval;
 
-    void BackupFileHelper::setExitWasCalled()
-    {
-        mbExitWasCalled = true;
-    }
+        if (-1 == nIndex)
+        {
+            aRetval = rSrc;
+        }
+        else if (nIndex > 0)
+        {
+            aRetval = rSrc.copy(0, nIndex);
+        }
 
-    bool BackupFileHelper::getExitWasCalled()
-    {
-        return mbExitWasCalled;
+        if (rSrc.getLength() > nIndex + 1)
+        {
+            rRight = rSrc.copy(nIndex + 1);
+        }
+
+        return aRetval;
     }
 
-    bool BackupFileHelper::tryPush()
+    sal_uInt32 createCrc32(FileSharedPtr& rCandidate, sal_uInt32 nOffset)
     {
-        if (isDifferentOrNew())
+        sal_uInt32 nCrc32(0);
+
+        if (rCandidate && osl::File::E_None == 
rCandidate->open(osl_File_OpenFlag_Read))
         {
-            // the new file is different or new, create a new first backup
-            // rename/move/cleanup other backup files, make space for new 
first backup
-            push();
+            sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
+            sal_uInt64 nBytesTransfer(0);
+            sal_uInt64 nSize(0);
 
-            // copy new one to now free 1st position
-            osl::File::copy(mrBaseURL, getName(1));
+            rCandidate->getSize(nSize);
 
-            return true;
-        }
+            // 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;
+                    }
+                }
+            }
 
-        return false;
-    }
+            rCandidate->close();
+        }
 
-    bool BackupFileHelper::isPopPossible()
-    {
-        return firstExists();
+        return nCrc32;
     }
+}
 
-    bool BackupFileHelper::tryPop()
+namespace
+{
+    struct PackedFileEntry
     {
-        if (firstExists())
+    private:
+        sal_uInt32          mnSize;     // size in bytes
+        sal_uInt32          mnOffset;   // offset in File (zero identifies new 
file)
+        sal_uInt32          mnCrc32;    // checksum
+        FileSharedPtr       maFile;     // file where to find the data (at 
offset)
+
+    public:
+        PackedFileEntry(
+            sal_uInt32 nSize,
+            sal_uInt32 nOffset,
+            sal_uInt32 nCrc32,
+            FileSharedPtr& rFile)
+        :   mnSize(nSize),
+            mnOffset(nOffset),
+            mnCrc32(nCrc32),
+            maFile(rFile)
         {
-            // first copy exists, copy over original and delete
-            const OUString aOneName(getName(1));
-            maBaseFile.close();
-            osl::File::copy(aOneName, mrBaseURL);
-            osl::File::remove(aOneName);
+        }
 
-            // rename/move/cleanup other backup files
-            pop();
+        PackedFileEntry()
+        :   mnSize(0),
+            mnOffset(0),
+            mnCrc32(0),
+            maFile()
+        {
+        }
 
-            return true;
+        sal_uInt32 getSize() const
+        {
+            return  mnSize;
         }
 
-        return false;
-    }
+        sal_uInt32 getOffset() const
+        {
+            return mnOffset;
+        }
 
-    rtl::OUString BackupFileHelper::getName(sal_uInt16 n)
-    {
-        if (maExt.isEmpty())
+        sal_uInt32 getCrc32() const
         {
-            return OUString(maBase + "_" + OUString::number(n));
+            return mnCrc32;
         }
 
-        return OUString(maBase + "_" + OUString::number(n) + "." + maExt);
-    }
+        bool read_header(
+            FileSharedPtr& rFile,
+            sal_uInt32 nOffset)
+        {
+            mnOffset = nOffset;
+            maFile = rFile;
 
-    bool BackupFileHelper::firstExists()
-    {
-        if (baseFileOpen() && splitBaseURL())
+            if (maFile)
+            {
+                sal_uInt8 aArray[4];
+                sal_uInt64 nBaseRead(0);
+
+                // read and compute entry size
+                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
+                {
+                    mnSize = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
+                }
+                else
+                {
+                    return false;
+                }
+
+                // read and compute entry crc32
+                if (osl::File::E_None == 
maFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
+                {
+                    mnCrc32 = (sal_uInt32(aArray[0]) << 24) + 
(sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + 
sal_uInt32(aArray[3]);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        bool write_header(oslFileHandle& rHandle)
         {
-            // check if 1st copy exists
-            osl::File aOneFile(getName(1));
-            const osl::FileBase::RC 
aResult(aOneFile.open(osl_File_OpenFlag_Read));
+            sal_uInt8 aArray[4];
+            sal_uInt64 nBaseWritten(0);
+
+            // write size
+            aArray[0] = sal_uInt8((mnSize & 0xff000000) >> 24);
+            aArray[1] = sal_uInt8((mnSize & 0x00ff0000) >> 16);
+            aArray[2] = sal_uInt8((mnSize & 0x0000ff00) >> 8);
+            aArray[3] = sal_uInt8(mnSize & 0x000000ff);
+
+            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            {
+                return false;
+            }
+
+            // for each entry, write crc32
+            aArray[0] = sal_uInt8((mnCrc32 & 0xff000000) >> 24);
+            aArray[1] = sal_uInt8((mnCrc32 & 0x00ff0000) >> 16);
+            aArray[2] = sal_uInt8((mnCrc32 & 0x0000ff00) >> 8);
+            aArray[3] = sal_uInt8(mnCrc32 & 0x000000ff);
+
+            if (osl_File_E_None != osl_writeFile(rHandle, static_cast<const 
void*>(aArray), 4, &nBaseWritten) || 4 != nBaseWritten)
+            {
+                return false;
+            }
 
-            return (osl::File::E_None == aResult);
+            return true;
         }
 
-        return false;
-    }
+        bool copy_content(oslFileHandle& rTargetHandle, bool bInflate)
+        {
+            if (maFile && osl::File::E_None == 
maFile->open(osl_File_OpenFlag_Read))
+            {
+                sal_uInt8 aArray[BACKUP_FILE_HELPER_BLOCK_SIZE];
+                sal_uInt64 nBytesTransfer(0);
+                sal_uInt64 nSize(getSize());
+                const bool bNewFile(0 == getOffset());
+
+                // 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())))
+                {
+                    if (!bInflate)
+                    {
+                        // copy-back, deflate file
+                    }
+                    else if (bNewFile)
+                    {
+                        // new file gets added, inflate initially
+                    }
+
+                    while (nSize != 0)
+                    {
+                        const sal_uInt64 nToTransfer(std::min(nSize, 
(sal_uInt64)BACKUP_FILE_HELPER_BLOCK_SIZE));
+
+                        if (osl::File::E_None != 
maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                        {
+                            break;
+                        }
+
+                        if (osl_File_E_None != osl_writeFile(rTargetHandle, 
static_cast<const void*>(aArray), nToTransfer, &nBytesTransfer) || 
nBytesTransfer != nToTransfer)
+                        {
+                            break;
+                        }
+
+                        nSize -= nToTransfer;
+                    }
+                }
+
+                maFile->close();
+
+                return (0 == nSize);
+            }
+            else
+            {
+                return false;
+            }
+        }
+    };
+}
+
+namespace
+{
+    typedef ::std::deque< PackedFileEntry > PackedFileEntryVector;
 
-    void BackupFileHelper::pop()
+    class PackedFile
     {
-        for (sal_uInt16 a(2); a < mnMaxAllowedBackups + 1; a++)
+    private:
+        const OUString          maURL;
+        PackedFileEntryVector   maPackedFileEntryVector;
+        bool                    mbChanged;
+
+    public:
+        PackedFile(const OUString& rURL)
+        :   maURL(rURL),
+            maPackedFileEntryVector(),
+            mbChanged(false)
         {
-            const OUString aSourceName(getName(a));
+            FileSharedPtr aSourceFile(new osl::File(rURL));
 
-            if (a > mnNumBackups + 1)
+            if (osl::File::E_None == aSourceFile->open(osl_File_OpenFlag_Read))
             {
-                // try to delete that file, it is out of scope
-                osl::File::remove(aSourceName);
+                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)
+                                {
+                                    // offset in souce file starts with 8Byte 
for header+numEntries and
+                                    // 8byte for each entry (size and crc32)
+                                    sal_uInt32 nOffset(8 + (8 * nEntries));
+
+                                    for (sal_uInt32 a(0); a < nEntries; a++)
+                                    {
+                                        // create new entry, read header (size 
and crc) and
+                                        // set offset and source file
+                                        PackedFileEntry aEntry;
+
+                                        if (aEntry.read_header(aSourceFile, 
nOffset))
+                                        {
+                                            // add to local data
+                                            
maPackedFileEntryVector.push_back(aEntry);
+
+                                            // increase offset for next entry
+                                            nOffset += aEntry.getSize();
+                                        }
+                                        else
+                                        {
+                                            // error
+                                            nEntries = 0;
+                                        }
+                                    }
+
+                                    if (0 == nEntries)
+                                    {
+                                        // on read error clear local data
+                                        maPackedFileEntryVector.clear();
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                aSourceFile->close();
             }
-            else
+
+            if (maPackedFileEntryVector.empty())
             {
-                // rename that file by decreasing index by one
-                osl::File::move(aSourceName, getName(a - 1));
+                // on error or no data get rid of pack file
+                osl::File::remove(maURL);
             }
         }
-    }
 
-    void BackupFileHelper::push()
-    {
-        for (sal_uInt16 a(0); a < mnMaxAllowedBackups; a++)
+        bool flush()
+        {
+            bool bRetval(true);
+
+            if (maPackedFileEntryVector.empty())
+            {
+                // get rid of (now?) empty pack file
+                osl::File::remove(maURL);
+            }
+            else if (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;
+                OUString aTempURL;
+
+                // open target temp file
+                if (osl::File::E_None == 
osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
+                {
+                    sal_uInt8 aArray[4];
+                    sal_uInt64 nBaseWritten(0);
+
+                    aArray[0] = 'P';
+                    aArray[1] = 'A';
+                    aArray[2] = 'C';
+                    aArray[3] = 'K';
+
+                    // write File_ID
+                    if (osl_File_E_None == osl_writeFile(aHandle, 
static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
+                    {
+                        const sal_uInt32 nSize(maPackedFileEntryVector.size());
+                        aArray[0] = sal_uInt8((nSize & 0xff000000) >> 24);
+                        aArray[1] = sal_uInt8((nSize & 0x00ff0000) >> 16);
+                        aArray[2] = sal_uInt8((nSize & 0x0000ff00) >> 8);
+                        aArray[3] = sal_uInt8(nSize & 0x000000ff);
+
+                        // write number of entries
+                        if (osl_File_E_None == osl_writeFile(aHandle, 
static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
+                        {
+                            // write headers
+                            for (auto& candidateA : maPackedFileEntryVector)
+                            {
+                                if (!candidateA.write_header(aHandle))
+                                {
+                                    // error
+                                    bRetval = false;
+                                    break;
+                                }
+                            }
+
+                            if (bRetval)
+                            {
+                                // write contents
+                                for (auto& candidateB : 
maPackedFileEntryVector)
+                                {
+                                    if (!candidateB.copy_content(aHandle, 
true))
+                                    {
+                                        bRetval = false;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // close temp file (in all cases)
+                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);
+            }
+
+            return bRetval;
+        }
+
+        bool tryPush(FileSharedPtr& rFileCandidate)
         {
-            const sal_uInt16 nIndex(mnMaxAllowedBackups - a);
-            const OUString aSourceName(getName(nIndex));
+            sal_uInt64 nFileSize(0);
+
+            if (rFileCandidate && osl::File::E_None == 
rFileCandidate->open(osl_File_OpenFlag_Read))
+            {
+                rFileCandidate->getSize(nFileSize);
+                rFileCandidate->close();
+            }
+
+            if (0 == nFileSize)
+            {
+                // empty file offered
+                return false;
+            }
 
-            if (nIndex >= mnNumBackups)
+            bool bNeedToAdd(false);
+            sal_uInt32 nCrc32(0);
+
+            if (!maPackedFileEntryVector.empty())
             {
-                // try to delete that file, it is out of scope
-                osl::File::remove(aSourceName);
+                // already backups there, check if different from last entry
+                const PackedFileEntry& aLastEntry = 
maPackedFileEntryVector.back();
+
+                if (aLastEntry.getSize() != 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;
+                    }
+                }
             }
             else
             {
-                // rename that file by increasing index by one
-                osl::File::move(aSourceName, getName(nIndex + 1));
+                // no backup yet, add
+                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 to 0 to 
mark
+                // the entry as new file entry
+                maPackedFileEntryVector.push_back(
+                    PackedFileEntry(
+                        static_cast< sal_uInt32 >(nFileSize),
+                        0,
+                        nCrc32,
+                        rFileCandidate));
+
+                mbChanged = true;
             }
+
+            return bNeedToAdd;
         }
-    }
 
-    bool BackupFileHelper::isDifferentOrNew()
-    {
-        if (baseFileOpen() && splitBaseURL())
+        bool tryPop(oslFileHandle& rHandle)
         {
-            osl::File aLastFile(getName(1));
-            const osl::FileBase::RC 
aResult(aLastFile.open(osl_File_OpenFlag_Read));
-            bool bDifferentOrNew(false);
+            bool bRetval(false);
 
-            if (osl::File::E_None == aResult)
+            if (!maPackedFileEntryVector.empty())
             {
-                // exists, check for being equal
-                bDifferentOrNew = !equalsBase(aLastFile);
+                // already backups there, check if different from last entry
+                PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
+
+                bRetval = aLastEntry.copy_content(rHandle, false);
+
+                if (bRetval)
+                {
+                    maPackedFileEntryVector.pop_back();
+                    mbChanged = true;
+                }
+
+                return bRetval;
             }
-            else if (osl::File::E_NOENT == aResult)
+
+            return false;
+        }
+
+        void tryReduceToNumBackups(sal_uInt16 nNumBackups)
+        {
+            while (maPackedFileEntryVector.size() > nNumBackups)
             {
-                // does not exist - also copy
-                bDifferentOrNew = true;
+                maPackedFileEntryVector.pop_front();
+                mbChanged = true;
             }
+        }
 
-            return bDifferentOrNew;
+        bool empty()
+        {
+            return maPackedFileEntryVector.empty();
         }
+    };
+}
 
-        return false;
+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()
+    {
+    }
+
+    void BackupFileHelper::setExitWasCalled()
+    {
+        mbExitWasCalled = true;
+    }
+
+    bool BackupFileHelper::getExitWasCalled()
+    {
+        return mbExitWasCalled;
     }
 
-    bool BackupFileHelper::equalsBase(osl::File& rLastFile)
+    bool BackupFileHelper::getSecureUserConfig(sal_uInt16& 
rnSecureUserConfigNumCopies)
     {
-        sal_uInt64 nBaseLen(0);
-        sal_uInt64 nLastLen(0);
-        maBaseFile.getSize(nBaseLen);
-        rLastFile.getSize(nLastLen);
+        // init to not active
+        bool bRetval(false);
+        rnSecureUserConfigNumCopies = 0;
+        OUString sTokenOut;
 
-        if (nBaseLen == nLastLen)
+        if (rtl::Bootstrap::get("SecureUserConfig", sTokenOut))
         {
-            // same filesize -> need to check content
-            sal_uInt8 aArrayOld[1024];
-            sal_uInt8 aArrayLast[1024];
-            sal_uInt64 nBytesReadBase(0);
-            sal_uInt64 nBytesReadLast(0);
-            bool bDiffers(false);
+            bRetval = sTokenOut.toBoolean();
+        }
+
+        if (bRetval && rtl::Bootstrap::get("SecureUserConfigNumCopies", 
sTokenOut))
+        {
+            rnSecureUserConfigNumCopies = static_cast< sal_uInt16 
>(sTokenOut.toUInt32());
+        }
+
+        return bRetval;
+    }
 
-            // both rewind on start
-            maBaseFile.setPos(0, 0);
-            rLastFile.setPos(0, 0);
+    rtl::OUString BackupFileHelper::getName()
+    {
+        return OUString(maBase + "/." + maName + ".pack");
+    }
 
-            while (!bDiffers
-                && osl::File::E_None == 
maBaseFile.read(static_cast<void*>(aArrayOld), 1024, nBytesReadBase)
-                && osl::File::E_None == 
rLastFile.read(static_cast<void*>(aArrayLast), 1024, nBytesReadLast)
-                && 0 != nBytesReadBase
-                && nBytesReadBase == nBytesReadLast)
+    bool BackupFileHelper::tryPush()
+    {
+        if (splitBaseURL() && baseFileExists())
+        {
+            PackedFile aPackedFile(getName());
+            FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
+
+            if (aPackedFile.tryPush(aBaseFile))
             {
-                bDiffers = memcmp(aArrayOld, aArrayLast, nBytesReadBase);
+                // reduce to allowed number and flush
+                aPackedFile.tryReduceToNumBackups(mnNumBackups);
+                aPackedFile.flush();
+
+                return true;
             }
+        }
+
+        return false;
+    }
+
+    bool BackupFileHelper::isPopPossible()
+    {
+        if (splitBaseURL() && baseFileExists())
+        {
+            PackedFile aPackedFile(getName());
 
-            return !bDiffers;
+            return !aPackedFile.empty();
         }
 
         return false;
     }
 
-    bool BackupFileHelper::splitBaseURL()
+    bool BackupFileHelper::tryPop()
     {
-        if (maBase.isEmpty() && !mrBaseURL.isEmpty())
+        if (splitBaseURL() && baseFileExists())
         {
-            const sal_Int32 nIndex(mrBaseURL.lastIndexOf('.'));
+            PackedFile aPackedFile(getName());
 
-            if (-1 == nIndex)
+            if (!aPackedFile.empty())
             {
-                maBase = mrBaseURL;
-            }
-            else if (nIndex > 0)
-            {
-                maBase = mrBaseURL.copy(0, nIndex);
+                oslFileHandle aHandle;
+                OUString aTempURL;
+
+                // open target temp file
+                if (osl::File::E_None == 
osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
+                {
+                    bool bRetval(aPackedFile.tryPop(aHandle));
+
+                    // close temp file (in all cases)
+                    osl_closeFile(aHandle);
+
+                    if (bRetval)
+                    {
+                        // 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);
+
+                        // reduce to allowed number and flush
+                        aPackedFile.tryReduceToNumBackups(mnNumBackups);
+                        aPackedFile.flush();
+                    }
+
+                    // delete temp file (in all cases - it may be moved 
already)
+                    osl::File::remove(aTempURL);
+
+                    return bRetval;
+                }
             }
+        }
 
-            if (mrBaseURL.getLength() > nIndex + 1)
-            {
-                maExt = mrBaseURL.copy(nIndex + 1);
-            }
+        return false;
+    }
+
+    bool BackupFileHelper::splitBaseURL()
+    {
+        if (maBase.isEmpty() && !mrBaseURL.isEmpty())
+        {
+            // split URL at extension and at last path separator
+            maBase = splitAtLastToken(splitAtLastToken(mrBaseURL, '.', maExt), 
'/', maName);
         }
 
-        return !maBase.isEmpty();
+        return !maBase.isEmpty() && !maName.isEmpty();
     }
 
-    bool BackupFileHelper::baseFileOpen()
+    bool BackupFileHelper::baseFileExists()
     {
-        if (!mbBaseFileIsOpen && !mrBaseURL.isEmpty())
+        if (!mrBaseURL.isEmpty())
         {
-            mbBaseFileIsOpen = (osl::File::E_None == 
maBaseFile.open(osl_File_OpenFlag_Read));
+            FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
+
+            return (osl::File::E_None == 
aBaseFile->open(osl_File_OpenFlag_Read));
         }
 
-        return mbBaseFileIsOpen;
+        return false;
     }
 }
 
diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx
index a193da0..206d346 100644
--- a/configmgr/source/components.cxx
+++ b/configmgr/source/components.cxx
@@ -643,18 +643,22 @@ Components::~Components()
         (*i)->setAlive(false);
     }
 
-    // test backup of registrymodifications
-    static bool bFeatureSecureUserConfig(true);
-
     if (!bExitWasCalled &&
-        bFeatureSecureUserConfig &&
         ModificationTarget::File == modificationTarget_ &&
         !modificationFileUrl_.isEmpty())
     {
-        static sal_uInt16 nNumCopies(5);
-        comphelper::BackupFileHelper aBackupFileHelper(modificationFileUrl_, 
nNumCopies);
+        // test backup of registrymodifications
+        sal_uInt16 nSecureUserConfigNumCopies(0);
+
+        // read configuration from soffice.ini
+        const bool 
bSecureUserConfig(comphelper::BackupFileHelper::getSecureUserConfig(nSecureUserConfigNumCopies));
 
-        aBackupFileHelper.tryPush();
+        if (bSecureUserConfig)
+        {
+            comphelper::BackupFileHelper 
aBackupFileHelper(modificationFileUrl_, nSecureUserConfigNumCopies);
+
+            aBackupFileHelper.tryPush();
+        }
     }
 }
 
diff --git a/configmgr/source/writemodfile.cxx 
b/configmgr/source/writemodfile.cxx
index 1d20c18..381ab00 100644
--- a/configmgr/source/writemodfile.cxx
+++ b/configmgr/source/writemodfile.cxx
@@ -400,6 +400,16 @@ void writeNode(
     }
 }
 
+// helpers to allow sorting of configmgr::Modifications::Node
+typedef std::pair< const rtl::OUString, configmgr::Modifications::Node > 
ModNodePairEntry;
+struct PairEntrySorter
+{
+    bool operator() (const ModNodePairEntry* pValue1, const ModNodePairEntry* 
pValue2) const
+    {
+        return pValue1->first.compareTo(pValue2->first) < 0;
+    }
+};
+
 void writeModifications(
     Components & components, TempFile &handle,
     OUString const & parentPathRepresentation,
@@ -459,11 +469,27 @@ void writeModifications(
         OUString pathRep(
             parentPathRepresentation + "/" +
             Data::createSegment(node->getTemplateName(), nodeName));
-        for (const auto & i : modifications.children)
+
+        // copy configmgr::Modifications::Node's to a sortable list. Use 
pointers
+        // to just reference the data instead of copying it
+        std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
+        ModNodePairEntryVector.reserve(modifications.children.size());
+
+        for (const auto& rCand : modifications.children)
+        {
+            ModNodePairEntryVector.push_back(&rCand);
+        }
+
+        // sort the list
+        std::sort(ModNodePairEntryVector.begin(), 
ModNodePairEntryVector.end(), PairEntrySorter());
+
+        // now use the list to write entries in sorted order
+        // instead of random as from the unordered map
+        for (const auto & i : ModNodePairEntryVector)
         {
             writeModifications(
-                components, handle, pathRep, node, i.first,
-                node->getMember(i.first), i.second);
+                components, handle, pathRep, node, i->first,
+                node->getMember(i->first), i->second);
         }
     }
 }
@@ -601,9 +627,31 @@ void writeModFile(
     //TODO: Do not write back information about those removed items that did 
not
     // come from the .xcs/.xcu files, anyway (but had been added dynamically
     // instead):
-    for (Modifications::Node::Children::const_iterator j(
-             data.modifications.getRoot().children.begin());
-         j != data.modifications.getRoot().children.end(); ++j)
+
+    // For profilesafemode it is necessary to detect changes in the
+    // registrymodifications file, this is done based on file size in bytes 
and crc32.
+    // Unfortunately this write is based on writing unordered map entries, 
which creates
+    // valid and semantically equal XML-Files, bubt with different crc32 
checksums. For
+    // the future usage it will be preferrable to have easily comparable 
config files
+    // which is guaranteed by writing the entries in sorted order. Indeed with 
this change
+    // (and in the recursive writeModifications call) the same config files 
get written
+
+    // copy configmgr::Modifications::Node's to a sortable list. Use pointers
+    // to just reference the data instead of copying it
+    std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
+    
ModNodePairEntryVector.reserve(data.modifications.getRoot().children.size());
+
+    for (const auto& rCand : data.modifications.getRoot().children)
+    {
+        ModNodePairEntryVector.push_back(&rCand);
+    }
+
+    // sort the list
+    std::sort(ModNodePairEntryVector.begin(), ModNodePairEntryVector.end(), 
PairEntrySorter());
+
+    // now use the list to write entries in sorted order
+    // instead of random as from the unordered map
+    for (const auto& j : ModNodePairEntryVector)
     {
         writeModifications(
             components, tmp, "", rtl::Reference< Node >(), j->first,
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 4c52d79..798d60d 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -948,11 +948,13 @@ void Desktop::HandleBootstrapErrors(
     else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
     {
         // test restore of registrymodifications
-        static bool bFeatureSecureUserConfig(true);
-        static sal_uInt16 nNumCopies(5);
+        sal_uInt16 nSecureUserConfigNumCopies(0);
         bool bFireOriginalError(true);
 
-        if (bFeatureSecureUserConfig)
+        // read configuration from soffice.ini
+        const bool 
bSecureUserConfig(comphelper::BackupFileHelper::getSecureUserConfig(nSecureUserConfigNumCopies));
+
+        if (bSecureUserConfig)
         {
             // try to asccess user layer configuration file
             OUString conf("${CONFIGURATION_LAYERS}");
@@ -977,7 +979,7 @@ void Desktop::HandleBootstrapErrors(
 
             if (!aUser.isEmpty())
             {
-                comphelper::BackupFileHelper aBackupFileHelper(aUser, 
nNumCopies);
+                comphelper::BackupFileHelper aBackupFileHelper(aUser, 
nSecureUserConfigNumCopies);
 
                 if (aBackupFileHelper.isPopPossible())
                 {
diff --git a/include/comphelper/backupfilehelper.hxx 
b/include/comphelper/backupfilehelper.hxx
index f407d2b..2c6cc25 100644
--- a/include/comphelper/backupfilehelper.hxx
+++ b/include/comphelper/backupfilehelper.hxx
@@ -15,6 +15,7 @@
 #include <comphelper/comphelperdllapi.h>
 #include <rtl/ustring.hxx>
 #include <osl/file.hxx>
+#include <memory>
 
 namespace comphelper
 {
@@ -45,12 +46,11 @@ namespace comphelper
     {
     private:
         // internal data
-        const OUString&     mrBaseURL;
-        sal_uInt16          mnNumBackups;
-        OUString            maBase;
-        OUString            maExt;
-        osl::File           maBaseFile;
-        bool                mbBaseFileIsOpen;
+        const OUString&                 mrBaseURL;
+        sal_uInt16                      mnNumBackups;
+        OUString                        maBase;
+        OUString                        maName;
+        OUString                        maExt;
 
         // internal flag if _exit() was called already - a hint to evtl.
         // not create copies of potentially not well-defined data. This
@@ -67,6 +67,10 @@ namespace comphelper
     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
          *
@@ -77,12 +81,21 @@ namespace comphelper
          *          It is used in tryPush() and tryPop() calls to cleanup/
          *          reduce the number of existing backups
          */
-        BackupFileHelper(const OUString& rBaseURL, sal_uInt16 nNumBackups = 5);
+        BackupFileHelper(
+            const OUString& rBaseURL,
+            sal_uInt16 nNumBackups = 5);
 
-        // allow to set flag when app had to call _exit()
+        // 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.
@@ -113,14 +126,9 @@ namespace comphelper
 
     private:
         // internal helper methods
-        rtl::OUString getName(sal_uInt16 n);
-        bool firstExists();
-        void pop();
-        void push();
-        bool isDifferentOrNew();
-        bool equalsBase(osl::File& rLastFile);
         bool splitBaseURL();
-        bool baseFileOpen();
+        bool baseFileExists();
+        rtl::OUString getName();
     };
 }
 
commit 5f3c1dc3db23ffdb995e9dc462f47d5c0d942100
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Thu Sep 15 12:27:28 2016 +0200

    profilesafe: Enhancements to BackupFileHelper
    
    Added helper class to allow easy creation/deployment
    of backups of a file. It works like a 'stack' of backups,
    supports easy add/remove/delete of last entry (LIFO).
    Added some work top allow opening dialogs in DeInit
    under linux.
    
    Change-Id: Idacec97ec2f097af9bd22a8a67b410c7677d17f1

diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
index 778f0a0..7a353b8 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 f7c473c..a193da0 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 bb836d2..4c52d79 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 0000000..4c332d1
--- /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 3061254..f407d2b 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.
commit 3bee40d97eba69613fc006eec1a2b5305565c3fd
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Thu Sep 1 16:16:39 2016 +0200

    profilesafe: Initial creation of BackupFileHelper
    
    Added helper class to allow easy creation/deployment
    of backups of a file (here: registrymodifications). It
    works like a 'stack' of backups, supports easy push/pop
    of backed-up versions.
    
    Change-Id: Ie19e1209534f23a3dbd6106a5ca13b24b8fefe4d

diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk
index 4d4e734..59869a7 100644
--- a/comphelper/Library_comphelper.mk
+++ b/comphelper/Library_comphelper.mk
@@ -76,6 +76,7 @@ $(eval $(call gb_Library_add_exception_objects,comphelper,\
     comphelper/source/misc/accimplaccess \
     comphelper/source/misc/anytostring \
     comphelper/source/misc/asyncnotification \
+    comphelper/source/misc/backupfilehelper \
     comphelper/source/misc/comphelper_module \
     comphelper/source/misc/comphelper_services \
     comphelper/source/misc/componentbase \
diff --git a/comphelper/source/misc/backupfilehelper.cxx 
b/comphelper/source/misc/backupfilehelper.cxx
new file mode 100644
index 0000000..778f0a0
--- /dev/null
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -0,0 +1,230 @@
+/* -*- 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/.
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/backupfilehelper.hxx>
+#include <rtl/ustring.hxx>
+
+namespace comphelper
+{
+    sal_uInt16 BackupFileHelper::mnMaxAllowedBackups = 10;
+
+    BackupFileHelper::BackupFileHelper(
+        const OUString& rBaseURL,
+        sal_uInt16 nNumBackups)
+        : mrBaseURL(rBaseURL),
+        mnNumBackups(::std::min(::std::max(nNumBackups, sal_uInt16(1)), 
mnMaxAllowedBackups)),
+        maBase(),
+        maExt(),
+        maBaseFile(rBaseURL),
+        mbBaseFileIsOpen(false)
+    {
+    }
+
+    bool BackupFileHelper::tryPush()
+    {
+        if (isDifferentOrNew())
+        {
+            // the new file is different or new, create a new first backup
+            // rename/move/cleanup other backup files, make space for new 
first backup
+            push();
+
+            // copy new one to now free 1st position
+            osl::File::copy(mrBaseURL, getName(1));
+
+            return true;
+        }
+
+        return false;
+    }
+
+    bool BackupFileHelper::isPopPossible()
+    {
+        return firstExists();
+    }
+
+    bool BackupFileHelper::tryPop()
+    {
+        if (firstExists())
+        {
+            // first copy exists, copy over original and delete
+            const OUString aOneName(getName(1));
+            maBaseFile.close();
+            osl::File::copy(aOneName, mrBaseURL);
+            osl::File::remove(aOneName);
+
+            // rename/move/cleanup other backup files
+            pop();
+
+            return true;
+        }
+
+        return false;
+    }
+
+    rtl::OUString BackupFileHelper::getName(sal_uInt16 n)
+    {
+        if (maExt.isEmpty())
+        {
+            return OUString(maBase + "_" + OUString::number(n));
+        }
+
+        return OUString(maBase + "_" + OUString::number(n) + "." + maExt);
+    }
+
+    bool BackupFileHelper::firstExists()
+    {
+        if (baseFileOpen() && splitBaseURL())
+        {
+            // check if 1st copy exists
+            osl::File aOneFile(getName(1));
+            const osl::FileBase::RC 
aResult(aOneFile.open(osl_File_OpenFlag_Read));
+
+            return (osl::File::E_None == aResult);
+        }
+
+        return false;
+    }
+
+    void BackupFileHelper::pop()
+    {
+        for (sal_uInt16 a(2); a < mnMaxAllowedBackups + 1; a++)
+        {
+            const OUString aSourceName(getName(a));
+
+            if (a > mnNumBackups + 1)
+            {
+                // try to delete that file, it is out of scope
+                osl::File::remove(aSourceName);
+            }
+            else
+            {
+                // rename that file by decreasing index by one
+                osl::File::move(aSourceName, getName(a - 1));
+            }
+        }
+    }
+
+    void BackupFileHelper::push()
+    {
+        for (sal_uInt16 a(0); a < mnMaxAllowedBackups; a++)
+        {
+            const sal_uInt16 nIndex(mnMaxAllowedBackups - a);
+            const OUString aSourceName(getName(nIndex));
+
+            if (nIndex >= mnNumBackups)
+            {
+                // try to delete that file, it is out of scope
+                osl::File::remove(aSourceName);
+            }
+            else
+            {
+                // rename that file by increasing index by one
+                osl::File::move(aSourceName, getName(nIndex + 1));
+            }
+        }
+    }
+
+    bool BackupFileHelper::isDifferentOrNew()
+    {
+        if (baseFileOpen() && splitBaseURL())
+        {
+            osl::File aLastFile(getName(1));
+            const osl::FileBase::RC 
aResult(aLastFile.open(osl_File_OpenFlag_Read));
+            bool bDifferentOrNew(false);
+
+            if (osl::File::E_None == aResult)
+            {
+                // exists, check for being equal
+                bDifferentOrNew = !equalsBase(aLastFile);
+            }
+            else if (osl::File::E_NOENT == aResult)
+            {
+                // does not exist - also copy
+                bDifferentOrNew = true;
+            }
+
+            return bDifferentOrNew;
+        }
+
+        return false;
+    }
+
+    bool BackupFileHelper::equalsBase(osl::File& rLastFile)
+    {
+        sal_uInt64 nBaseLen(0);
+        sal_uInt64 nLastLen(0);
+        maBaseFile.getSize(nBaseLen);
+        rLastFile.getSize(nLastLen);
+
+        if (nBaseLen == nLastLen)
+        {
+            // same filesize -> need to check content
+            sal_uInt8 aArrayOld[1024];
+            sal_uInt8 aArrayLast[1024];
+            sal_uInt64 nBytesReadBase(0);
+            sal_uInt64 nBytesReadLast(0);
+            bool bDiffers(false);
+
+            // both rewind on start
+            maBaseFile.setPos(0, 0);
+            rLastFile.setPos(0, 0);
+
+            while (!bDiffers
+                && osl::File::E_None == 
maBaseFile.read(static_cast<void*>(aArrayOld), 1024, nBytesReadBase)
+                && osl::File::E_None == 
rLastFile.read(static_cast<void*>(aArrayLast), 1024, nBytesReadLast)
+                && 0 != nBytesReadBase
+                && nBytesReadBase == nBytesReadLast)
+            {
+                bDiffers = memcmp(aArrayOld, aArrayLast, nBytesReadBase);
+            }
+
+            return !bDiffers;
+        }
+
+        return false;
+    }
+
+    bool BackupFileHelper::splitBaseURL()
+    {
+        if (maBase.isEmpty() && !mrBaseURL.isEmpty())
+        {
+            const sal_Int32 nIndex(mrBaseURL.lastIndexOf('.'));
+
+            if (-1 == nIndex)
+            {
+                maBase = mrBaseURL;
+            }
+            else if (nIndex > 0)
+            {
+                maBase = mrBaseURL.copy(0, nIndex);
+            }
+
+            if (mrBaseURL.getLength() > nIndex + 1)
+            {
+                maExt = mrBaseURL.copy(nIndex + 1);
+            }
+        }
+
+        return !maBase.isEmpty();
+    }
+
+    bool BackupFileHelper::baseFileOpen()
+    {
+        if (!mbBaseFileIsOpen && !mrBaseURL.isEmpty())
+        {
+            mbBaseFileIsOpen = (osl::File::E_None == 
maBaseFile.open(osl_File_OpenFlag_Read));
+        }
+
+        return mbBaseFileIsOpen;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx
index 4797a67..f7c473c 100644
--- a/configmgr/source/components.cxx
+++ b/configmgr/source/components.cxx
@@ -49,6 +49,7 @@
 #include <sal/log.hxx>
 #include <sal/types.h>
 #include <salhelper/thread.hxx>
+#include <comphelper/backupfilehelper.hxx>
 
 #include "additions.hxx"
 #include "components.hxx"
@@ -616,6 +617,22 @@ Components::~Components()
     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
         (*i)->setAlive(false);
     }
+
+    // test backup of registrymodifications (currently off)
+    static bool bFeatureSecureUserConfig(false);
+
+    if (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();
+        }
+    }
 }
 
 void Components::parseFileLeniently(
diff --git a/include/comphelper/backupfilehelper.hxx 
b/include/comphelper/backupfilehelper.hxx
new file mode 100644
index 0000000..3061254
--- /dev/null
+++ b/include/comphelper/backupfilehelper.hxx
@@ -0,0 +1,115 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_COMPHELPER_BACKUPFILEHELPER_HXX
+#define INCLUDED_COMPHELPER_BACKUPFILEHELPER_HXX
+
+#include <sal/config.h>
+
+#include <comphelper/comphelperdllapi.h>
+#include <rtl/ustring.hxx>
+
+namespace comphelper
+{
+    /** Helper class to backup/restore a single file
+     *
+     *  You need to hand over the URL of the file to look at and
+     *  a maximum number of allowed copies. That number is internally
+     *  limited to a max of 10 (see implementation). The number of
+     *  allowed copies is limited to [1..max].
+     *
+     *  Calling tryPush() will check if there is no backup yet or if
+     *  there is one that the file has changed. If yes, a new copy is
+     *  created on a kind of 'stack' of copies. Tre return value can
+     *  be used to see if a backup was indeed created.
+     *
+     *  Calling tryPop() will do the opposite: If a backup is available,
+     *  delete the orig file and re-instantiate the backup. The backup
+     *  is taken off the 'stack' of copies. The return value can be
+     *  used to check if this was done.
+     *
+     *  isPopPossible can be called to see if there is a backup available
+     *  before calling tryPop().
+     *
+     *  The 'stack' of copies works by using the same path, filename
+     *  and extension, but adding a '_1' -> '_(num_of_copy)' to it.
+     */
+    class COMPHELPER_DLLPUBLIC BackupFileHelper
+    {
+    private:
+        // internal data
+        const OUString&     mrBaseURL;
+        sal_uInt16          mnNumBackups;
+        OUString            maBase;
+        OUString            maExt;
+        osl::File           maBaseFile;
+        bool                mbBaseFileIsOpen;
+
+        // internal upper limit (max) of allowed backups
+        static sal_uInt16   mnMaxAllowedBackups;
+
+    public:
+        /** Constructor to handle Backups of the given file
+         *
+         *  @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
+         */
+        BackupFileHelper(const OUString& rBaseURL, sal_uInt16 nNumBackups = 5);
+
+        /** 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.
+         *
+         *  @return bool
+         *          returns true if a new backup was actually created
+         */
+        bool tryPush();
+
+        /** finds out if a restore is possible
+         *
+         *  @return bool
+         *          returns true if a restore to an older backup is possible
+         */
+        bool isPopPossible();
+
+        /** tries to execute a restore. Will overwrite the base file
+         *  in that case and take one version off the 'stack' of copies.
+         *  Also may cleanup older backups when NumBackups given in the
+         *  constructor has changed.
+         *
+         *  @return bool
+         *          returns true if a restore was actually created
+         */
+        bool tryPop();
+
+    private:
+        // internal helper methods
+        rtl::OUString getName(sal_uInt16 n);
+        bool firstExists();
+        void pop();
+        void push();
+        bool isDifferentOrNew();
+        bool equalsBase(osl::File& rLastFile);
+        bool splitBaseURL();
+        bool baseFileOpen();
+    };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 5ab5779bf4a16f4ee4a8d1198ffbd8f842f2edd9
Author: Stephan Bergmann <sberg...@redhat.com>
Date:   Tue Oct 11 09:39:21 2016 +0200

    external/nss: Adapt ASan/UBSan-specific patches to nss 3.27
    
    Change-Id: Ic96a57a1f43f7aae4e0733d2e65edd843b827a54

diff --git a/external/nss/asan.patch.1 b/external/nss/asan.patch.1
index 3b64aa6..0685adb 100644
--- a/external/nss/asan.patch.1
+++ b/external/nss/asan.patch.1
@@ -1,12 +1,12 @@
 diff -ur nss.org/nss/coreconf/Linux.mk nss/nss/coreconf/Linux.mk
 --- nss.org/nss/coreconf/Linux.mk      2014-05-06 04:36:01.817838877 +0200
 +++ nss/nss/coreconf/Linux.mk  2014-05-06 04:37:25.387835456 +0200
-@@ -145,7 +145,7 @@
- # The linker on Red Hat Linux 7.2 and RHEL 2.1 (GNU ld version 2.11.90.0.8)
- # incorrectly reports undefined references in the libraries we link with, so
+@@ -158,7 +158,7 @@
  # we don't use -z defs there.
+ # Also, -z defs conflicts with Address Sanitizer, which emits relocations
+ # against the libsanitizer runtime built into the main executable.
 -ZDEFS_FLAG            = -Wl,-z,defs
 +ZDEFS_FLAG            =
- DSO_LDOPTS            += $(if $(findstring 2.11.90.0.8,$(shell ld 
-v)),,$(ZDEFS_FLAG)) -Wl,-z,origin '-Wl,-rpath,$$ORIGIN'
- LDFLAGS                       += $(ARCHFLAG)
- 
+ ifneq ($(USE_ASAN),1)
+ DSO_LDOPTS             += $(if $(findstring 2.11.90.0.8,$(shell ld 
-v)),,$(ZDEFS_FLAG)) -Wl,-z,origin '-Wl,-rpath,$$ORIGIN'
+ endif

... etc. - the rest is truncated
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to