[Libreoffice-commits] core.git: Branch 'feature/mar-updater' - 591 commits - accessibility/inc accessibility/source avmedia/inc avmedia/source basctl/inc basctl/source basegfx/source basegfx/test basic/inc basic/qa basic/source bin/gen-boost-headers bin/lo-commit-stat bin/oss-fuzz-build.sh bin/update chart2/AllLangResTarget_chartcontroller.mk chart2/inc chart2/qa chart2/source cli_ure/source codemaker/source comphelper/qa comphelper/source compilerplugins/clang config_host/config_features.h.in config_host.mk.in configmgr/qa configmgr/source configure.ac connectivity/AllLangResTarget_sdbcl.mk connectivity/inc connectivity/Library_hsqldb.mk connectivity/Module_connectivity.mk connectivity/source cppcanvas/inc cppcanvas/Library_cppcanvas.mk cppcanvas/source cppuhelper/source cppu/qa cui/AllLangResTarget_cui.mk cui/inc cui/Library_cui.mk cui/source cui/uiconfig dbaccess/AllLangResTarget_dbu.mk dbaccess/inc dbaccess/source desktop/AllLangResTarget_deploymentgui.mk desktop/CppunitTest_desktop_app.mk de sktop/inc desktop/Library_crashreport.mk desktop/Library_sofficeapp.mk desktop/qa desktop/source dictionaries download.lst drawinglayer/qa drawinglayer/source editeng/inc editeng/source extensions/AllLangResTarget_bib.mk extensions/AllLangResTarget_updchk.mk extensions/inc extensions/Library_updatecheckui.mk extensions/Module_extensions.mk extensions/qa extensions/source external/boost external/coinmp external/firebird external/harfbuzz external/icu external/libcdr external/libebook external/libfreehand external/libmspub external/libvisio external/pdfium external/redland extras/source filter/inc filter/source forms/inc forms/source formula/inc formula/Library_forui.mk formula/source fpicker/inc fpicker/Library_fps_office.mk fpicker/source framework/AllLangResTarget_fwe.mk framework/inc framework/source g helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/source i18nlangtag/qa i18nlangtag/source i18npool/qa i18npool/source i18nutil/source icon-themes/breeze icon-themes/breez e_dark icon-themes/breeze_svg icon-themes/elementary icon-themes/galaxy icon-themes/hicontrast icon-themes/oxygen icon-themes/sifr icon-themes/tango idl/inc idl/source include/avmedia include/basegfx include/basic include/com include/comphelper include/connectivity include/drawinglayer include/editeng include/filter include/formula include/i18nlangtag include/linguistic include/o3tl include/onlineupdate include/oox include/rtl include/sfx2 include/sot include/svl include/svtools include/svx include/toolkit include/tools include/ucbhelper include/unotools include/vcl include/xmloff jvmfwk/plugins jvmfwk/source l10ntools/inc l10ntools/source lingucomponent/source linguistic/source lotuswordpro/source m4/ax_boost_locale.m4 Makefile.fetch Makefile.gbuild Makefile.in mysqlc/source o3tl/qa odk/docs offapi/com officecfg/files.mk officecfg/registry onlineupdate/astyle.options onlineupdate/Executable_mar.mk onlineupdate/Executable_mbsdiff.mk onlineupdate/Executable_updater.mk onlineupdate/Ex ecutable_update_service.mk onlineupdate/inc onlineupdate/Module_onlineupdate.mk onlineupdate/README onlineupdate/source onlineupdate/StaticLibrary_libmar.mk onlineupdate/StaticLibrary_updatehelper.mk onlineupdate/StaticLibrary_winhelper.mk onlineupdate/WinResTarget_updater.mk oox/inc oox/source opencl/inc opencl/source package/source postprocess/CustomTarget_images.mk postprocess/CustomTarget_registry.mk postprocess/Rdb_services.mk readlicense_oo/license reportdesign/inc reportdesign/source RepositoryExternal.mk Repository.mk rsc/inc rsc/source sal/cppunittester sal/osl sal/qa sal/rtl sax/source scaddins/AllLangResTarget_analysis.mk scaddins/source sc/AllLangResTarget_sc.mk sccomp/source sc/inc sc/Module_sc.mk scp2/inc scp2/source sc/qa scripting/source sc/sdi sc/source sc/uiconfig sd/AllLangResTarget_sd.mk sdext/inc sdext/Library_PresentationMinimizer.mk sdext/source sd/inc sd/Module_sd.mk sd/qa sd/sdi sd/source sd/uiconfig sfx2/AllLangResTarget_sfx2.mk sfx2/inc sfx2/sdi sfx2/sourc e shell/source slideshow/inc slideshow/source solenv/bin solenv/CompilerTest_compilerplugins_clang.mk solenv/gbuild sot/inc sot/source starmath/inc starmath/qa starmath/sdi starmath/source starmath/uiconfig svgio/source svl/qa svl/source svtools/AllLangResTarget_svt.mk svtools/inc svtools/source svx/AllLangResTarget_svx.mk svx/inc svx/sdi svx/source sw/AllLangResTarget_sw.mk sw/inc sw/Module_sw.mk sw/qa sw/sdi sw/source sw/uiconfig test/source testtools/source toolkit/source tools/Library_tl.mk tools/qa tools/source translations ucbhelper/source ucb/source UnoControls/source unodevtools/source unotest/source unotools/inc unotools/source uui/source vbahelper/inc vbahelper/source vcl/AllLangResTarget_vcl.mk vcl/android vcl/CppunitTest_vcl_errorhandler.mk vcl/Executable_ww6fuzzer.mk vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/Module_vcl.mk vcl/null vcl/opengl vcl/osx vcl/qa vcl/source vcl/unx vcl/vcl.android.component vcl/win vcl/workben wizards/AllLangResTarget_wzi.mk wizards/ com wizards/Module_wizards.mk wizards/Package_template.mk wizards/Pyuno_commonwizards.mk wizards/source writerfilter/inc writerfilter/source writerperfect/inc writerperfect/qa writerperfect/source xmlhelp/source xmloff/inc xmloff/qa xmloff/source xmlsecurity/Executable_pdfverify.mk xmlsecurity/inc xmlsecurity/Module_xmlsecurity.mk xmlsecurity/source xmlsecurity/workben

Markus Mohrhard markus.mohrhard at googlemail.com
Wed May 3 01:35:34 UTC 2017


Rebased ref, commits from common ancestor:
commit 047ae4b3e9003bf6dfe513869cb4caf5595ffc7b
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed May 3 00:36:06 2017 +0200

    without the wb+ reading the patch file will fail
    
    Change-Id: I61be299647d41bb464bea039630ddd4ff545f412

diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx
index 57ac77507a8b..3c5baca1e3ac 100644
--- a/onlineupdate/source/update/updater/updater.cxx
+++ b/onlineupdate/source/update/updater/updater.cxx
@@ -1610,7 +1610,7 @@ PatchFile::Prepare()
 
     NS_tremove(spath);
 
-    mPatchStream = NS_tfopen(spath, NS_T("wb"));
+    mPatchStream = NS_tfopen(spath, NS_T("wb+"));
     if (!mPatchStream)
         return WRITE_ERROR;
 
commit ee992c1549fa0ec9b570b43caee8f84899703e38
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 28 01:28:28 2017 +0200

    log all the updater actions
    
    Change-Id: Ia7b08c4e93d5b3b65b0f44af9c92f5e6f6fafd96

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index cad36200daaa..b57b3d1879ba 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -233,6 +233,7 @@ void update()
 
 void CreateValidUpdateDir(const update_info& update_info)
 {
+    Updater::log(OString("Create Update Dir"));
     OUString aInstallDir("$BRAND_BASE_DIR");
     rtl::Bootstrap::expandMacros(aInstallDir);
     OUString aInstallPath = getPathFromURL(aInstallDir);
@@ -255,6 +256,7 @@ void CreateValidUpdateDir(const update_info& update_info)
     {
         // TODO: remove the update directory
         SAL_WARN("desktop.updater", "failed to update");
+        Updater::log(OUString("failed to create update dir"));
     }
     else
     {
@@ -471,6 +473,7 @@ size_t WriteCallbackFile(void *ptr, size_t size,
 
 std::string download_content(const OString& rURL, bool bFile, OUString& rHash)
 {
+    Updater::log("Download: " + rURL);
     CURL* curl = curl_easy_init();
 
     if (!curl)
@@ -606,7 +609,7 @@ void update_checker()
     OUString aDownloadCheckURL = aDownloadCheckBaseURL + "update/check/1/" + aProductName +
         "/" + aBuildID + "/" + aBuildTarget + "/" + "/" + aChannel;
     OString aURL = OUStringToOString(aDownloadCheckURL, RTL_TEXTENCODING_UTF8);
-
+    Updater::log("Update check: " + aURL);
 
     try
     {
@@ -620,10 +623,16 @@ void update_checker()
                 // No update currently available
                 // add entry to updating.log with the message
                 SAL_WARN("desktop.updater", "Message received from the updater: " << aUpdateInfo.aMessage);
+                Updater::log("Server response: " + aUpdateInfo.aMessage);
             }
             else
             {
                 download_file(aUpdateInfo.aUpdateFile.aURL, aUpdateInfo.aUpdateFile.nSize, aUpdateInfo.aUpdateFile.aHash, "update.mar");
+                for (auto& lang_update : aUpdateInfo.aLanguageFiles)
+                {
+                    OUString aFileName = "update_" + lang_update.aLangCode + ".mar";
+                    download_file(lang_update.aUpdateFile.aURL, lang_update.aUpdateFile.nSize, lang_update.aUpdateFile.aHash, aFileName);
+                }
                 CreateValidUpdateDir(aUpdateInfo);
             }
         }
@@ -631,22 +640,27 @@ void update_checker()
     catch (const invalid_update_info&)
     {
         SAL_WARN("desktop.updater", "invalid update information");
+        Updater::log(OString("warning: invalid update info"));
     }
     catch (const error_updater&)
     {
         SAL_WARN("desktop.updater", "error during the update check");
+        Updater::log(OString("warning: error by the updater"));
     }
     catch (const invalid_size& e)
     {
         SAL_WARN("desktop.updater", e.what());
+        Updater::log(OString("warning: invalid size"));
     }
     catch (const invalid_hash& e)
     {
         SAL_WARN("desktop.updater", e.what());
+        Updater::log(OString("warning: invalid hash"));
     }
     catch (...)
     {
         SAL_WARN("desktop.updater", "unknown error during the update check");
+        Updater::log(OString("warning: unknown exception"));
     }
 }
 
@@ -658,6 +672,14 @@ OUString Updater::getUpdateInfoURL()
     return aUpdateInfoURL;
 }
 
+OUString Updater::getUpdateInfoLog()
+{
+    OUString aUpdateInfoURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/updating.log");
+    rtl::Bootstrap::expandMacros(aUpdateInfoURL);
+
+    return aUpdateInfoURL;
+}
+
 OUString Updater::getPatchDirURL()
 {
     OUString aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
@@ -682,4 +704,20 @@ OUString Updater::getExecutableDirURL()
     return aExeDir;
 }
 
+void Updater::log(const OUString& rMessage)
+{
+    OUString aUpdateLog = getUpdateInfoLog();
+    SvFileStream aLog(aUpdateLog, StreamMode::STD_READWRITE);
+    aLog.Seek(aLog.Tell() + aLog.remainingSize()); // make sure we are at the end
+    aLog.WriteLine(OUStringToOString(rMessage, RTL_TEXTENCODING_UTF8));
+}
+
+void Updater::log(const OString& rMessage)
+{
+    OUString aUpdateLog = getUpdateInfoLog();
+    SvFileStream aLog(aUpdateLog, StreamMode::STD_READWRITE);
+    aLog.Seek(aLog.Tell() + aLog.remainingSize()); // make sure we are at the end
+    aLog.WriteLine(rMessage);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/app/updater.hxx b/desktop/source/app/updater.hxx
index b36c1f91b306..f3f28bc638ec 100644
--- a/desktop/source/app/updater.hxx
+++ b/desktop/source/app/updater.hxx
@@ -23,10 +23,13 @@ private:
 public:
 
     static OUString getUpdateInfoURL();
+    static OUString getUpdateInfoLog();
     static OUString getPatchDirURL();
     static OUString getUpdateDirURL();
     static OUString getExecutableDirURL();
 
+    static void log(const OUString& rMessage);
+    static void log(const OString& rMessage);
 };
 
 #endif
commit 29d50ff876a9b5250a7179897757ea8d77baf4a9
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Apr 27 03:02:22 2017 +0200

    fix errors in upload scripts
    
    Change-Id: I0ee9fbef7b80e5d37800b4fb9daff7e8ba46d65d

diff --git a/bin/update/create_build_config.py b/bin/update/create_build_config.py
index 163e94a4426f..8d6bf5206ce8 100755
--- a/bin/update/create_build_config.py
+++ b/bin/update/create_build_config.py
@@ -17,7 +17,7 @@ def update_all_url_entries(data, **kwargs):
         for partial in data['partials']:
             partial['file']['url'] = replace_variables_in_string(partial['file']['url'], **kwargs)
 
-            for lang, lang_file in partial['languages'].iter():
+            for lang, lang_file in partial['languages'].items():
                 lang_file['url'] = replace_variables_in_string(lang_file['url'], **kwargs)
 
 def main(argv):
diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index a9d7aa2b9fe5..38919542d6a4 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -12,8 +12,6 @@ from path import UpdaterPath
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
-def ensure_dir_exist()
-
 def main():
     if len(sys.argv) < 5:
         print("Usage: create_full_mar_for_languages.py $PRODUCTNAME $WORKDIR $FILENAMEPREFIX $UPDATE_CONFIG")
commit a317c0cb99597ab5fbf8fc2829e826dc3638aa7c
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Apr 27 01:30:19 2017 +0200

    integrate the partial update info into the uploaded info
    
    Change-Id: I1b6fc7970d3010c63ae910d55103efb504e15b53

diff --git a/Makefile.gbuild b/Makefile.gbuild
index 44637577da52..61ad648aad79 100644
--- a/Makefile.gbuild
+++ b/Makefile.gbuild
@@ -35,12 +35,12 @@ create-update-info:
 	mkdir -p $(MAR_DIR)/language
 	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
 	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar_for_languages.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
-	$(SRCDIR)/bin/update/create_build_config.py "$(PRODUCTNAME)" "$(VERSION)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 
 upload-update-info:
 	$(eval BUILDID := $(shell git -C $(SRCDIR) log -1 --format=%H))
 	$(eval PLATFORM := $(RTL_OS)_$(RTL_ARCH))
 	$(eval UPDATE_DIR := $(WORKDIR)/update-info)
+	$(SRCDIR)/bin/update/create_build_config.py "$(PRODUCTNAME)" "$(VERSION)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 	$(SRCDIR)/bin/update/upload_builds.py "$(PRODUCTNAME)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 	$(SRCDIR)/bin/update/upload_build_config.py "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 
diff --git a/bin/update/create_build_config.py b/bin/update/create_build_config.py
index 8d0cf0e07cbe..163e94a4426f 100755
--- a/bin/update/create_build_config.py
+++ b/bin/update/create_build_config.py
@@ -13,6 +13,13 @@ def update_all_url_entries(data, **kwargs):
     for language in data['languages']:
         language['complete']['url'] = replace_variables_in_string(language['complete']['url'], **kwargs)
 
+    if 'partials' in data:
+        for partial in data['partials']:
+            partial['file']['url'] = replace_variables_in_string(partial['file']['url'], **kwargs)
+
+            for lang, lang_file in partial['languages'].iter():
+                lang_file['url'] = replace_variables_in_string(lang_file['url'], **kwargs)
+
 def main(argv):
     if len(argv) < 7:
         print("Usage: create_build_config.py $PRODUCTNAME $VERSION $BUILDID $PLATFORM $TARGETDIR $UPDATE_CONFIG")
@@ -26,7 +33,7 @@ def main(argv):
             'platform' : argv[4]
             }
 
-    extra_data_files = ['complete_info.json', 'complete_lang_info.json']
+    extra_data_files = ['complete_info.json', 'complete_lang_info.json', 'partial_update_info.json']
 
     for extra_file in extra_data_files:
         extra_file_path = os.path.join(argv[5], extra_file)
commit f69530a3dee66c7cbae437a6811f2e52f18ae66a
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Apr 27 00:07:43 2017 +0200

    use file instead of complete for the key of the partial update info
    
    Change-Id: Ifbb482a4fd9c1c92e9cdd7769d4b16160de14a86

diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
index 419a8f65226b..23d4f6fe6a90 100755
--- a/bin/update/create_partial_update.py
+++ b/bin/update/create_partial_update.py
@@ -129,7 +129,7 @@ def main():
         subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, update["complete"], current_build_path])
         sign_mar_file(update_dir, config, mar_file, mar_name_prefix)
 
-        partial_info = {"complete":get_file_info(mar_file, config.base_url), "from": build, "to": build_id, "languages": {}}
+        partial_info = {"file":get_file_info(mar_file, config.base_url), "from": build, "to": build_id, "languages": {}}
         for lang, lang_info in update["languages"].items():
             lang_name = generate_lang_file_name(build_id, build, mar_name_prefix, lang)
 
commit d73a7b1e2bdbece1bf7de193acfba053c966907e
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 23:58:57 2017 +0200

    add missing file
    
    Change-Id: I7cd9d541b90f4f6b38aa5e36e295e7677bb22f58

diff --git a/bin/update/path.py b/bin/update/path.py
new file mode 100644
index 000000000000..1bc14d70d940
--- /dev/null
+++ b/bin/update/path.py
@@ -0,0 +1,52 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/.
+#
+
+import os
+import errno
+
+def mkdir_p(path):
+    try:
+        os.makedirs(path)
+    except OSError as exc:  # Python >2.5
+        if exc.errno == errno.EEXIST and os.path.isdir(path):
+            pass
+        else:
+            raise
+
+class UpdaterPath(object):
+
+    def __init__(self, workdir):
+        self._workdir = workdir
+
+    def get_workdir(self):
+        return self._workdir
+
+    def get_update_dir(self):
+        return os.path.join(self._workdir, "update-info")
+
+    def get_current_build_dir(self):
+        return os.path.join(self._workdir, "mar", "current-build")
+
+    def get_mar_dir(self):
+        return os.path.join(self._workdir, "mar")
+
+    def get_previous_build_dir(self):
+        return os.path.join(self._workdir, "mar", "previous-build")
+
+    def get_language_dir(self):
+        return os.path.join(self.get_mar_dir(), "language")
+    
+    def ensure_dir_exist(self):
+        mkdir_p(self.get_update_dir())
+        mkdir_p(self.get_current_build_dir())
+        mkdir_p(self.get_mar_dir())
+        mkdir_p(self.get_previous_build_dir())
+        mkdir_p(self.get_language_dir())
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
commit 318aee0aee85ec169102d766759fb3c027ebd839
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 23:58:05 2017 +0200

    use the shared signing code
    
    Change-Id: Ica0fad83820569623f3cc2f0217ac9cd8ee19257

diff --git a/bin/update/create_full_mar_for_languages.py b/bin/update/create_full_mar_for_languages.py
index 98e1b1c539e7..039521dd10af 100755
--- a/bin/update/create_full_mar_for_languages.py
+++ b/bin/update/create_full_mar_for_languages.py
@@ -9,6 +9,7 @@ from tools import uncompress_file_to_dir, get_file_info
 
 from config import parse_config
 from path import UpdaterPath
+from signing import sign_mar_file
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
@@ -38,8 +39,6 @@ def main():
 
     config = parse_config(update_config)
 
-    mar_executable = os.environ.get('MAR', 'mar')
-
     language_pack_dir = os.path.join(workdir, "installation", product_name + "_languagepack", "archive", "install")
     language_packs = os.listdir(language_pack_dir)
     lang_infos = []
@@ -56,9 +55,7 @@ def main():
 
         subprocess.call([os.path.join(current_dir_path, 'make_full_update.sh'), mar_file_name, directory])
 
-        signed_mar_file = make_complete_mar_name(target_dir, filename_prefix + '_signed', language)
-        subprocess.call([mar_executable, '-C', target_dir, '-d', config.certificate_path, '-n', config.certificate_name, '-s', mar_file_name, signed_mar_file])
-        os.rename(signed_mar_file, mar_file_name)
+        sign_mar_file(target_dir, config, mar_file_name, filename_prefix)
 
         lang_infos.append(create_lang_infos(mar_file_name, language, config.base_url))
 
commit f8f6abdda6c34e036be4e6604e98ec696eb8b19b
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 23:49:31 2017 +0200

    simplify path handling in the updater scripts
    
    Change-Id: Idcf7f9cedc2368f6a4e4e10c2852cc9b1125b712

diff --git a/Makefile.gbuild b/Makefile.gbuild
index ed08c6217d13..44637577da52 100644
--- a/Makefile.gbuild
+++ b/Makefile.gbuild
@@ -32,12 +32,10 @@ create-update-info:
 	$(eval MAR_DIR := $(WORKDIR)/mar)
 	rm -rf $(MAR_DIR) || true
 	rm -rf $(UPDATE_DIR) || true
-	mkdir -p $(UPDATE_DIR)
-	mkdir -p $(MAR_DIR)/current-build
 	mkdir -p $(MAR_DIR)/language
-	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/current-build/" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
-	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar_for_languages.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/language" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
-	$(SRCDIR)/bin/update/create_build_config.py "$(PRODUCTNAME)" "$(VERSION)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)" "$(UPDATE_CONFIG)"
+	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
+	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar_for_languages.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)"
+	$(SRCDIR)/bin/update/create_build_config.py "$(PRODUCTNAME)" "$(VERSION)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 
 upload-update-info:
 	$(eval BUILDID := $(shell git -C $(SRCDIR) log -1 --format=%H))
@@ -51,11 +49,6 @@ create-partial-info:
 	$(eval VERSION := $(LIBO_VERSION_MAJOR).$(LIBO_VERSION_MINOR).$(LIBO_VERSION_MICRO).$(LIBO_VERSION_PATCH)$(LIBO_VERSION_SUFFIX)$(LIBO_VERSION_SUFFIX_SUFFIX))
 	$(eval PLATFORM := $(RTL_OS)_$(RTL_ARCH))
 	$(eval MAR_NAME_PREFIX := $(PRODUCTNAME)_$(VERSION)_$(PLATFORM)_$(BUILDID))
-	$(eval UPDATE_DIR := $(WORKDIR)/update-info)
-	$(eval MAR_DIR := $(WORKDIR)/mar)
-	$(eval CURRENT_BUILD := $(WORKDIR)/mar/current-build/)
-	mkdir -p $(UPDATE_DIR)
-	mkdir -p $(UPDATE_DIR)/previous-builds
-	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_partial_update.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/previous-builds/" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)" "$(PLATFORM)" "$(CURRENT_BUILD)" "$(BUILDID)" "$(MAR_DIR)"
+	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_partial_update.py "$(WORKDIR)" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)" "$(PLATFORM)" "$(BUILDID)"
 
 # vim: set noet sw=4 ts=4:
diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index 649eafe2bfa6..a9d7aa2b9fe5 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -8,19 +8,19 @@ import json
 from tools import uncompress_file_to_dir, get_file_info, make_complete_mar_name
 from config import parse_config
 from signing import sign_mar_file
+from path import UpdaterPath
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
+def ensure_dir_exist()
+
 def main():
-    print(sys.argv)
-    if len(sys.argv) < 7:
-        print("Usage: create_full_mar_for_languages.py $PRODUCTNAME $WORKDIR $TARGETDIR $TEMPDIR $FILENAMEPREFIX $UPDATE_CONFIG")
+    if len(sys.argv) < 5:
+        print("Usage: create_full_mar_for_languages.py $PRODUCTNAME $WORKDIR $FILENAMEPREFIX $UPDATE_CONFIG")
         sys.exit(1)
 
-    update_config = sys.argv[6]
-    filename_prefix = sys.argv[5]
-    temp_dir = sys.argv[4]
-    target_dir = sys.argv[3]
+    update_config = sys.argv[4]
+    filename_prefix = sys.argv[3]
     workdir = sys.argv[2]
     product_name = sys.argv[1]
 
@@ -28,6 +28,12 @@ def main():
         print("missing update config")
         sys.exit(1)
 
+    update_path = UpdaterPath(workdir)
+    update_path.ensure_dir_exist()
+
+    target_dir = update_path.get_update_dir()
+    temp_dir = update_path.get_current_build_dir()
+
     config = parse_config(update_config)
 
     tar_dir = os.path.join(workdir, "installation", product_name, "archive", "install", "en-US")
diff --git a/bin/update/create_full_mar_for_languages.py b/bin/update/create_full_mar_for_languages.py
index 7daf5fe6034e..98e1b1c539e7 100755
--- a/bin/update/create_full_mar_for_languages.py
+++ b/bin/update/create_full_mar_for_languages.py
@@ -8,6 +8,7 @@ import json
 from tools import uncompress_file_to_dir, get_file_info
 
 from config import parse_config
+from path import UpdaterPath
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
@@ -22,18 +23,19 @@ def create_lang_infos(mar_file_name, language, url):
     return data
 
 def main():
-    print(sys.argv)
-    if len(sys.argv) < 7:
+    if len(sys.argv) < 5:
         print("Usage: create_full_mar_for_languages.py $PRODUCTNAME $WORKDIR $TARGETDIR $TEMPDIR $FILENAMEPREFIX $UPDATE_CONFIG")
         sys.exit(1)
 
-    update_config = sys.argv[6]
-    filename_prefix = sys.argv[5]
-    temp_dir = sys.argv[4]
-    target_dir = sys.argv[3]
+    update_config = sys.argv[4]
+    filename_prefix = sys.argv[3]
     workdir = sys.argv[2]
     product_name = sys.argv[1]
 
+    updater_path = UpdaterPath(workdir)
+    target_dir = updater_path.get_update_dir()
+    temp_dir = updater_path.get_language_dir()
+
     config = parse_config(update_config)
 
     mar_executable = os.environ.get('MAR', 'mar')
diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
index ca194325d20d..419a8f65226b 100755
--- a/bin/update/create_partial_update.py
+++ b/bin/update/create_partial_update.py
@@ -10,12 +10,19 @@ import json
 
 from config import parse_config
 from uncompress_mar import extract_mar
-from tools import get_file_info
+from tools import get_file_info, get_hash
 from signing import sign_mar_file
 
+from path import UpdaterPath, mkdir_p
+
 BUF_SIZE = 1024
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
+def InvalidFileException(Exception):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(self, *args, **kwargs)
+
 def download_file(filepath, url, hash_string):
     with open(filepath, "wb") as f:
         response = requests.get(url, stream=True)
@@ -26,26 +33,10 @@ def download_file(filepath, url, hash_string):
         for block in response.iter_content(1024):
             f.write(block)
 
-    with open(filepath, "rb") as f:
-        sha512 = hashlib.sha512()
-        while True:
-            data = f.read(BUF_SIZE)
-            if not data:
-                break
-            sha512.update(data)
-        file_hash = sha512.hexdigest()
+    file_hash = get_hash(filepath)
 
     if file_hash != hash_string:
-        pass
-
-def mkdir_p(path):
-    try:
-        os.makedirs(path)
-    except OSError as exc:  # Python >2.5
-        if exc.errno == errno.EEXIST and os.path.isdir(path):
-            pass
-        else:
-            raise
+        raise InvalidFileException()
 
 def handle_language(lang_entries, filedir):
     mar = os.environ.get('MAR', 'mar')
@@ -109,16 +100,20 @@ def add_single_dir(path):
     return dir_name[0]
 
 def main():
-    product_name = sys.argv[1]
-    workdir = sys.argv[2]
-    update_dir = sys.argv[3]
-    temp_dir = sys.argv[4]
-    mar_name_prefix = sys.argv[5]
-    update_config = sys.argv[6]
-    platform = sys.argv[7]
-    current_build_path = sys.argv[8]
-    build_id = sys.argv[9]
-    mar_dir = sys.argv[10]
+    workdir = sys.argv[1]
+
+    updater_path = UpdaterPath(workdir)
+    updater_path.ensure_dir_exist()
+
+    mar_name_prefix = sys.argv[2]
+    update_config = sys.argv[3]
+    platform = sys.argv[4]
+    build_id = sys.argv[5]
+
+    current_build_path = updater_path.get_current_build_dir()
+    mar_dir = updater_path.get_mar_dir()
+    temp_dir = updater_path.get_previous_build_dir()
+    update_dir = updater_path.get_update_dir()
 
     current_build_path = add_single_dir(current_build_path)
 
commit 48af0c7f68aeaa87f651508b49d127999ba14edf
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 06:18:06 2017 +0200

    create valid partial language updates and write partial update info
    
    Change-Id: I4000523cfc944657714267958836dd3ce4ec3b0d

diff --git a/Makefile.gbuild b/Makefile.gbuild
index dbf0e0d40888..ed08c6217d13 100644
--- a/Makefile.gbuild
+++ b/Makefile.gbuild
@@ -56,6 +56,6 @@ create-partial-info:
 	$(eval CURRENT_BUILD := $(WORKDIR)/mar/current-build/)
 	mkdir -p $(UPDATE_DIR)
 	mkdir -p $(UPDATE_DIR)/previous-builds
-	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_partial_update.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/previous-builds/" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)" "$(PLATFORM)" "$(CURRENT_BUILD)" "$(BUILDID)"
+	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_partial_update.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/previous-builds/" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)" "$(PLATFORM)" "$(CURRENT_BUILD)" "$(BUILDID)" "$(MAR_DIR)"
 
 # vim: set noet sw=4 ts=4:
diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
index 0382f82e79d3..ca194325d20d 100755
--- a/bin/update/create_partial_update.py
+++ b/bin/update/create_partial_update.py
@@ -6,9 +6,12 @@ import hashlib
 import os
 import subprocess
 import errno
+import json
 
 from config import parse_config
 from uncompress_mar import extract_mar
+from tools import get_file_info
+from signing import sign_mar_file
 
 BUF_SIZE = 1024
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
@@ -94,13 +97,17 @@ def download_mar_for_update_channel_and_platform(config, platform, temp_dir):
     return downloaded_updates
 
 def generate_file_name(current_build_id, old_build_id, mar_name_prefix):
-    name = "%s_from_%s_to_%s_partial.mar" %(mar_name_prefix, current_build_id, old_build_id)
+    name = "%s_from_%s_partial.mar" %(mar_name_prefix, old_build_id)
     return name
 
 def generate_lang_file_name(current_build_id, old_build_id, mar_name_prefix, lang):
-    name = "%s_%s_from_%s_to_%s_partial.mar" %(mar_name_prefix, lang, current_build_id, old_build_id)
+    name = "%s_%s_from_%s_partial.mar" %(mar_name_prefix, lang, old_build_id)
     return name
 
+def add_single_dir(path):
+    dir_name =  [os.path.join(path, name) for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))]
+    return dir_name[0]
+
 def main():
     product_name = sys.argv[1]
     workdir = sys.argv[2]
@@ -111,25 +118,42 @@ def main():
     platform = sys.argv[7]
     current_build_path = sys.argv[8]
     build_id = sys.argv[9]
-    dir_name =  [os.path.join(current_build_path, name) for name in os.listdir(current_build_path) if os.path.isdir(os.path.join(current_build_path, name))]
-    current_build_path = dir_name[0]
+    mar_dir = sys.argv[10]
+
+    current_build_path = add_single_dir(current_build_path)
 
     config = parse_config(update_config)
 
     updates = download_mar_for_update_channel_and_platform(config, platform, temp_dir)
 
-    print(updates)
+    data = {"partials": []}
+
     for build, update in updates.items():
         file_name = generate_file_name(build_id, build, mar_name_prefix)
-        mar_file = os.path.join(temp_dir, build, file_name)
-        print(mar_file)
-        print(current_build_path)
-        print(update["complete"])
-        subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, current_build_path, update["complete"]])
-        for lang in update["languages"].items():
+        mar_file = os.path.join(update_dir, file_name)
+        subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, update["complete"], current_build_path])
+        sign_mar_file(update_dir, config, mar_file, mar_name_prefix)
+
+        partial_info = {"complete":get_file_info(mar_file, config.base_url), "from": build, "to": build_id, "languages": {}}
+        for lang, lang_info in update["languages"].items():
             lang_name = generate_lang_file_name(build_id, build, mar_name_prefix, lang)
-            lang_mar_file = os.path.join(temp_dir, build, lang_name)
-            #subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, current_build_path, update["complete"]])
+
+            # write the file into the final directory
+            lang_mar_file = os.path.join(update_dir, lang_name)
+
+            # the directory of the old language file is of the form
+            # workdir/mar/language/en-US/LibreOffice_<version>_<os>_archive_langpack_<lang>/
+            language_dir = add_single_dir(os.path.join(mar_dir, "language", lang))
+            subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), lang_mar_file, lang_info, language_dir])
+            sign_mar_file(update_dir, config, lang_mar_file, mar_name_prefix)
+
+            # add the partial language info
+            partial_info["languages"][lang] = get_file_info(lang_mar_file, config.base_url)
+
+        data["partials"].append(partial_info)
+
+    with open(os.path.join(update_dir, "partial_update_info.json"), "w") as f:
+        json.dump(data, f)
 
 
 if __name__ == '__main__':
commit 819a791d72c399c2a69045c1a6b5ced0a507af90
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 02:43:25 2017 +0200

    add the generation of partial update files to the makefiles
    
    It seems that the generated partial update files are now generated
    correctly. We now need to handle languages and sign the partial files as
    well as upload them.
    
    Change-Id: I69fbdad42da2c8a2d9695bc852956b82ce773f4c

diff --git a/Makefile.gbuild b/Makefile.gbuild
index 6d625bb5e5fc..dbf0e0d40888 100644
--- a/Makefile.gbuild
+++ b/Makefile.gbuild
@@ -46,4 +46,16 @@ upload-update-info:
 	$(SRCDIR)/bin/update/upload_builds.py "$(PRODUCTNAME)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 	$(SRCDIR)/bin/update/upload_build_config.py "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 
+create-partial-info:
+	$(eval BUILDID := $(shell git -C $(SRCDIR) log -1 --format=%H))
+	$(eval VERSION := $(LIBO_VERSION_MAJOR).$(LIBO_VERSION_MINOR).$(LIBO_VERSION_MICRO).$(LIBO_VERSION_PATCH)$(LIBO_VERSION_SUFFIX)$(LIBO_VERSION_SUFFIX_SUFFIX))
+	$(eval PLATFORM := $(RTL_OS)_$(RTL_ARCH))
+	$(eval MAR_NAME_PREFIX := $(PRODUCTNAME)_$(VERSION)_$(PLATFORM)_$(BUILDID))
+	$(eval UPDATE_DIR := $(WORKDIR)/update-info)
+	$(eval MAR_DIR := $(WORKDIR)/mar)
+	$(eval CURRENT_BUILD := $(WORKDIR)/mar/current-build/)
+	mkdir -p $(UPDATE_DIR)
+	mkdir -p $(UPDATE_DIR)/previous-builds
+	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_partial_update.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/previous-builds/" "$(MAR_NAME_PREFIX)" "$(UPDATE_CONFIG)" "$(PLATFORM)" "$(CURRENT_BUILD)" "$(BUILDID)"
+
 # vim: set noet sw=4 ts=4:
diff --git a/Makefile.in b/Makefile.in
index f0788001f881..055a129ad4c2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -419,6 +419,9 @@ create-update-info:
 upload-update-info:
 	$(MAKE) -f $(SRCDIR)/Makefile.gbuild upload-update-info
 
+create-partial-info:
+	$(MAKE) -f $(SRCDIR)/Makefile.gbuild create-partial-info
+
 dump-deps:
 	@$(SRCDIR)/bin/module-deps.pl $(MAKE) $(SRCDIR)/Makefile.gbuild
 
commit bee8c7fdd3f4524f39176e71755d28b8ec0bac2a
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 02:43:02 2017 +0200

    extract the mar signing code
    
    Change-Id: I007b0b68a61242b7255a1a58a3637e3307d675aa

diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index f4990304857e..649eafe2bfa6 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -7,6 +7,7 @@ import json
 
 from tools import uncompress_file_to_dir, get_file_info, make_complete_mar_name
 from config import parse_config
+from signing import sign_mar_file
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
@@ -37,10 +38,8 @@ def main():
     mar_file = make_complete_mar_name(target_dir, filename_prefix)
     subprocess.call([os.path.join(current_dir_path, 'make_full_update.sh'), mar_file, uncompress_dir])
 
-    signed_mar_file = make_mar_name(target_dir, filename_prefix + '_signed')
-    subprocess.check_call([mar_executable, '-C', target_dir, '-d', config.certificate_path, '-n', config.certificate_name, '-s', mar_file, signed_mar_file])
 
-    os.rename(signed_mar_file, mar_file)
+    sign_mar_file(target_dir, config, mar_file, filename_prefix)
 
     file_info = { 'complete' : get_file_info(mar_file, config.base_url) }
 
diff --git a/bin/update/signing.py b/bin/update/signing.py
new file mode 100644
index 000000000000..e6ac2832d844
--- /dev/null
+++ b/bin/update/signing.py
@@ -0,0 +1,11 @@
+from tools import make_complete_mar_name
+
+import os
+import subprocess
+
+def sign_mar_file(target_dir, config, mar_file, filename_prefix):
+    signed_mar_file = make_complete_mar_name(target_dir, filename_prefix + '_signed')
+    mar_executable = os.environ.get('MAR', 'mar')
+    subprocess.check_call([mar_executable, '-C', target_dir, '-d', config.certificate_path, '-n', config.certificate_name, '-s', mar_file, signed_mar_file])
+
+    os.rename(signed_mar_file, mar_file)
commit 0989678801b0645dba3678250816429959abb021
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 02:42:15 2017 +0200

    extract mar file name generation
    
    Change-Id: If928cae4c722354d5c3e415e7cb8426a3a4412f7

diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index ebe2a01cd2cf..f4990304857e 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -5,15 +5,11 @@ import os
 import subprocess
 import json
 
-from tools import uncompress_file_to_dir, get_file_info
+from tools import uncompress_file_to_dir, get_file_info, make_complete_mar_name
 from config import parse_config
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
-def make_mar_name(target_dir, filename_prefix):
-    filename = filename_prefix + "_complete.mar"
-    return os.path.join(target_dir, filename)
-
 def main():
     print(sys.argv)
     if len(sys.argv) < 7:
@@ -38,8 +34,7 @@ def main():
 
     uncompress_dir = uncompress_file_to_dir(tar_file, temp_dir)
 
-    mar_executable = os.environ.get('MAR', 'mar')
-    mar_file = make_mar_name(target_dir, filename_prefix)
+    mar_file = make_complete_mar_name(target_dir, filename_prefix)
     subprocess.call([os.path.join(current_dir_path, 'make_full_update.sh'), mar_file, uncompress_dir])
 
     signed_mar_file = make_mar_name(target_dir, filename_prefix + '_signed')
diff --git a/bin/update/tools.py b/bin/update/tools.py
index 84c7ae6fb0ab..5a3e34521b40 100644
--- a/bin/update/tools.py
+++ b/bin/update/tools.py
@@ -49,3 +49,7 @@ def replace_variables_in_string(string, **kwargs):
         new_string = new_string.replace('$(%s)'%key, val)
 
     return new_string
+
+def make_complete_mar_name(target_dir, filename_prefix):
+    filename = filename_prefix + "_complete.mar"
+    return os.path.join(target_dir, filename)
commit e652b41225a9b8861d28e5fc4033dec433513996
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 02:13:45 2017 +0200

    reuse the new extract mar code for the partial update generation
    
    Change-Id: Ie8c92472631034935e73e55c934ce128c7b6ecd2

diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
index 90c2abd697e3..0382f82e79d3 100755
--- a/bin/update/create_partial_update.py
+++ b/bin/update/create_partial_update.py
@@ -8,6 +8,7 @@ import subprocess
 import errno
 
 from config import parse_config
+from uncompress_mar import extract_mar
 
 BUF_SIZE = 1024
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
@@ -53,7 +54,7 @@ def handle_language(lang_entries, filedir):
         download_file(lang_file , data["url"], data["hash"])
         dir_path = os.path.join(lang_dir, "lang")
         mkdir_p(dir_path)
-        subprocess.call([mar, "-C", dir_path, "-x", lang_file])
+        extract_mar(lang_file, dir_path)
         langs[lang] = dir_path
 
     return langs
@@ -83,7 +84,7 @@ def download_mar_for_update_channel_and_platform(config, platform, temp_dir):
 
         dir_path = os.path.join(filedir, "complete")
         mkdir_p(dir_path)
-        subprocess.call([mar, "-C", dir_path, "-x", filepath])
+        extract_mar(filepath, dir_path)
 
         downloaded_updates[build] = {"complete": dir_path}
 
commit c4e32aa034070f9197ff2a732842baf35d1571d4
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 01:55:01 2017 +0200

    ignore the precomplete file at least for now
    
    Change-Id: I997bdc38f705d7536a99a168815ece93dcf0c0de

diff --git a/bin/update/make_incremental_update.sh b/bin/update/make_incremental_update.sh
index 7c5e10826ba8..72286f06ce8a 100755
--- a/bin/update/make_incremental_update.sh
+++ b/bin/update/make_incremental_update.sh
@@ -122,12 +122,12 @@ if test $? -ne 0 ; then
   exit 1
 fi
 
-if [ ! -f "precomplete" ]; then
-  if [ ! -f "Contents/Resources/precomplete" ]; then
-    notice "precomplete file is missing!"
-    exit 1
-  fi
-fi
+# if [ ! -f "precomplete" ]; then
+#   if [ ! -f "Contents/Resources/precomplete" ]; then
+#     notice "precomplete file is missing!"
+#     exit 1
+#   fi
+# fi
 
 list_dirs newdirs
 list_files newfiles
commit f5a9ce1b106961fafd8e9bb1283d5b7d09b077cb
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 26 01:17:50 2017 +0200

    add a script to extract and uncompress from a mar file
    
    Change-Id: I87c11b8f7d42bc438b88482a8dd3fd1512a06df8

diff --git a/bin/update/uncompress_mar.py b/bin/update/uncompress_mar.py
new file mode 100755
index 000000000000..4c5f40733d41
--- /dev/null
+++ b/bin/update/uncompress_mar.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/.
+#
+
+# Extract a mar file and uncompress the content
+
+import os
+import sys
+import subprocess
+
+def uncompress_content(file_path):
+    bzip2 = os.environ.get('BZIP2', 'bzip2')
+    file_path_compressed = file_path + ".bz2"
+    os.rename(file_path, file_path_compressed)
+    subprocess.check_call(["bzip2", "-d", file_path_compressed])
+
+def extract_mar(mar_file, target_dir):
+    mar = os.environ.get('MAR', 'mar')
+    subprocess.check_call([mar, "-C", target_dir, "-x", mar_file])
+    file_info = subprocess.check_output([mar, "-t", mar_file])
+    lines = file_info.splitlines()
+    for line in lines:
+        info = line.split()
+        # ignore header line
+        if info[2] == b'NAME':
+            continue
+
+        uncompress_content(os.path.join(target_dir, info[2].decode("utf-8")))
+
+def main():
+    if len(sys.argv) != 3:
+        print("Help: This program takes exactly two arguments pointing to a mar file and a target location")
+        sys.exit(1)
+
+    mar_file = sys.argv[1]
+    target_dir = sys.argv[2]
+    extract_mar(mar_file, target_dir)
+
+if __name__ == "__main__":
+    main()
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
commit 795f4031d3b8c81da8013709347e5be4bf5ca935
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 21:39:11 2017 +0200

    remove the split functionality from the update creation
    
    Change-Id: I036cabff089a2cf464c887ee78b702637cce08b0

diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index 25e654c9cd8b..ebe2a01cd2cf 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -38,10 +38,6 @@ def main():
 
     uncompress_dir = uncompress_file_to_dir(tar_file, temp_dir)
 
-    # on linux we should stip the symbols from the libraries
-    if sys.platform.startswith('linux'):
-        subprocess.call('strip -g ' + os.path.join(uncompress_dir, 'program/') + '*', shell=True)
-
     mar_executable = os.environ.get('MAR', 'mar')
     mar_file = make_mar_name(target_dir, filename_prefix)
     subprocess.call([os.path.join(current_dir_path, 'make_full_update.sh'), mar_file, uncompress_dir])
commit 1429a73cc782f5bb91bc2d27207a661af6dc7ab1
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 21:29:09 2017 +0200

    add a way to strip symbols from the tarballs
    
    Change-Id: I682dcc9c366efea2be00b738f630a82b4cf9d636

diff --git a/solenv/bin/modules/installer/environment.pm b/solenv/bin/modules/installer/environment.pm
index 8e5f61e1d052..8afe3c12c782 100644
--- a/solenv/bin/modules/installer/environment.pm
+++ b/solenv/bin/modules/installer/environment.pm
@@ -123,6 +123,7 @@ sub set_global_environment_variables
     if ( $ENV{'DONTCOMPRESS'} ) { $installer::globals::solarisdontcompress = 1; }
     if ( $ENV{'IGNORE_ERROR_IN_LOGFILE'} ) { $installer::globals::ignore_error_in_logfile = 1; }
     if (( $ENV{'DISABLE_STRIP'} ) && ( $ENV{'DISABLE_STRIP'} ne '' )) { $installer::globals::strip = 0; }
+    if (( $ENV{'ENABLE_STRIP'} ) && ( $ENV{'ENABLE_STRIP'} ne '' )) { $installer::globals::strip = 1; }
 
     if ( $installer::globals::localinstalldir ) { $installer::globals::localinstalldirset = 1; }
     # Special handling, if LOCALINSTALLDIR contains "~" in the path
commit 978267504e65034316c93c4e6ffbb8def7191d3b
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 20:41:15 2017 +0200

    start working on the creation of partial update files
    
    Change-Id: I13a70e0b12090a7e23529bc35240cefc13d17779

diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
new file mode 100755
index 000000000000..90c2abd697e3
--- /dev/null
+++ b/bin/update/create_partial_update.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+import requests
+import json
+import sys
+import hashlib
+import os
+import subprocess
+import errno
+
+from config import parse_config
+
+BUF_SIZE = 1024
+current_dir_path = os.path.dirname(os.path.realpath(__file__))
+
+def download_file(filepath, url, hash_string):
+    with open(filepath, "wb") as f:
+        response = requests.get(url, stream=True)
+
+        if not response.ok:
+            return
+
+        for block in response.iter_content(1024):
+            f.write(block)
+
+    with open(filepath, "rb") as f:
+        sha512 = hashlib.sha512()
+        while True:
+            data = f.read(BUF_SIZE)
+            if not data:
+                break
+            sha512.update(data)
+        file_hash = sha512.hexdigest()
+
+    if file_hash != hash_string:
+        pass
+
+def mkdir_p(path):
+    try:
+        os.makedirs(path)
+    except OSError as exc:  # Python >2.5
+        if exc.errno == errno.EEXIST and os.path.isdir(path):
+            pass
+        else:
+            raise
+
+def handle_language(lang_entries, filedir):
+    mar = os.environ.get('MAR', 'mar')
+    langs = {}
+    for lang, data in lang_entries.items():
+        lang_dir = os.path.join(filedir, lang)
+        lang_file = os.path.join(lang_dir, "lang.mar")
+        mkdir_p(lang_dir)
+        download_file(lang_file , data["url"], data["hash"])
+        dir_path = os.path.join(lang_dir, "lang")
+        mkdir_p(dir_path)
+        subprocess.call([mar, "-C", dir_path, "-x", lang_file])
+        langs[lang] = dir_path
+
+    return langs
+
+def download_mar_for_update_channel_and_platform(config, platform, temp_dir):
+    mar = os.environ.get('MAR', 'mar')
+    base_url = "http://updater.libreofficecrash.org/update/partial-targets/1/"
+    url = base_url + platform + "/" + config.channel
+    r = requests.get(url)
+    if r.status_code is not 200:
+        print(r.content)
+        raise Exception("download failed")
+
+    update_info = json.loads(r.content.decode("utf-8"))
+    update_files = update_info['updates']
+    downloaded_updates = {}
+    for update_file in update_files:
+        build = update_file["build"]
+        filedir = temp_dir + build
+
+        mkdir_p(filedir)
+
+        filepath = filedir + "/complete.mar"
+        url = update_file["update"]["url"]
+        expected_hash = update_file["update"]["hash"]
+        download_file(filepath, url, expected_hash)
+
+        dir_path = os.path.join(filedir, "complete")
+        mkdir_p(dir_path)
+        subprocess.call([mar, "-C", dir_path, "-x", filepath])
+
+        downloaded_updates[build] = {"complete": dir_path}
+
+        langs = handle_language(update_file["languages"], filedir)
+        downloaded_updates[build]["languages"] = langs
+
+    return downloaded_updates
+
+def generate_file_name(current_build_id, old_build_id, mar_name_prefix):
+    name = "%s_from_%s_to_%s_partial.mar" %(mar_name_prefix, current_build_id, old_build_id)
+    return name
+
+def generate_lang_file_name(current_build_id, old_build_id, mar_name_prefix, lang):
+    name = "%s_%s_from_%s_to_%s_partial.mar" %(mar_name_prefix, lang, current_build_id, old_build_id)
+    return name
+
+def main():
+    product_name = sys.argv[1]
+    workdir = sys.argv[2]
+    update_dir = sys.argv[3]
+    temp_dir = sys.argv[4]
+    mar_name_prefix = sys.argv[5]
+    update_config = sys.argv[6]
+    platform = sys.argv[7]
+    current_build_path = sys.argv[8]
+    build_id = sys.argv[9]
+    dir_name =  [os.path.join(current_build_path, name) for name in os.listdir(current_build_path) if os.path.isdir(os.path.join(current_build_path, name))]
+    current_build_path = dir_name[0]
+
+    config = parse_config(update_config)
+
+    updates = download_mar_for_update_channel_and_platform(config, platform, temp_dir)
+
+    print(updates)
+    for build, update in updates.items():
+        file_name = generate_file_name(build_id, build, mar_name_prefix)
+        mar_file = os.path.join(temp_dir, build, file_name)
+        print(mar_file)
+        print(current_build_path)
+        print(update["complete"])
+        subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, current_build_path, update["complete"]])
+        for lang in update["languages"].items():
+            lang_name = generate_lang_file_name(build_id, build, mar_name_prefix, lang)
+            lang_mar_file = os.path.join(temp_dir, build, lang_name)
+            #subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), mar_file, current_build_path, update["complete"]])
+
+
+if __name__ == '__main__':
+    main()
commit 3b1c45d21287f02d05945349e724899fc8d2761a
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 20:40:05 2017 +0200

    add mbsdiff as build executable
    
    Change-Id: I68c9b14937c219ee142386b72047a6995d004f47

diff --git a/Repository.mk b/Repository.mk
index 5e8d79ca6435..ce2478a456aa 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Helper_register_executables,NONE, \
 	lngconvex \
 	localize \
 	makedepend \
+	mbsdiff \
 	mork_helper \
 	osl_process_child \
 	pdf2xml \
diff --git a/onlineupdate/Executable_mbsdiff.mk b/onlineupdate/Executable_mbsdiff.mk
new file mode 100644
index 000000000000..e5a49b5ac747
--- /dev/null
+++ b/onlineupdate/Executable_mbsdiff.mk
@@ -0,0 +1,36 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Executable_Executable,mbsdiff))
+
+$(eval $(call gb_Executable_set_include,mbsdiff,\
+	-I$(SRCDIR)/onlineupdate/inc \
+	$$(INCLUDE) \
+))
+
+$(eval $(call gb_Executable_use_externals,mbsdiff,\
+	bzip2 \
+))
+
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Executable_add_libs,mbsdiff,\
+    ws2_32.lib \
+))
+endif
+
+$(eval $(call gb_Executable_add_defs,mbsdiff,\
+	-DUNICODE \
+))
+
+$(eval $(call gb_Executable_add_cxxobjects,mbsdiff,\
+	onlineupdate/source/mbsdiff/bsdiff \
+))
+
+# vim:set shiftwidth=4 tabstop=4 noexpandtab: */
diff --git a/onlineupdate/Module_onlineupdate.mk b/onlineupdate/Module_onlineupdate.mk
index e84a208e79b3..dfb8d54ef70c 100644
--- a/onlineupdate/Module_onlineupdate.mk
+++ b/onlineupdate/Module_onlineupdate.mk
@@ -20,6 +20,7 @@ $(eval $(call gb_Module_add_targets,onlineupdate,\
 		StaticLibrary_winhelper )\
 	Executable_mar \
 	Executable_updater \
+	Executable_mbsdiff \
 ))
 endif
 
diff --git a/onlineupdate/source/update/updater/bspatch.h b/onlineupdate/inc/bspatch.h
similarity index 100%
rename from onlineupdate/source/update/updater/bspatch.h
rename to onlineupdate/inc/bspatch.h
diff --git a/onlineupdate/source/mbsdiff/bsdiff.cxx b/onlineupdate/source/mbsdiff/bsdiff.cxx
new file mode 100644
index 000000000000..ef80bd99770f
--- /dev/null
+++ b/onlineupdate/source/mbsdiff/bsdiff.cxx
@@ -0,0 +1,405 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+  bsdiff.c -- Binary patch generator.
+
+  Copyright 2003 Colin Percival
+
+  For the terms under which this work may be distributed, please see
+  the adjoining file "LICENSE".
+
+  ChangeLog:
+  2005-05-05 - Use the modified header struct from bspatch.h; use 32-bit
+               values throughout.
+                 --Benjamin Smedberg <benjamin at smedbergs.us>
+  2005-05-18 - Use the same CRC algorithm as bzip2, and leverage the CRC table
+               provided by libbz2.
+                 --Darin Fisher <darin at meer.net>
+*/
+
+#include "bspatch.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#ifdef XP_WIN
+#include <io.h>
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#include <arpa/inet.h>
+#define _O_BINARY 0
+#endif
+
+#undef MIN
+#define MIN(x,y) (((x)<(y)) ? (x) : (y))
+
+/*---------------------------------------------------------------------------*/
+
+/* This variable lives in libbz2.  It's declared in bzlib_private.h, so we just
+ * declare it here to avoid including that entire header file.
+ */
+extern "C"  unsigned int BZ2_crc32Table[256];
+
+static unsigned int
+crc32(const unsigned char *buf, unsigned int len)
+{
+    unsigned int crc = 0xffffffffL;
+
+    const unsigned char *end = buf + len;
+    for (; buf != end; ++buf)
+        crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf];
+
+    crc = ~crc;
+    return crc;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+reporterr(int e, const char *fmt, ...)
+{
+    if (fmt) {
+        va_list args;
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+
+    exit(e);
+}
+
+static void
+split(int32_t *I,int32_t *V,int32_t start,int32_t len,int32_t h)
+{
+    int32_t i,j,k,x,tmp,jj,kk;
+
+    if(len<16) {
+        for(k=start;k<start+len;k+=j) {
+            j=1;x=V[I[k]+h];
+            for(i=1;k+i<start+len;i++) {
+                if(V[I[k+i]+h]<x) {
+                    x=V[I[k+i]+h];
+                    j=0;
+                };
+                if(V[I[k+i]+h]==x) {
+                    tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
+                    j++;
+                };
+            };
+            for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
+            if(j==1) I[k]=-1;
+        };
+        return;
+    };
+
+    x=V[I[start+len/2]+h];
+    jj=0;kk=0;
+    for(i=start;i<start+len;i++) {
+        if(V[I[i]+h]<x) jj++;
+        if(V[I[i]+h]==x) kk++;
+    };
+    jj+=start;kk+=jj;
+
+    i=start;j=0;k=0;
+    while(i<jj) {
+        if(V[I[i]+h]<x) {
+            i++;
+        } else if(V[I[i]+h]==x) {
+            tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
+            j++;
+        } else {
+            tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
+            k++;
+        };
+    };
+
+    while(jj+j<kk) {
+        if(V[I[jj+j]+h]==x) {
+            j++;
+        } else {
+            tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
+            k++;
+        };
+    };
+
+    if(jj>start) split(I,V,start,jj-start,h);
+
+    for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
+    if(jj==kk-1) I[jj]=-1;
+
+    if(start+len>kk) split(I,V,kk,start+len-kk,h);
+}
+
+static void
+qsufsort(int32_t *I,int32_t *V,unsigned char *old,int32_t oldsize)
+{
+    int32_t buckets[256];
+    int32_t i,h,len;
+
+    for(i=0;i<256;i++) buckets[i]=0;
+    for(i=0;i<oldsize;i++) buckets[old[i]]++;
+    for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
+    for(i=255;i>0;i--) buckets[i]=buckets[i-1];
+    buckets[0]=0;
+
+    for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
+    I[0]=oldsize;
+    for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
+    V[oldsize]=0;
+    for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
+    I[0]=-1;
+
+    for(h=1;I[0]!=-(oldsize+1);h+=h) {
+        len=0;
+        for(i=0;i<oldsize+1;) {
+            if(I[i]<0) {
+                len-=I[i];
+                i-=I[i];
+            } else {
+                if(len) I[i-len]=-len;
+                len=V[I[i]]+1-i;
+                split(I,V,i,len,h);
+                i+=len;
+                len=0;
+            };
+        };
+        if(len) I[i-len]=-len;
+    };
+
+    for(i=0;i<oldsize+1;i++) I[V[i]]=i;
+}
+
+static int32_t
+matchlen(unsigned char *old,int32_t oldsize,unsigned char *newbuf,int32_t newsize)
+{
+    int32_t i;
+
+    for(i=0;(i<oldsize)&&(i<newsize);i++)
+        if(old[i]!=newbuf[i]) break;
+
+    return i;
+}
+
+static int32_t
+search(int32_t *I,unsigned char *old,int32_t oldsize,
+       unsigned char *newbuf,int32_t newsize,int32_t st,int32_t en,int32_t *pos)
+{
+    int32_t x,y;
+
+    if(en-st<2) {
+        x=matchlen(old+I[st],oldsize-I[st],newbuf,newsize);
+        y=matchlen(old+I[en],oldsize-I[en],newbuf,newsize);
+
+        if(x>y) {
+            *pos=I[st];
+            return x;
+        } else {
+            *pos=I[en];
+            return y;
+        }
+    };
+
+    x=st+(en-st)/2;
+    if(memcmp(old+I[x],newbuf,MIN(oldsize-I[x],newsize))<0) {
+        return search(I,old,oldsize,newbuf,newsize,x,en,pos);
+    } else {
+        return search(I,old,oldsize,newbuf,newsize,st,x,pos);
+    };
+}
+
+int main(int argc,char *argv[])
+{
+    int fd;
+    unsigned char *old,*newbuf;
+    int32_t oldsize,newsize;
+    int32_t *I,*V;
+
+    int32_t scan,pos,len;
+    int32_t lastscan,lastpos,lastoffset;
+    int32_t oldscore,scsc;
+
+    int32_t s,Sf,lenf,Sb,lenb;
+    int32_t overlap,Ss,lens;
+    int32_t i;
+
+    int32_t dblen,eblen;
+    unsigned char *db,*eb;
+
+    unsigned int scrc;
+
+    MBSPatchHeader header = {
+        {'M','B','D','I','F','F','1','0'},
+        0, 0, 0, 0, 0, 0
+    };
+
+    uint32_t numtriples;
+
+    if(argc!=4)
+        reporterr(1,"usage: %s <oldfile> <newfile> <patchfile>\n",argv[0]);
+
+    /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
+        that we never try to malloc(0) and get a NULL pointer */
+    if(((fd=open(argv[1],O_RDONLY|_O_BINARY,0))<0) ||
+        ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
+        ((old=(unsigned char*) malloc(oldsize+1))==NULL) ||
+        (lseek(fd,0,SEEK_SET)!=0) ||
+        (read(fd,old,oldsize)!=oldsize) ||
+        (close(fd)==-1))
+        reporterr(1,"%s\n",argv[1]);
+
+    scrc = crc32(old, oldsize);
+
+    if(((I=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL) ||
+        ((V=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL))
+        reporterr(1,NULL);
+
+    qsufsort(I,V,old,oldsize);
+
+    free(V);
+
+    /* Allocate newsize+1 bytes instead of newsize bytes to ensure
+        that we never try to malloc(0) and get a NULL pointer */
+    if(((fd=open(argv[2],O_RDONLY|_O_BINARY,0))<0) ||
+        ((newsize=lseek(fd,0,SEEK_END))==-1) ||
+        ((newbuf=(unsigned char*) malloc(newsize+1))==NULL) ||
+        (lseek(fd,0,SEEK_SET)!=0) ||
+        (read(fd,newbuf,newsize)!=newsize) ||
+        (close(fd)==-1)) reporterr(1,"%s\n",argv[2]);
+
+    if(((db=(unsigned char*) malloc(newsize+1))==NULL) ||
+        ((eb=(unsigned char*) malloc(newsize+1))==NULL))
+        reporterr(1,NULL);
+
+    dblen=0;
+    eblen=0;
+
+    if((fd=open(argv[3],O_CREAT|O_TRUNC|O_WRONLY|_O_BINARY,0666))<0)
+        reporterr(1,"%s\n",argv[3]);
+
+    /* start writing here */
+
+    /* We don't know the lengths yet, so we will write the header again
+         at the end */
+
+    if(write(fd,&header,sizeof(MBSPatchHeader))!=sizeof(MBSPatchHeader))
+        reporterr(1,"%s\n",argv[3]);
+
+    scan=0;len=0;
+    lastscan=0;lastpos=0;lastoffset=0;
+    numtriples = 0;
+    while(scan<newsize) {
+        oldscore=0;
+
+        for(scsc=scan+=len;scan<newsize;scan++) {
+            len=search(I,old,oldsize,newbuf+scan,newsize-scan,
+                    0,oldsize,&pos);
+
+            for(;scsc<scan+len;scsc++)
+            if((scsc+lastoffset<oldsize) &&
+                (old[scsc+lastoffset] == newbuf[scsc]))
+                oldscore++;
+
+            if(((len==oldscore) && (len!=0)) ||
+                (len>oldscore+8)) break;
+
+            if((scan+lastoffset<oldsize) &&
+                (old[scan+lastoffset] == newbuf[scan]))
+                oldscore--;
+        };
+
+        if((len!=oldscore) || (scan==newsize)) {
+            MBSPatchTriple triple;
+
+            s=0;Sf=0;lenf=0;
+            for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
+                if(old[lastpos+i]==newbuf[lastscan+i]) s++;
+                i++;
+                if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
+            };
+
+            lenb=0;
+            if(scan<newsize) {
+                s=0;Sb=0;
+                for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
+                    if(old[pos-i]==newbuf[scan-i]) s++;
+                    if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
+                };
+            };
+
+            if(lastscan+lenf>scan-lenb) {
+                overlap=(lastscan+lenf)-(scan-lenb);
+                s=0;Ss=0;lens=0;
+                for(i=0;i<overlap;i++) {
+                    if(newbuf[lastscan+lenf-overlap+i]==
+                       old[lastpos+lenf-overlap+i]) s++;
+                    if(newbuf[scan-lenb+i]==
+                       old[pos-lenb+i]) s--;
+                    if(s>Ss) { Ss=s; lens=i+1; };
+                };
+
+                lenf+=lens-overlap;
+                lenb-=lens;
+            };
+
+            for(i=0;i<lenf;i++)
+                db[dblen+i]=newbuf[lastscan+i]-old[lastpos+i];
+            for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
+                eb[eblen+i]=newbuf[lastscan+lenf+i];
+
+            dblen+=lenf;
+            eblen+=(scan-lenb)-(lastscan+lenf);
+
+            triple.x = htonl(lenf);
+            triple.y = htonl((scan-lenb)-(lastscan+lenf));
+            triple.z = htonl((pos-lenb)-(lastpos+lenf));
+            if (write(fd,&triple,sizeof(triple)) != sizeof(triple))
+                reporterr(1,NULL);
+
+#ifdef DEBUG_bsmedberg
+            printf("Writing a block:\n"
+                   "    X: %u\n"
+                   "    Y: %u\n"
+                   "    Z: %i\n",
+                   (uint32_t) lenf,
+                   (uint32_t) ((scan-lenb)-(lastscan+lenf)),
+                   (uint32_t) ((pos-lenb)-(lastpos+lenf)));
+#endif
+
+            ++numtriples;
+
+            lastscan=scan-lenb;
+            lastpos=pos-lenb;
+            lastoffset=pos-scan;
+        };
+    };
+
+    if(write(fd,db,dblen)!=dblen)
+        reporterr(1,NULL);
+
+    if(write(fd,eb,eblen)!=eblen)
+        reporterr(1,NULL);
+
+    header.slen    = htonl(oldsize);
+    header.scrc32    = htonl(scrc);
+    header.dlen    = htonl(newsize);
+    header.cblen    = htonl(numtriples * sizeof(MBSPatchTriple));
+    header.difflen    = htonl(dblen);
+    header.extralen = htonl(eblen);
+
+    if (lseek(fd,0,SEEK_SET) == -1 ||
+        write(fd,&header,sizeof(header)) != sizeof(header) ||
+        close(fd) == -1)
+        reporterr(1,NULL);
+
+    free(db);
+    free(eb);
+    free(I);
+    free(old);
+    free(newbuf);
+
+    return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit e1e9d1ed95870fd8a9d95296e90431d3c8ad4ce0
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Apr 24 23:57:22 2017 +0200

    actually abort the update process if the update file is invalid
    
    Change-Id: I724e50d1e74228f0be00b9b6376c3d074db5c9ed

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 1d3b0acc9158..cad36200daaa 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -287,6 +287,40 @@ class invalid_update_info : public std::exception
 {
 };
 
+class invalid_hash : public std::exception
+{
+    OString maMessage;
+public:
+
+    invalid_hash(const OUString& rExpectedHash, const OUString& rReceivedHash)
+    {
+        OUString aMsg = "Invalid hash found.\nExpected: " + rExpectedHash + ";\nReceived: " + rReceivedHash;
+        maMessage = OUStringToOString(aMsg, RTL_TEXTENCODING_UTF8);
+    }
+
+    const char* what() const noexcept override
+    {
+        return maMessage.getStr();
+    }
+};
+
+class invalid_size : public std::exception
+{
+    OString maMessage;
+public:
+
+    invalid_size(const size_t nExpectedSize, const size_t nReceivedSize)
+    {
+        OUString aMsg = "Invalid file size found.\nExpected: " + OUString::number(nExpectedSize) + ";\nReceived: " + OUString::number(nReceivedSize);
+        maMessage = OUStringToOString(aMsg, RTL_TEXTENCODING_UTF8);
+    }
+
+    const char* what() const noexcept override
+    {
+        return maMessage.getStr();
+    }
+};
+
 OUString toOUString(const std::string& rStr)
 {
     return OUString::fromUtf8(rStr.c_str());
@@ -538,11 +572,13 @@ void download_file(const OUString& rURL, size_t nFileSize, const OUString& rHash
     if (nSize != nFileSize)
     {
         SAL_WARN("desktop.updater", "File sizes don't match. File might be corrupted.");
+        throw invalid_size(nFileSize, nSize);
     }
 
     if (aHash != rHash)
     {
         SAL_WARN("desktop.updater", "File hash don't match. File might be corrupted.");
+        throw invalid_hash(rHash, aHash);
     }
 
     OUString aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
@@ -600,6 +636,14 @@ void update_checker()
     {
         SAL_WARN("desktop.updater", "error during the update check");
     }
+    catch (const invalid_size& e)
+    {
+        SAL_WARN("desktop.updater", e.what());
+    }
+    catch (const invalid_hash& e)
+    {
+        SAL_WARN("desktop.updater", e.what());
+    }
     catch (...)
     {
         SAL_WARN("desktop.updater", "unknown error during the update check");
commit 27ec95dfe4eb327b75378604faeb015667aabf55
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Apr 24 23:25:44 2017 +0200

    actually check the hash of the update files
    
    Change-Id: I98a5f8904a35cb167e87d6c5c11bcf133115cbc1

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 388c45e7211e..1d3b0acc9158 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -31,6 +31,7 @@
 #include <orcus/json_document_tree.hpp>
 #include <orcus/config.hpp>
 #include <orcus/pstring.hpp>
+#include <comphelper/hash.hxx>
 
 namespace {
 
@@ -280,18 +281,6 @@ static size_t WriteCallback(void *ptr, size_t size,
   return real_size;
 }
 
-// Callback to get the response data from server to a file.
-static size_t WriteCallbackFile(void *ptr, size_t size,
-                            size_t nmemb, void *userp)
-{
-  if (!userp)
-    return 0;
-
-  SvStream* response = static_cast<SvStream *>(userp);
-  size_t real_size = size * nmemb;
-  response->WriteBytes(static_cast<char *>(ptr), real_size);
-  return real_size;
-}
 
 
 class invalid_update_info : public std::exception
@@ -408,7 +397,45 @@ update_info parse_response(const std::string& rResponse)
     return aUpdateInfo;
 }
 
-std::string download_content(const OString& rURL, bool bFile)
+struct WriteDataFile
+{
+    comphelper::Hash maHash;
+    SvStream* mpStream;
+
+    WriteDataFile(SvStream* pStream):
+        maHash(comphelper::HashType::SHA512),
+        mpStream(pStream)
+    {
+    }
+
+    OUString getHash()
+    {
+        auto final_hash = maHash.finalize();
+        std::stringstream aStrm;
+        for (auto& i: final_hash)
+        {
+            aStrm << std::setw(2) << std::setfill('0') << std::hex << (int)i;
+        }
+
+        return toOUString(aStrm.str());
+    }
+};
+
+// Callback to get the response data from server to a file.
+size_t WriteCallbackFile(void *ptr, size_t size,
+                            size_t nmemb, void *userp)
+{
+  if (!userp)
+    return 0;
+
+  WriteDataFile* response = static_cast<WriteDataFile *>(userp);
+  size_t real_size = size * nmemb;
+  response->mpStream->WriteBytes(static_cast<char *>(ptr), real_size);
+  response->maHash.update(static_cast<const unsigned char*>(ptr), real_size);
+  return real_size;
+}
+
+std::string download_content(const OString& rURL, bool bFile, OUString& rHash)
 {
     CURL* curl = curl_easy_init();
 
@@ -434,6 +461,7 @@ std::string download_content(const OString& rURL, bool bFile)
 
     std::string response_body;
     utl::TempFile aTempFile;
+    WriteDataFile aFile(aTempFile.GetStream(StreamMode::WRITE));
     if (!bFile)
     {
         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
@@ -452,7 +480,7 @@ std::string download_content(const OString& rURL, bool bFile)
 
         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallbackFile);
         curl_easy_setopt(curl, CURLOPT_WRITEDATA,
-                static_cast<void *>(aTempFile.GetStream(StreamMode::WRITE)));
+                static_cast<void *>(&aFile));
     }
 
     // Fail if 400+ is returned from the web server.
@@ -473,12 +501,10 @@ std::string download_content(const OString& rURL, bool bFile)
         throw error_updater();
     }
 
-    return response_body;
-}
+    if (bFile)
+        rHash = aFile.getHash();
 
-OUString generateHash(const OUString& /*rURL*/)
-{
-    return OUString();
+    return response_body;
 }
 
 void handle_file_error(osl::FileBase::RC eError)
@@ -496,7 +522,8 @@ void handle_file_error(osl::FileBase::RC eError)
 void download_file(const OUString& rURL, size_t nFileSize, const OUString& rHash, const OUString& aFileName)
 {
     OString aURL = OUStringToOString(rURL, RTL_TEXTENCODING_UTF8);
-    std::string temp_file = download_content(aURL, true);
+    OUString aHash;
+    std::string temp_file = download_content(aURL, true, aHash);
     if (temp_file.empty())
         throw error_updater();
 
@@ -513,7 +540,6 @@ void download_file(const OUString& rURL, size_t nFileSize, const OUString& rHash
         SAL_WARN("desktop.updater", "File sizes don't match. File might be corrupted.");
     }
 
-    OUString aHash = generateHash(aTempFile);
     if (aHash != rHash)
     {
         SAL_WARN("desktop.updater", "File hash don't match. File might be corrupted.");
@@ -548,7 +574,8 @@ void update_checker()
 
     try
     {
-        std::string response_body = download_content(aURL, false);
+        OUString aHash;
+        std::string response_body = download_content(aURL, false, aHash);
         if (!response_body.empty())
         {
             update_info aUpdateInfo = parse_response(response_body);
commit 81959f50781b773eec9eaa53c2888ce836de28de
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Apr 24 19:51:40 2017 +0200

    if the update_dir does not exist continue with the update check

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index f354570fe11a..3eb1fdf11c2e 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1487,16 +1487,12 @@ int Desktop::Main()
         {
             osl::DirectoryItem aPatchInfo;
             osl::DirectoryItem::get(Updater::getUpdateInfoURL(), aPatchInfo);
+            osl::DirectoryItem aDirectoryItem;
+            osl::DirectoryItem::get(Updater::getUpdateDirURL(), aDirectoryItem);
 
-            if (aPatchInfo.is())
+            if (aPatchInfo.is() && aDirectoryItem.is())
             {
-                osl::DirectoryItem aDirectoryItem;
-                osl::DirectoryItem::get(Updater::getUpdateDirURL(), aDirectoryItem);
-                bool bValidUpdateDirExists = aDirectoryItem.is();
-                if (bValidUpdateDirExists)
-                {
-                    update();
-                }
+                update();
             }
             else if (isTimeForUpdateCheck())
             {
commit 830f9442dc0c9db36f3ee8fd4fcb9e62b527deef
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Apr 24 18:54:59 2017 +0200

    better reporting for normal response from updater
    
    Change-Id: I26cbd69c46afadc21eeab73cbccddc6873c43655

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index a0e0e3bf4f6f..388c45e7211e 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -194,6 +194,7 @@ struct update_info
 {
     OUString aFromBuildID;
     OUString aSeeAlsoURL;
+    OUString aMessage;
 
     update_file aUpdateFile;
     std::vector<language_file> aLanguageFiles;
@@ -356,6 +357,13 @@ update_info parse_response(const std::string& rResponse)
     {
         throw invalid_update_info();
     }
+    else if (std::find(aRootKeys.begin(), aRootKeys.end(), "response") != aRootKeys.end())
+    {
+        update_info aUpdateInfo;
+        auto aMsgNode = aDocumentRoot.child("response");
+        aUpdateInfo.aMessage = toOUString(aMsgNode.string_value().str());
+        return aUpdateInfo;
+    }
 
     orcus::json::detail::node aFromNode = aDocumentRoot.child("from");
     if (aFromNode.type() != orcus::json_node_t::string)
@@ -544,8 +552,17 @@ void update_checker()
         if (!response_body.empty())
         {
             update_info aUpdateInfo = parse_response(response_body);
-            download_file(aUpdateInfo.aUpdateFile.aURL, aUpdateInfo.aUpdateFile.nSize, aUpdateInfo.aUpdateFile.aHash, "update.mar");
-            CreateValidUpdateDir(aUpdateInfo);
+            if (aUpdateInfo.aUpdateFile.aURL.isEmpty())
+            {
+                // No update currently available
+                // add entry to updating.log with the message
+                SAL_WARN("desktop.updater", "Message received from the updater: " << aUpdateInfo.aMessage);
+            }
+            else
+            {
+                download_file(aUpdateInfo.aUpdateFile.aURL, aUpdateInfo.aUpdateFile.nSize, aUpdateInfo.aUpdateFile.aHash, "update.mar");
+                CreateValidUpdateDir(aUpdateInfo);
+            }
         }
     }
     catch (const invalid_update_info&)
commit 8c0a29b1ef892a296702986000b13d6171d6364e
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Apr 24 01:14:53 2017 +0200

    extract the common updater path info into methods
    
    Change-Id: I8d25fc3c6a6a0a7e05bac6679f2312a904e75bbd

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 5916d56b6c2d..f354570fe11a 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1485,19 +1485,13 @@ int Desktop::Main()
 #if HAVE_FEATURE_UPDATE_MAR
         if (officecfg::Office::Update::Update::Enabled::get())
         {
-            OUString aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
-            rtl::Bootstrap::expandMacros(aPatchDirURL);
-
             osl::DirectoryItem aPatchInfo;
-            osl::DirectoryItem::get(aPatchDirURL + "/update.info", aPatchInfo);
+            osl::DirectoryItem::get(Updater::getUpdateInfoURL(), aPatchInfo);
 
             if (aPatchInfo.is())
             {
-                OUString aInstallationDir( "$BRAND_BASE_DIR/");
-                rtl::Bootstrap::expandMacros(aInstallationDir);
-
                 osl::DirectoryItem aDirectoryItem;
-                osl::DirectoryItem::get(aInstallationDir + "/updated", aDirectoryItem);
+                osl::DirectoryItem::get(Updater::getUpdateDirURL(), aDirectoryItem);
                 bool bValidUpdateDirExists = aDirectoryItem.is();
                 if (bValidUpdateDirExists)
                 {
diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index e82e84f41bc6..a0e0e3bf4f6f 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -140,7 +140,7 @@ char** createCommandLine()
     }
     {
         // directory with the patch log
-        OUString aPatchDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
+        OUString aPatchDir = Updater::getPatchDirURL();
         rtl::Bootstrap::expandMacros(aPatchDir);
         OUString aTempDirPath = getPathFromURL(aPatchDir);
         createStr(aTempDirPath, pArgs, 1);
@@ -152,9 +152,8 @@ char** createCommandLine()
     }
     {
         // the temporary updated build
-        OUString aPatchDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/update_dir/");
-        rtl::Bootstrap::expandMacros(aPatchDir);
-        OUString aWorkingDir = getPathFromURL(aPatchDir);
+        OUString aUpdateDirURL = Updater::getUpdateDirURL();
+        OUString aWorkingDir = getPathFromURL(aUpdateDirURL);
         createStr(aWorkingDir, pArgs, 3);
     }
     {
@@ -162,15 +161,14 @@ char** createCommandLine()
         createStr(pPID, pArgs, 4);
     }
     {
-        OUString aExeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
+        OUString aExeDir = Updater::getExecutableDirURL();
         OUString aSofficePath = getPathFromURL(aExeDir);
         createStr(aSofficePath, pArgs, 5);
     }
     {
         // the executable to start after the successful update
-        OUString aSofficeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
-        rtl::Bootstrap::expandMacros(aSofficeDir);
-        OUString aSofficePathURL = aSofficeDir + OUString::fromUtf8(pSofficeExeName);
+        OUString aExeDir = Updater::getExecutableDirURL();
+        OUString aSofficePathURL = aExeDir + OUString::fromUtf8(pSofficeExeName);
         OUString aSofficePath = getPathFromURL(aSofficePathURL);
         createStr(aSofficePath, pArgs, 6);
     }
@@ -564,4 +562,36 @@ void update_checker()
     }
 }
 
+OUString Updater::getUpdateInfoURL()
+{
+    OUString aUpdateInfoURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/update.info");
+    rtl::Bootstrap::expandMacros(aUpdateInfoURL);
+
+    return aUpdateInfoURL;
+}
+
+OUString Updater::getPatchDirURL()
+{
+    OUString aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
+    rtl::Bootstrap::expandMacros(aPatchDirURL);
+
+    return aPatchDirURL;
+}
+
+OUString Updater::getUpdateDirURL()
+{
+    OUString aUpdateDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/update_dir/");
+    rtl::Bootstrap::expandMacros(aUpdateDirURL);
+
+    return aUpdateDirURL;
+}
+
+OUString Updater::getExecutableDirURL()
+{
+    OUString aExeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
+    rtl::Bootstrap::expandMacros(aExeDir);
+
+    return aExeDir;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/app/updater.hxx b/desktop/source/app/updater.hxx
index fa5349afbe11..b36c1f91b306 100644
--- a/desktop/source/app/updater.hxx
+++ b/desktop/source/app/updater.hxx
@@ -16,6 +16,19 @@ void update();
 
 void update_checker();
 
+class Updater
+{
+private:
+
+public:
+
+    static OUString getUpdateInfoURL();
+    static OUString getPatchDirURL();
+    static OUString getUpdateDirURL();
+    static OUString getExecutableDirURL();
+
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6abf277036363154293111d6f1259ddd6c963325
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 21 22:57:59 2017 +0200

    either try to install an update or check for update
    
    Change-Id: Id1e879598ef34715786e10e163ed1e4689f3137a

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 11b872772087..5916d56b6c2d 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1504,8 +1504,7 @@ int Desktop::Main()
                     update();
                 }
             }
-
-            if (isTimeForUpdateCheck())
+            else if (isTimeForUpdateCheck())
             {
                 sal_uInt64 nNow = tools::Time::GetSystemTicks();
                 std::shared_ptr< comphelper::ConfigurationChanges > batch(
commit 4631f1d861a31f0e454147196db5f196065d2714
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 21 22:16:39 2017 +0200

    normalize path for updater

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 07f24b48378f..e82e84f41bc6 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -56,7 +56,31 @@ const char* pSofficeExeName = "soffice.exe";
 
 OUString normalizePath(const OUString& rPath)
 {
-    return rPath.replaceAll("//", "/");
+    OUString aPath =  rPath.replaceAll("//", "/");
+
+    // remove final /
+    if (aPath.endsWith("/"))
+    {
+        aPath = aPath.copy(0, aPath.getLength() - 1);
+    }
+
+    while (aPath.indexOf("/..") != -1)
+    {
+        sal_Int32 nIndex = aPath.indexOf("/..");
+        sal_Int32 i = nIndex - 1;
+        for (; i > 0; --i)
+        {
+            if (aPath[i] == '/')
+                break;
+        }
+
+        OUString aTempPath = aPath;
+        aPath = aTempPath.copy(0, i) + aPath.copy(nIndex + 3);
+    }
+
+    SAL_DEBUG(aPath);
+
+    return aPath;
 }
 
 void CopyFileToDir(const OUString& rTempDirURL, const OUString rFileName, const OUString& rOldDir)
commit 29f2809da5db26e5622dccedfe3839aa10dcdb7c
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 21 22:04:09 2017 +0200

    better flexibility through configurable updated build directory
    
    Change-Id: Icaa814cdcd27171fbafc2407d55161cdc13e750e

diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx
index 18cf8b2cc966..57ac77507a8b 100644
--- a/onlineupdate/source/update/updater/updater.cxx
+++ b/onlineupdate/source/update/updater/updater.cxx
@@ -2357,8 +2357,8 @@ ProcessReplaceRequest()
                  NS_T("%s/Contents"),
                  gWorkingDirPath);
 #else
-                 NS_T("%s.bak/updated"),
-                 gInstallDirPath);
+                 NS_T("%s"),
+                 gWorkingDirPath);
 #endif
 
     // First try to remove the possibly existing temp directory, because if this
commit 4da600b793b6a4cfd775031af322f3679542db67
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 21 21:14:50 2017 +0200

    first stab at normalizing updater path
    
    Change-Id: I5ef2253068595c41577330395810b0797eff8cbb

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index f31f2800dc4b..07f24b48378f 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -54,6 +54,10 @@ const char* pSofficeExeName = "soffice.exe";
 #error "Need implementation"
 #endif
 
+OUString normalizePath(const OUString& rPath)
+{
+    return rPath.replaceAll("//", "/");
+}
 
 void CopyFileToDir(const OUString& rTempDirURL, const OUString rFileName, const OUString& rOldDir)
 {
@@ -73,7 +77,7 @@ OUString getPathFromURL(const OUString& rURL)
     OUString aPath;
     osl::FileBase::getSystemPathFromFileURL(rURL, aPath);
 
-    return aPath;
+    return normalizePath(aPath);
 }
 
 void CopyUpdaterToTempDir(const OUString& rInstallDirURL, const OUString& rTempDirURL)
commit 1f326352aa937dba628506b0e489ab276026aceb
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Apr 21 20:50:21 2017 +0200

    use an update dir that is in the user profile
    
    The user profile should always be writable
    
    Change-Id: I45f7e05e128d62a5930e6db9793b8cf4e7751046

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index a700527a43b9..f31f2800dc4b 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -111,17 +111,22 @@ char** createCommandLine()
         createStr(pUpdaterName, pArgs, 0);
     }
     {
+        // directory with the patch log
         OUString aPatchDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
         rtl::Bootstrap::expandMacros(aPatchDir);
         OUString aTempDirPath = getPathFromURL(aPatchDir);
         createStr(aTempDirPath, pArgs, 1);
     }
     {
+        // the actual update directory
         OUString aInstallPath = getPathFromURL(aLibExecDirURL);
         createStr(aInstallPath, pArgs, 2);
     }
     {
-        OUString aWorkingDir = getPathFromURL(aLibExecDirURL + "/updated");
+        // the temporary updated build
+        OUString aPatchDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/update_dir/");
+        rtl::Bootstrap::expandMacros(aPatchDir);
+        OUString aWorkingDir = getPathFromURL(aPatchDir);
         createStr(aWorkingDir, pArgs, 3);
     }
     {
@@ -134,6 +139,7 @@ char** createCommandLine()
         createStr(aSofficePath, pArgs, 5);
     }
     {
+        // the executable to start after the successful update
         OUString aSofficeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
         rtl::Bootstrap::expandMacros(aSofficeDir);
         OUString aSofficePathURL = aSofficeDir + OUString::fromUtf8(pSofficeExeName);
@@ -202,7 +208,9 @@ void CreateValidUpdateDir(const update_info& update_info)
     OUString aInstallDir("$BRAND_BASE_DIR");
     rtl::Bootstrap::expandMacros(aInstallDir);
     OUString aInstallPath = getPathFromURL(aInstallDir);
-    OUString aWorkdirPath = getPathFromURL(aInstallDir + "/updated");
+    OUString aUpdatedBuildDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/update_dir/");
+    rtl::Bootstrap::expandMacros(aUpdatedBuildDir);
+    OUString aWorkdirPath = getPathFromURL(aUpdatedBuildDir);
 
     OUString aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
     rtl::Bootstrap::expandMacros(aPatchDirURL);
commit d5b7b08c55933231e96d12130e122caf589211e3
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 19 13:28:02 2017 +0200

    don't crash when we get bad response
    
    Change-Id: I4bc68e9f9604a8a39f36f10434571cd9fbb48ae1

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index b6abf4c01b74..a700527a43b9 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -522,6 +522,10 @@ void update_checker()
     {
         SAL_WARN("desktop.updater", "error during the update check");
     }
+    catch (...)
+    {
+        SAL_WARN("desktop.updater", "unknown error during the update check");
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6b687119ca6733eed730a90779ce8d66742b2325
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Apr 19 13:20:47 2017 +0200

    ignore SIGPIPE in glx test process
    
    Change-Id: I31977f86290b4fd7e0869af85f5132ae7cd9d5fd

diff --git a/vcl/unx/glxtest.cxx b/vcl/unx/glxtest.cxx
index efe55910d164..383be628dfa9 100644
--- a/vcl/unx/glxtest.cxx
+++ b/vcl/unx/glxtest.cxx
@@ -25,6 +25,7 @@
 #include <fcntl.h>
 #include "stdint.h"
 #include <string.h>
+#include <signal.h>
 
 #include "opengl/x11/glxtest.hxx"
 
@@ -98,6 +99,7 @@ x_error_handler(Display *, XErrorEvent *ev)
 
 void glxtest()
 {
+  signal(SIGPIPE, SIG_IGN);
   // we want to redirect to /dev/null stdout, stderr, and while we're at it,
   // any PR logging file descriptors. To that effect, we redirect all positive
   // file descriptors up to what open() returns here. In particular, 1 is stdout and 2 is stderr.
commit c7e534506f927558d026954935d913f56f246341
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 18 19:42:53 2017 +0200

    hard coding the number of entries just leads to problems
    
    Change-Id: I527c2c881bf46b1724b8da9223b2614ff30fbec7

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index e9d989acc26b..b6abf4c01b74 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -323,12 +323,6 @@ update_info parse_response(const std::string& rResponse)
         throw invalid_update_info();
     }
 
-    if (aRootKeys.size() != 5)
-    {
-        SAL_WARN("desktop.Update", "invalid root entries: " << rResponse);
-        throw invalid_update_info();
-    }
-
     orcus::json::detail::node aFromNode = aDocumentRoot.child("from");
     if (aFromNode.type() != orcus::json_node_t::string)
     {
commit b61d22cb934c767927513430069eb40180090587
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 18 19:16:02 2017 +0200

    version entry is no more
    
    Change-Id: I5011deec4a3b00b22d68d5dff594586d74d717ba

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index dffafcbcde53..e9d989acc26b 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -162,7 +162,6 @@ struct update_info
 {
     OUString aFromBuildID;
     OUString aSeeAlsoURL;
-    OUString aNewVersion;
 
     update_file aUpdateFile;
     std::vector<language_file> aLanguageFiles;
@@ -342,12 +341,6 @@ update_info parse_response(const std::string& rResponse)
         throw invalid_update_info();
     }
 
-    orcus::json::detail::node aVersionNode = aDocumentRoot.child("version");
-    if (aVersionNode.type() != orcus::json_node_t::string)
-    {
-        throw invalid_update_info();
-    }
-
     orcus::json::detail::node aUpdateNode = aDocumentRoot.child("update");
     if (aUpdateNode.type() != orcus::json_node_t::object)
     {
@@ -362,7 +355,6 @@ update_info parse_response(const std::string& rResponse)
 
     update_info aUpdateInfo;
     aUpdateInfo.aFromBuildID = toOUString(aFromNode.string_value().str());
-    aUpdateInfo.aNewVersion = toOUString(aVersionNode.string_value().str());
     aUpdateInfo.aSeeAlsoURL = toOUString(aSeeAlsoNode.string_value().str());
 
     aUpdateInfo.aUpdateFile = parse_update_file(aUpdateNode);
commit 0a30074149f6d53536a9c5ca08cc8a41e42d433d
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 18 13:30:46 2017 +0200

    protect the downloading of the update info also with try..catch
    
    Change-Id: Ie3f2687670b02d8af85016c25b49cb42517701b9

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index a4bf6d6e9d81..dffafcbcde53 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -517,10 +517,10 @@ void update_checker()
         "/" + aBuildID + "/" + aBuildTarget + "/" + "/" + aChannel;
     OString aURL = OUStringToOString(aDownloadCheckURL, RTL_TEXTENCODING_UTF8);
 
-    std::string response_body = download_content(aURL, false);
 
     try
     {
+        std::string response_body = download_content(aURL, false);
         if (!response_body.empty())
         {
             update_info aUpdateInfo = parse_response(response_body);
commit e04335a1bd29b445f0447ae9e663626c9188bdce
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 18 13:08:40 2017 +0200

    update the update URL and adapt to the server changes
    
    Change-Id: I6ece7924e6e0980c2bb4fffa9d733e6352382084

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 2b9c68a0d969..a4bf6d6e9d81 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -509,15 +509,12 @@ void update_checker()
     OUString aProductName = utl::ConfigManager::getProductName();
     OUString aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}");
     rtl::Bootstrap::expandMacros(aBuildID);
-    OUString aVersion = "5.3.0.0.alpha0+";
     OUString aBuildTarget = "${_OS}_${_ARCH}";
     rtl::Bootstrap::expandMacros(aBuildTarget);
-    OUString aLocale = "en-US";
     OUString aChannel = officecfg::Office::Update::Update::UpdateChannel::get();
 
-    OUString aDownloadCheckURL = aDownloadCheckBaseURL + "update/1/" + aProductName +
-        "/" + aVersion + "/" + aBuildID + "/" + aBuildTarget + "/" + aLocale +
-        "/" + aChannel;
+    OUString aDownloadCheckURL = aDownloadCheckBaseURL + "update/check/1/" + aProductName +
+        "/" + aBuildID + "/" + aBuildTarget + "/" + "/" + aChannel;
     OString aURL = OUStringToOString(aDownloadCheckURL, RTL_TEXTENCODING_UTF8);
 
     std::string response_body = download_content(aURL, false);
commit b3f6d7ef9a7862a3bc43322d176de027973d1108
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 00:50:14 2017 +0200

    send the csrf token with the updater scripts
    
    Change-Id: Iad6953b8206ba02ca09069115e168230b27f72fe

diff --git a/bin/update/upload_build_config.py b/bin/update/upload_build_config.py
index 0380cc1c323b..3267f021b8e3 100755
--- a/bin/update/upload_build_config.py
+++ b/bin/update/upload_build_config.py
@@ -29,9 +29,11 @@ def main(argv):
     r1 = session.post(login_url, data=login_data, headers={"Referer": login_url})
 
     url = base_address + "update/upload/release"
+    data = {}
+    data['csrfmiddlewaretoken'] = csrftoken
 
     build_config = os.path.join(sys.argv[1], "build_config.json")
-    r = session.post(url, files={'release_config': open(build_config, "r")})
+    r = session.post(url, files={'release_config': open(build_config, "r")}, data=data)
     print(r.content)
     if r.status_code != 200:
         sys.exit(1)
commit c0518762f520e3c3a2d544055b78ea191d1663bd
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 00:49:25 2017 +0200

    use the path and not the URL string
    
    Change-Id: I045e801a86f656a182bd1c5c42aca29cde694f71

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 8c71f3bc2c9c..2b9c68a0d969 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -114,7 +114,7 @@ char** createCommandLine()
         OUString aPatchDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
         rtl::Bootstrap::expandMacros(aPatchDir);
         OUString aTempDirPath = getPathFromURL(aPatchDir);
-        createStr(aPatchDir, pArgs, 1);
+        createStr(aTempDirPath, pArgs, 1);
     }
     {
         OUString aInstallPath = getPathFromURL(aLibExecDirURL);
commit 3ea328fa62db81565f4733f20483a0eb4390c736
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 00:48:39 2017 +0200

    use consistent method names
    
    Change-Id: I19e066b7e4c4ba1fc1b0802e80260a6d9b0d9b9a

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 7085c11073a8..11b872772087 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1501,7 +1501,7 @@ int Desktop::Main()
                 bool bValidUpdateDirExists = aDirectoryItem.is();
                 if (bValidUpdateDirExists)
                 {
-                    Update();
+                    update();
                 }
             }
 
diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 83d2a3010bf6..8c71f3bc2c9c 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -170,7 +170,7 @@ struct update_info
 
 }
 
-void Update()
+void update()
 {
     OUString aLibExecDirURL( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER );
     rtl::Bootstrap::expandMacros(aLibExecDirURL);
diff --git a/desktop/source/app/updater.hxx b/desktop/source/app/updater.hxx
index fab760516952..fa5349afbe11 100644
--- a/desktop/source/app/updater.hxx
+++ b/desktop/source/app/updater.hxx
@@ -12,7 +12,7 @@
 
 #include <rtl/ustring.hxx>
 
-void Update();
+void update();
 
 void update_checker();
 
commit eef5dbbf70ea526ac1c2ad475911c1dec58e0e81
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 00:46:51 2017 +0200

    follow redirects when downloading update files
    
    Change-Id: Ic6679aa3d150499b354ccb396c136178d662bb67

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 5b4b5c1ebac3..83d2a3010bf6 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -402,6 +402,7 @@ std::string download_content(const OString& rURL, bool bFile)
     curl_slist* headerlist = nullptr;
     headerlist = curl_slist_append(headerlist, buf);
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); // follow redirects
 
     std::string response_body;
     utl::TempFile aTempFile;
commit d13105098d6fa773a55be6be656b6e7d7fbe307f
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 00:45:27 2017 +0200

    executable names on linux and windows are different
    
    Also use different user agent strings.
    
    Change-Id: I047e743f2ea13ee5ea6bff1cb5d6d86ca2ac6417

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 0ca03bc9de9e..5b4b5c1ebac3 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -38,17 +38,22 @@ class error_updater : public std::exception
 {
 };
 
-static const char kUserAgent[] = "UpdateChecker/1.0 (Linux)";
+#ifdef UNX
+static const char kUserAgent[] = "LibreOffice UpdateChecker/1.0 (Linux)";
+#else
+static const char kUserAgent[] = "LibreOffice UpdateChecker/1.0 (unknown platform)";
+#endif
 
 #ifdef UNX
 const char* pUpdaterName = "updater";
+const char* pSofficeExeName = "soffice";
 #elif defined(WNT)
 const char* pUpdaterName = "updater.exe";
+const char* pSofficeExeName = "soffice.exe";
 #else
 #error "Need implementation"
 #endif
 
-const char* pSofficeExeName = "soffice";
 
 void CopyFileToDir(const OUString& rTempDirURL, const OUString rFileName, const OUString& rOldDir)
 {
commit 52d07cd097c522f1304775632b55e4c736528b8e
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sun Jan 8 21:16:45 2017 +0100

    add more TODO comments

diff --git a/onlineupdate/source/update/updater/loaddlls.cxx b/onlineupdate/source/update/updater/loaddlls.cxx
index 246d9f86bf79..6a0c8a61ee91 100644
--- a/onlineupdate/source/update/updater/loaddlls.cxx
+++ b/onlineupdate/source/update/updater/loaddlls.cxx
@@ -36,6 +36,7 @@ struct AutoLoadSystemDependencies
             }
         }
 
+        // TODO: moggi: do we need all that code?
         // When SetDefaultDllDirectories is not available, fallback to preloading
         // dlls. The order that these are loaded does not matter since they are
         // loaded using the LOAD_WITH_ALTERED_SEARCH_PATH flag.
commit e479b807f92cdd0c1589957c35cc6100a4fcede4
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Jan 6 05:45:49 2017 +0100

    add the astyle script used to format the files

diff --git a/onlineupdate/astyle.options b/onlineupdate/astyle.options
new file mode 100644
index 000000000000..fc8d9f69faff
--- /dev/null
+++ b/onlineupdate/astyle.options
@@ -0,0 +1,7 @@
+--style=allman
+-s4
+--indent=spaces=4
+--attach-namespaces
+--indent-switches
+--indent-col1-comments
+--pad-header
commit ad8fec98f5c4a76e7449dec2ffaa18e93b515fff
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Fri Jan 6 05:42:34 2017 +0100

    use a more libreoffice like formatting
    
    This formatting has been done by an astyle script. The idea is that with
    a consistent formatting it is much easier to bring in changes from
    Mozilla. Updating the code with the new version, running the astyle
    script and then looking through the diff seems like the most sensible
    option.

diff --git a/onlineupdate/source/libmar/sign/nss_secutil.h b/onlineupdate/source/libmar/sign/nss_secutil.h
index 363c64918068..f599fcce573d 100644
--- a/onlineupdate/source/libmar/sign/nss_secutil.h
+++ b/onlineupdate/source/libmar/sign/nss_secutil.h
@@ -16,14 +16,16 @@
 #include "key.h"
 #include <stdint.h>
 
-typedef struct {
-  enum {
-    PW_NONE = 0,
-    PW_FROMFILE = 1,
-    PW_PLAINTEXT = 2,
-    PW_EXTERNAL = 3
-  } source;
-  char *data;
+typedef struct
+{
+    enum
+    {
+        PW_NONE = 0,
+        PW_FROMFILE = 1,
+        PW_PLAINTEXT = 2,
+        PW_EXTERNAL = 3
+    } source;
+    char *data;
 } secuPWData;
 
 #if( defined(_WINDOWS) && !defined(_WIN32_WCE))
diff --git a/onlineupdate/source/libmar/verify/cryptox.h b/onlineupdate/source/libmar/verify/cryptox.h
index d08ef159a83c..eb8548fa7a4f 100644
--- a/onlineupdate/source/libmar/verify/cryptox.h
+++ b/onlineupdate/source/libmar/verify/cryptox.h
@@ -77,9 +77,9 @@ CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData,
                                        unsigned int aDataSize,
                                        CryptoX_PublicKey* aPublicKey);
 CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
-                                         CryptoX_PublicKey* aPublicKey,
-                                         const unsigned char* aSignature,
-                                         unsigned int aSignatureLen);
+        CryptoX_PublicKey* aPublicKey,
+        const unsigned char* aSignature,
+        unsigned int aSignatureLen);
 void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData);
 void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
 #ifdef __cplusplus
@@ -118,9 +118,9 @@ CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash);
 CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash,
                                       BYTE *buf, DWORD len);
 CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
-                                         HCRYPTKEY *pubKey,
-                                         const BYTE *signature,
-                                         DWORD signatureLen);
+        HCRYPTKEY *pubKey,
+        const BYTE *signature,
+        DWORD signatureLen);
 
 #define CryptoX_InvalidHandleValue ((ULONG_PTR)NULL)
 #define CryptoX_ProviderHandle HCRYPTPROV
diff --git a/onlineupdate/source/service/certificatecheck.cxx b/onlineupdate/source/service/certificatecheck.cxx
index 3a9eba020ccb..58d70162f40c 100644
--- a/onlineupdate/source/service/certificatecheck.cxx
+++ b/onlineupdate/source/service/certificatecheck.cxx
@@ -28,87 +28,97 @@ DWORD
 CheckCertificateForPEFile(LPCWSTR filePath,
                           CertificateCheckInfo &infoToMatch)
 {
-  HCERTSTORE certStore = nullptr;
-  HCRYPTMSG cryptMsg = nullptr;
-  PCCERT_CONTEXT certContext = nullptr;
-  PCMSG_SIGNER_INFO signerInfo = nullptr;
-  DWORD lastError = ERROR_SUCCESS;
+    HCERTSTORE certStore = nullptr;
+    HCRYPTMSG cryptMsg = nullptr;
+    PCCERT_CONTEXT certContext = nullptr;
+    PCMSG_SIGNER_INFO signerInfo = nullptr;
+    DWORD lastError = ERROR_SUCCESS;
 
-  // Get the HCERTSTORE and HCRYPTMSG from the signed file.
-  DWORD encoding, contentType, formatType;
-  BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
-                                  filePath,
-                                  CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
-                                  CERT_QUERY_CONTENT_FLAG_ALL,
-                                  0, &encoding, &contentType,
-                                  &formatType, &certStore, &cryptMsg, nullptr);
-  if (!result) {
-    lastError = GetLastError();
-    LOG_WARN(("CryptQueryObject failed.  (%d)", lastError));
-    goto cleanup;
-  }
+    // Get the HCERTSTORE and HCRYPTMSG from the signed file.
+    DWORD encoding, contentType, formatType;
+    BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
+                                   filePath,
+                                   CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+                                   CERT_QUERY_CONTENT_FLAG_ALL,
+                                   0, &encoding, &contentType,
+                                   &formatType, &certStore, &cryptMsg, nullptr);
+    if (!result)
+    {
+        lastError = GetLastError();
+        LOG_WARN(("CryptQueryObject failed.  (%d)", lastError));
+        goto cleanup;
+    }
 
-  // Pass in nullptr to get the needed signer information size.
-  DWORD signerInfoSize;
-  result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
-                            nullptr, &signerInfoSize);
-  if (!result) {
-    lastError = GetLastError();
-    LOG_WARN(("CryptMsgGetParam failed.  (%d)", lastError));
-    goto cleanup;
-  }
+    // Pass in nullptr to get the needed signer information size.
+    DWORD signerInfoSize;
+    result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
+                              nullptr, &signerInfoSize);
+    if (!result)
+    {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list