[Libreoffice-commits] core.git: Branch 'feature/mar-updater' - 76 commits - bin/update config_host/config_features.h.in config_host.mk.in configure.ac desktop/CppunitTest_desktop_app.mk desktop/inc desktop/Library_crashreport.mk desktop/Library_sofficeapp.mk desktop/source include/onlineupdate include/sfx2 Makefile.gbuild Makefile.in officecfg/files.mk officecfg/registry onlineupdate/Executable_mar.mk onlineupdate/Executable_updater.mk onlineupdate/Executable_update_service.mk onlineupdate/inc onlineupdate/Module_onlineupdate.mk onlineupdate/README onlineupdate/source onlineupdate/StaticLibrary_libmar.mk onlineupdate/StaticLibrary_winhelper.mk postprocess/CustomTarget_registry.mk Repository.mk sfx2/inc sfx2/source

Markus Mohrhard markus.mohrhard at googlemail.com
Fri Nov 18 13:18:14 UTC 2016


 Makefile.gbuild                                                       |   18 
 Makefile.in                                                           |   11 
 Repository.mk                                                         |   10 
 bin/update/common.sh                                                  |  205 
 bin/update/create_build_config.py                                     |   43 
 bin/update/create_full_mar.py                                         |   56 
 bin/update/create_full_mar_for_languages.py                           |   67 
 bin/update/make_full_update.sh                                        |  121 
 bin/update/make_incremental_update.sh                                 |  317 
 bin/update/tools.py                                                   |   51 
 bin/update/upload_build_config.py                                     |   40 
 bin/update/upload_builds.py                                           |   31 
 config_host.mk.in                                                     |    1 
 config_host/config_features.h.in                                      |    5 
 configure.ac                                                          |    8 
 desktop/CppunitTest_desktop_app.mk                                    |    4 
 desktop/Library_crashreport.mk                                        |    2 
 desktop/Library_sofficeapp.mk                                         |    6 
 desktop/inc/app.hxx                                                   |    3 
 desktop/source/app/app.cxx                                            |   53 
 desktop/source/app/updater.cxx                                        |  521 
 desktop/source/app/updater.hxx                                        |   21 
 dev/null                                                              |binary
 include/onlineupdate/mar_private.h                                    |    2 
 include/sfx2/sidebar/Panel.hxx                                        |    2 
 officecfg/files.mk                                                    |    1 
 officecfg/registry/schema/org/openoffice/Office/Update.xcs            |   52 
 onlineupdate/Executable_mar.mk                                        |   16 
 onlineupdate/Executable_update_service.mk                             |   33 
 onlineupdate/Executable_updater.mk                                    |   18 
 onlineupdate/Module_onlineupdate.mk                                   |    2 
 onlineupdate/README                                                   |    5 
 onlineupdate/StaticLibrary_libmar.mk                                  |   10 
 onlineupdate/StaticLibrary_winhelper.mk                               |   22 
 onlineupdate/inc/winhelper/windowsStart.hxx                           |   23 
 onlineupdate/source/libmar/sign/mar_sign.c                            |    2 
 onlineupdate/source/libmar/src/mar_read.c                             |    2 
 onlineupdate/source/libmar/tool/mar.c                                 |   47 
 onlineupdate/source/service/certificatecheck.cxx                      |  270 
 onlineupdate/source/service/certificatecheck.hxx                      |   22 
 onlineupdate/source/service/maintenanceservice.cxx                    |  391 
 onlineupdate/source/service/maintenanceservice.hxx                    |   10 
 onlineupdate/source/service/registrycertificates.cxx                  |  136 
 onlineupdate/source/service/registrycertificates.hxx                  |   13 
 onlineupdate/source/service/resource.hxx                              |   20 
 onlineupdate/source/service/servicebase.cxx                           |   86 
 onlineupdate/source/service/servicebase.hxx                           |   22 
 onlineupdate/source/service/serviceinstall.cxx                        |  733 +
 onlineupdate/source/service/serviceinstall.hxx                        |   21 
 onlineupdate/source/service/workmonitor.cxx                           |  684 +
 onlineupdate/source/service/workmonitor.hxx                           |    5 
 onlineupdate/source/update/common/pathhash.cxx                        |    3 
 onlineupdate/source/update/common/updatedefines.h                     |    3 
 onlineupdate/source/update/common/updatehelper.cxx                    |   11 
 onlineupdate/source/update/updater/archivereader.cxx                  |    6 
 onlineupdate/source/update/updater/gen_cert_header.py                 |   10 
 onlineupdate/source/update/updater/master-daily.der                   |binary
 onlineupdate/source/update/updater/nsWindowsRestart.cxx               |  577 
 onlineupdate/source/update/updater/primaryCert.h                      |    3 
 onlineupdate/source/update/updater/progressui_win.cxx                 |    3 
 onlineupdate/source/update/updater/secondaryCert.h                    |    3 
 onlineupdate/source/update/updater/updater-common.build               |   15 
 onlineupdate/source/update/updater/updater.cxx                        | 5824 +++++-----
 onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx |    1 
 onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h   |    1 
 onlineupdate/source/winhelper/windowsStart.cxx                        |  237 
 postprocess/CustomTarget_registry.mk                                  |    1 
 sfx2/inc/uitest/sfx_uiobject.hxx                                      |   50 
 sfx2/source/sidebar/Panel.cxx                                         |    7 
 sfx2/source/uitest/sfx_uiobject.cxx                                   |   81 
 70 files changed, 7652 insertions(+), 3428 deletions(-)

New commits:
commit 0a4a6707eb1ed21bc3159b8c8cd1b5e0753fc3ff
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sat Sep 17 16:42:46 2016 +0200

    add the missing libs for the test
    
    Change-Id: Iac96738d84a90f2125c1844c3380ea9a3a9c1645

diff --git a/desktop/CppunitTest_desktop_app.mk b/desktop/CppunitTest_desktop_app.mk
index aa5bf0c..47006f4 100644
--- a/desktop/CppunitTest_desktop_app.mk
+++ b/desktop/CppunitTest_desktop_app.mk
@@ -16,6 +16,10 @@ $(eval $(call gb_CppunitTest_add_exception_objects,desktop_app, \
 $(eval $(call gb_CppunitTest_use_externals,desktop_app, \
 	$(if $(ENABLE_BREAKPAD),breakpad) \
     dbus \
+	$(if $(ENABLE_ONLINE_UPDATE_MAR),\
+		curl \
+        orcus-parser \
+        orcus )\
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,desktop_app, \
commit ee8f247d6f4956023e74401669c9e729e25a5d60
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sat Sep 17 11:51:39 2016 +0200

    add certificate parts for current daily build cert
    
    Change-Id: I33fa792da09b5bfb05291eace3815c1312faa8de

diff --git a/onlineupdate/source/update/updater/master-daily.der b/onlineupdate/source/update/updater/master-daily.der
new file mode 100644
index 0000000..33dd3e7
Binary files /dev/null and b/onlineupdate/source/update/updater/master-daily.der differ
diff --git a/onlineupdate/source/update/updater/primaryCert.h b/onlineupdate/source/update/updater/primaryCert.h
new file mode 100644
index 0000000..f161aa3
--- /dev/null
+++ b/onlineupdate/source/update/updater/primaryCert.h
@@ -0,0 +1,3 @@
+const uint8_t primaryCertData[] = {
+    0x30, 0x82, 0x02, 0xc3, 0x30, 0x82, 0x01, 0xab, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x00, 0xa7, 0x67, 0xe2, 0xee, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x4f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x33, 0x30, 0x30, 0x30, 0x33, 0x31, 0x30, 0x35, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x33, 0x30, 0x30, 0x30, 0x33, 0x31, 0x30, 0x35, 0x5a, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x4f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x3
 0, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb3, 0x63, 0x91, 0x44, 0xf6, 0xf1, 0xd7, 0x7f, 0xc9, 0x3d, 0xee, 0x39, 0x44, 0xba, 0xd5, 0x1b, 0x68, 0x10, 0xfd, 0x2e, 0xb3, 0xe9, 0x17, 0xd8, 0x78, 0x18, 0xff, 0xbb, 0x63, 0x6f, 0x21, 0xd9, 0xb3, 0x55, 0x83, 0xe2, 0x90, 0x18, 0xba, 0x1e, 0x3b, 0x57, 0xbb, 0x4a, 0xc7, 0x4a, 0x3b, 0x49, 0x14, 0x1b, 0xe0, 0xc5, 0x01, 0x8e, 0xb3, 0xfc, 0xe0, 0x31, 0x21, 0xea, 0x6b, 0xc6, 0x5f, 0x70, 0x3c, 0x1f, 0x40, 0x9e, 0x6f, 0xf1, 0x37, 0xa0, 0x74, 0xc5, 0x55, 0xc7, 0x4d, 0x9c, 0xdd, 0x6b, 0xb4, 0xd3, 0x17, 0x22, 0x9e, 0x27, 0xea, 0x57, 0x45, 0x58, 0x19, 0x39, 0x18, 0x42, 0x37, 0x94, 0x8d, 0x11, 0xa1, 0xa9, 0xcb, 0xdd, 0x45, 0x7e, 0x82, 0xbf, 0x93, 0x75, 0xcc, 0x8d, 0x95, 0x04, 0x74, 0xc0, 0x84, 0x2e, 0x7d, 0xbc, 0x56, 0x2d, 0xd1, 0x0e, 0x2e, 0xbf, 0x0e, 0x52, 0x22, 0x0c, 0x65, 0xb2, 0x7a, 0x12, 0x14, 0x27, 0x0b, 0xc9, 0x37, 0x30, 0x48, 0xbc, 0xf0, 0xb8, 0x6d, 0x6f, 0x38, 0xda, 0x98, 0xd0, 0x1c, 0x87, 0xfe, 0x69, 0xc4, 0xc7, 0x73, 0xed, 0x78, 0x01
 , 0xa5, 0xea, 0x48, 0x08, 0x28, 0xcc, 0x0e, 0x52, 0x20, 0x1f, 0x46, 0x42, 0x83, 0x2e, 0xa6, 0xfd, 0x30, 0xc6, 0x48, 0x55, 0x78, 0xff, 0xd6, 0xac, 0xdd, 0x61, 0xd3, 0xb9, 0xdb, 0x49, 0x6b, 0x93, 0x5a, 0x5b, 0x37, 0xf5, 0xcb, 0x09, 0x4a, 0x6c, 0xa3, 0x85, 0x1f, 0xeb, 0x33, 0x3f, 0xd0, 0xda, 0x55, 0xc3, 0xb2, 0x56, 0x7d, 0x13, 0x16, 0x23, 0x2b, 0x1c, 0x3f, 0xdd, 0x1a, 0xf9, 0x90, 0xf7, 0x43, 0x63, 0x80, 0xa5, 0x71, 0xce, 0x23, 0x56, 0x1b, 0xbf, 0x51, 0x3a, 0xfe, 0x6b, 0x48, 0xfd, 0x42, 0x50, 0xc0, 0x09, 0x30, 0x32, 0x27, 0x20, 0x0d, 0xda, 0x32, 0x02, 0x23, 0x92, 0x10, 0x85, 0xbf, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0xb2, 0x3f, 0x45, 0x2c, 0xf5, 0x75, 0xeb, 0x20, 0x2f, 0x76, 0x6f, 0x18, 0x06, 0x42, 0x20, 0x83, 0x39, 0x50, 0x64, 0x07, 0xbb, 0xb1, 0x38, 0x74, 0xbe, 0xbb, 0xf4, 0x25, 0x11, 0x72, 0xf9, 0x4a, 0xf0, 0x9a, 0x0b, 0xe7, 0x45, 0x22, 0x59, 0x04, 0x7b, 0xa4,
  0xe8, 0x46, 0xe5, 0x67, 0xdb, 0x9a, 0x9e, 0x27, 0x94, 0x5e, 0x60, 0x8b, 0xf5, 0xb1, 0x3f, 0xf2, 0xab, 0x1c, 0x54, 0xc8, 0xbc, 0x2b, 0x83, 0xf9, 0xa7, 0x18, 0x02, 0xb6, 0x95, 0xfa, 0xde, 0x16, 0x49, 0xca, 0xbd, 0x2e, 0xfc, 0xb6, 0x36, 0x9a, 0x9a, 0x7a, 0x1f, 0xc8, 0x91, 0xce, 0x30, 0xe2, 0x89, 0x58, 0x05, 0xee, 0xf3, 0xd1, 0xed, 0x79, 0x45, 0x20, 0xbd, 0x84, 0x48, 0xb0, 0x56, 0x8e, 0x04, 0xc8, 0xb7, 0x7e, 0x46, 0x2a, 0x2e, 0xb3, 0xca, 0xc1, 0xb6, 0x0b, 0xd4, 0x31, 0x6e, 0x83, 0x13, 0xe9, 0xa5, 0xbd, 0x17, 0x0e, 0x47, 0x34, 0x99, 0xc9, 0x5b, 0xb2, 0x53, 0x73, 0x57, 0xeb, 0x30, 0x0d, 0x2d, 0xaa, 0x25, 0xbb, 0xab, 0xac, 0xe8, 0xda, 0xf0, 0xf1, 0xd7, 0x2d, 0x17, 0x70, 0x9e, 0x30, 0x3c, 0x38, 0x59, 0xbf, 0x40, 0x3f, 0x6e, 0xe4, 0x22, 0x84, 0x94, 0x59, 0xf6, 0x32, 0xc1, 0xcb, 0x9c, 0x56, 0x52, 0x04, 0xeb, 0xf6, 0xa3, 0x75, 0xf8, 0xcb, 0xed, 0xaf, 0x17, 0x57, 0x8f, 0x98, 0x56, 0xa4, 0x9d, 0x85, 0x16, 0xc8, 0xf7, 0xd6, 0x97, 0xed, 0xab, 0xe0, 0x4c, 0x1a, 0x44, 0x5c, 0x68, 0x30, 0x26, 0x40, 
 0x6b, 0xe9, 0x88, 0x6a, 0x37, 0x1e, 0xbf, 0x25, 0x38, 0x55, 0xd9, 0x84, 0x8d, 0x55, 0x08, 0xe6, 0x18, 0xc3, 0xd7, 0x96, 0xfa, 0xd0, 0x2f, 0x17, 0x9b, 0xb6, 0x40, 0xc3, 0x47, 0xb3, 0x30, 0x01, 0x59, 0xec, 0x7c, 0x8d, 0x7e, 0x0a, 0x0d, 0xeb, 0xc4, 0x3b, 0x06, 0x4e, 0x97, 0x41, 0x5e
+};
diff --git a/onlineupdate/source/update/updater/secondaryCert.h b/onlineupdate/source/update/updater/secondaryCert.h
new file mode 100644
index 0000000..7453f27
--- /dev/null
+++ b/onlineupdate/source/update/updater/secondaryCert.h
@@ -0,0 +1,3 @@
+const uint8_t secondaryCertData[] = {
+    0x30, 0x82, 0x02, 0xc3, 0x30, 0x82, 0x01, 0xab, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x00, 0xa7, 0x67, 0xe2, 0xee, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x4f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x33, 0x30, 0x30, 0x30, 0x33, 0x31, 0x30, 0x35, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x33, 0x30, 0x30, 0x30, 0x33, 0x31, 0x30, 0x35, 0x5a, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x4f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x3
 0, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb3, 0x63, 0x91, 0x44, 0xf6, 0xf1, 0xd7, 0x7f, 0xc9, 0x3d, 0xee, 0x39, 0x44, 0xba, 0xd5, 0x1b, 0x68, 0x10, 0xfd, 0x2e, 0xb3, 0xe9, 0x17, 0xd8, 0x78, 0x18, 0xff, 0xbb, 0x63, 0x6f, 0x21, 0xd9, 0xb3, 0x55, 0x83, 0xe2, 0x90, 0x18, 0xba, 0x1e, 0x3b, 0x57, 0xbb, 0x4a, 0xc7, 0x4a, 0x3b, 0x49, 0x14, 0x1b, 0xe0, 0xc5, 0x01, 0x8e, 0xb3, 0xfc, 0xe0, 0x31, 0x21, 0xea, 0x6b, 0xc6, 0x5f, 0x70, 0x3c, 0x1f, 0x40, 0x9e, 0x6f, 0xf1, 0x37, 0xa0, 0x74, 0xc5, 0x55, 0xc7, 0x4d, 0x9c, 0xdd, 0x6b, 0xb4, 0xd3, 0x17, 0x22, 0x9e, 0x27, 0xea, 0x57, 0x45, 0x58, 0x19, 0x39, 0x18, 0x42, 0x37, 0x94, 0x8d, 0x11, 0xa1, 0xa9, 0xcb, 0xdd, 0x45, 0x7e, 0x82, 0xbf, 0x93, 0x75, 0xcc, 0x8d, 0x95, 0x04, 0x74, 0xc0, 0x84, 0x2e, 0x7d, 0xbc, 0x56, 0x2d, 0xd1, 0x0e, 0x2e, 0xbf, 0x0e, 0x52, 0x22, 0x0c, 0x65, 0xb2, 0x7a, 0x12, 0x14, 0x27, 0x0b, 0xc9, 0x37, 0x30, 0x48, 0xbc, 0xf0, 0xb8, 0x6d, 0x6f, 0x38, 0xda, 0x98, 0xd0, 0x1c, 0x87, 0xfe, 0x69, 0xc4, 0xc7, 0x73, 0xed, 0x78, 0x01
 , 0xa5, 0xea, 0x48, 0x08, 0x28, 0xcc, 0x0e, 0x52, 0x20, 0x1f, 0x46, 0x42, 0x83, 0x2e, 0xa6, 0xfd, 0x30, 0xc6, 0x48, 0x55, 0x78, 0xff, 0xd6, 0xac, 0xdd, 0x61, 0xd3, 0xb9, 0xdb, 0x49, 0x6b, 0x93, 0x5a, 0x5b, 0x37, 0xf5, 0xcb, 0x09, 0x4a, 0x6c, 0xa3, 0x85, 0x1f, 0xeb, 0x33, 0x3f, 0xd0, 0xda, 0x55, 0xc3, 0xb2, 0x56, 0x7d, 0x13, 0x16, 0x23, 0x2b, 0x1c, 0x3f, 0xdd, 0x1a, 0xf9, 0x90, 0xf7, 0x43, 0x63, 0x80, 0xa5, 0x71, 0xce, 0x23, 0x56, 0x1b, 0xbf, 0x51, 0x3a, 0xfe, 0x6b, 0x48, 0xfd, 0x42, 0x50, 0xc0, 0x09, 0x30, 0x32, 0x27, 0x20, 0x0d, 0xda, 0x32, 0x02, 0x23, 0x92, 0x10, 0x85, 0xbf, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0xb2, 0x3f, 0x45, 0x2c, 0xf5, 0x75, 0xeb, 0x20, 0x2f, 0x76, 0x6f, 0x18, 0x06, 0x42, 0x20, 0x83, 0x39, 0x50, 0x64, 0x07, 0xbb, 0xb1, 0x38, 0x74, 0xbe, 0xbb, 0xf4, 0x25, 0x11, 0x72, 0xf9, 0x4a, 0xf0, 0x9a, 0x0b, 0xe7, 0x45, 0x22, 0x59, 0x04, 0x7b, 0xa4,
  0xe8, 0x46, 0xe5, 0x67, 0xdb, 0x9a, 0x9e, 0x27, 0x94, 0x5e, 0x60, 0x8b, 0xf5, 0xb1, 0x3f, 0xf2, 0xab, 0x1c, 0x54, 0xc8, 0xbc, 0x2b, 0x83, 0xf9, 0xa7, 0x18, 0x02, 0xb6, 0x95, 0xfa, 0xde, 0x16, 0x49, 0xca, 0xbd, 0x2e, 0xfc, 0xb6, 0x36, 0x9a, 0x9a, 0x7a, 0x1f, 0xc8, 0x91, 0xce, 0x30, 0xe2, 0x89, 0x58, 0x05, 0xee, 0xf3, 0xd1, 0xed, 0x79, 0x45, 0x20, 0xbd, 0x84, 0x48, 0xb0, 0x56, 0x8e, 0x04, 0xc8, 0xb7, 0x7e, 0x46, 0x2a, 0x2e, 0xb3, 0xca, 0xc1, 0xb6, 0x0b, 0xd4, 0x31, 0x6e, 0x83, 0x13, 0xe9, 0xa5, 0xbd, 0x17, 0x0e, 0x47, 0x34, 0x99, 0xc9, 0x5b, 0xb2, 0x53, 0x73, 0x57, 0xeb, 0x30, 0x0d, 0x2d, 0xaa, 0x25, 0xbb, 0xab, 0xac, 0xe8, 0xda, 0xf0, 0xf1, 0xd7, 0x2d, 0x17, 0x70, 0x9e, 0x30, 0x3c, 0x38, 0x59, 0xbf, 0x40, 0x3f, 0x6e, 0xe4, 0x22, 0x84, 0x94, 0x59, 0xf6, 0x32, 0xc1, 0xcb, 0x9c, 0x56, 0x52, 0x04, 0xeb, 0xf6, 0xa3, 0x75, 0xf8, 0xcb, 0xed, 0xaf, 0x17, 0x57, 0x8f, 0x98, 0x56, 0xa4, 0x9d, 0x85, 0x16, 0xc8, 0xf7, 0xd6, 0x97, 0xed, 0xab, 0xe0, 0x4c, 0x1a, 0x44, 0x5c, 0x68, 0x30, 0x26, 0x40, 
 0x6b, 0xe9, 0x88, 0x6a, 0x37, 0x1e, 0xbf, 0x25, 0x38, 0x55, 0xd9, 0x84, 0x8d, 0x55, 0x08, 0xe6, 0x18, 0xc3, 0xd7, 0x96, 0xfa, 0xd0, 0x2f, 0x17, 0x9b, 0xb6, 0x40, 0xc3, 0x47, 0xb3, 0x30, 0x01, 0x59, 0xec, 0x7c, 0x8d, 0x7e, 0x0a, 0x0d, 0xeb, 0xc4, 0x3b, 0x06, 0x4e, 0x97, 0x41, 0x5e
+};
commit 85f69f43c9b164a043c87ae7cf060d6eab246525
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sat Sep 17 07:46:25 2016 +0200

    update the last update check time
    
    Change-Id: I4a664c5dca2fcefbea49e1e550e82d191ba358dd

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index c4dfef0..f1727be 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1252,9 +1252,6 @@ void restartOnMac(bool passArguments) {
 bool isTimeForUpdateCheck()
 {
     sal_uInt64 nLastUpdate = officecfg::Office::Update::Update::LastUpdateTime::get();
-    if (nLastUpdate == 0)
-        return true;
-
     sal_uInt64 nNow = tools::Time::GetSystemTicks();
 
     sal_uInt64 n7DayInMS = 1000 * 60 * 60 * 24 * 7; // 7 days in ms
@@ -1508,7 +1505,10 @@ int Desktop::Main()
             if (isTimeForUpdateCheck())
             {
                 sal_uInt64 nNow = tools::Time::GetSystemTicks();
-                officecfg::Office::Update::Update::LastUpdateTime::set(nNow);
+                std::shared_ptr< comphelper::ConfigurationChanges > batch(
+                        comphelper::ConfigurationChanges::create());
+                officecfg::Office::Update::Update::LastUpdateTime::set(nNow, batch);
+                batch->commit();
                 m_aUpdateThread = std::thread(update_checker);
             }
         }
diff --git a/officecfg/registry/schema/org/openoffice/Office/Update.xcs b/officecfg/registry/schema/org/openoffice/Office/Update.xcs
index 6c25d74..49021c3 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Update.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Update.xcs
@@ -29,11 +29,11 @@
             </info>
             <value>Some Value</value>
         </prop>
-        <prop oor:name="LastUpdateTime" oor:type="xs:int" oor:nillable="false">
+        <prop oor:name="LastUpdateTime" oor:type="xs:long" oor:nillable="false">
             <info>
                 <desc>The last time the update check ran</desc>
             </info>
-            <value>-1</value>
+            <value>0</value>
         </prop>
         <prop oor:name="URL" oor:type="xs:string" oor:nillable="false">
             <info>
commit eb2289f3cc51584cc1e60d0cfe4b89343b9cf0a7
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Sep 12 06:11:18 2016 +0200

    only check for updates once every 7 days
    
    Change-Id: Ia2dc109ba80c346922c0236c3ca6ea09e18e9eb3

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 98bcd74..c4dfef0 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1251,7 +1251,17 @@ void restartOnMac(bool passArguments) {
 
 bool isTimeForUpdateCheck()
 {
-    return true;
+    sal_uInt64 nLastUpdate = officecfg::Office::Update::Update::LastUpdateTime::get();
+    if (nLastUpdate == 0)
+        return true;
+
+    sal_uInt64 nNow = tools::Time::GetSystemTicks();
+
+    sal_uInt64 n7DayInMS = 1000 * 60 * 60 * 24 * 7; // 7 days in ms
+    if (nNow - n7DayInMS >= nLastUpdate)
+        return true;
+
+    return false;
 }
 
 }
@@ -1496,7 +1506,11 @@ int Desktop::Main()
             }
 
             if (isTimeForUpdateCheck())
+            {
+                sal_uInt64 nNow = tools::Time::GetSystemTicks();
+                officecfg::Office::Update::Update::LastUpdateTime::set(nNow);
                 m_aUpdateThread = std::thread(update_checker);
+            }
         }
 #endif
 
commit ee687a0a01e59f5d1a13308fe8bab2ca521421fe
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Sep 8 07:55:48 2016 +0200

    update the updater code from mozilla
    
    Change-Id: I400a7d103cf5bbd1a8b86c54a5d1b84c7dbf34e8

diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx
index a0813ae..2d20698 100644
--- a/onlineupdate/source/update/updater/updater.cxx
+++ b/onlineupdate/source/update/updater/updater.cxx
@@ -80,8 +80,19 @@
 
 #if defined(MACOSX)
 // These functions are defined in launchchild_osx.mm
-void LaunchChild(int argc, char **argv);
+void CleanupElevatedMacUpdate(bool aFailureOccurred);
+bool IsOwnedByGroupAdmin(const char* aAppBundle);
+bool IsRecursivelyWritable(const char* aPath);
+void LaunchChild(int argc, const char** argv);
 void LaunchMacPostProcess(const char* aAppBundle);
+bool ObtainUpdaterArguments(int* argc, char*** argv);
+bool ServeElevatedUpdate(int argc, const char** argv);
+void SetGroupOwnershipAndPermissions(const char* aAppBundle);
+struct UpdateServerThreadArgs
+{
+    int argc;
+    const NS_tchar** argv;
+};
 #endif
 
 #ifndef SSIZE_MAX
@@ -102,6 +113,13 @@ void LaunchMacPostProcess(const char* aAppBundle);
 #endif
 
 #ifdef _WIN32
+#ifdef MOZ_MAINTENANCE_SERVICE
+#include "registrycertificates.h"
+#endif
+BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
+BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer,
+        LPCWSTR siblingFilePath,
+        LPCWSTR newFileName);
 #include "updatehelper.h"
 
 // Closes the handle if valid and if the updater is elevated returns with the
@@ -113,6 +131,7 @@ void LaunchMacPostProcess(const char* aAppBundle);
         CloseHandle(handle); \
     } \
     if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \
+        LogFinish(); \
         return retCode; \
     } \
 }
@@ -204,6 +223,7 @@ static bool sIsOSUpdate = false;
 static NS_tchar* gDestPath;
 static NS_tchar gCallbackRelPath[MAXPATHLEN];
 static NS_tchar gCallbackBackupPath[MAXPATHLEN];
+static NS_tchar gDeleteDirPath[MAXPATHLEN];
 #endif
 
 static const NS_tchar kWhitespace[] = NS_T(" \t");
@@ -264,9 +284,8 @@ EnvHasValue(const char *name)
     return (val && *val);
 }
 
-#ifdef _WIN32
 /**
- * Coverts a relative update path to a full path for Windows.
+ * Coverts a relative update path to a full path.
  *
  * @param  relpath
  *         The relative path to convert to a full path.
@@ -275,23 +294,56 @@ EnvHasValue(const char *name)
 static NS_tchar*
 get_full_path(const NS_tchar *relpath)
 {
-    size_t lendestpath = NS_tstrlen(gDestPath);
+    NS_tchar *destpath = sStagedUpdate ? gWorkingDirPath : gInstallDirPath;
+    size_t lendestpath = NS_tstrlen(destpath);
     size_t lenrelpath = NS_tstrlen(relpath);
-    NS_tchar *s = (NS_tchar *) malloc((lendestpath + lenrelpath + 1) * sizeof(NS_tchar));
-    if (!s)
+    NS_tchar *s = new NS_tchar[lendestpath + lenrelpath + 2];
+    if (!s) {
         return nullptr;
+    }
 
     NS_tchar *c = s;
 
-    NS_tstrcpy(c, gDestPath);
+    NS_tstrcpy(c, destpath);
     c += lendestpath;
+    NS_tstrcat(c, NS_T("/"));
+    c++;
+
     NS_tstrcat(c, relpath);
     c += lenrelpath;
     *c = NS_T('\0');
-    c++;
     return s;
 }
+
+/**
+ * Converts a full update path into a relative path; reverses get_full_path.
+ *
+ * @param  fullpath
+ *         The absolute path to convert into a relative path.
+ * return pointer to the location within fullpath where the relative path starts
+ *        or fullpath itself if it already looks relative.
+ */
+static const NS_tchar*
+get_relative_path(const NS_tchar *fullpath)
+{
+    // If the path isn't absolute, just return it as-is.
+#ifdef _WIN32
+    if (fullpath[1] != ':' && fullpath[2] != '\\') {
+#else
+    if (fullpath[0] != '/') {
 #endif
+        return fullpath;
+    }
+
+    NS_tchar *prefix = sStagedUpdate ? gWorkingDirPath : gInstallDirPath;
+
+    // If the path isn't long enough to be absolute, return it as-is.
+    if (NS_tstrlen(fullpath) <= NS_tstrlen(prefix)) {
+        return fullpath;
+    }
+
+    return fullpath + NS_tstrlen(prefix) + 1;
+}
 
 /**
  * Gets the platform specific path and performs simple checks to the path. If
@@ -852,14 +904,18 @@ static int backup_create(const NS_tchar *path)
 
 // Rename the backup of the specified file that was created by renaming it back
 // to the original file.
-static int backup_restore(const NS_tchar *path)
+static int backup_restore(const NS_tchar *path, const NS_tchar *relPath)
 {
     NS_tchar backup[MAXPATHLEN];
     NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
             NS_T("%s") BACKUP_EXT, path);
 
+    NS_tchar relBackup[MAXPATHLEN];
+    NS_tsnprintf(relBackup, sizeof(relBackup) / sizeof(relBackup[0]),
+            NS_T("%s") BACKUP_EXT, relPath);
+
     if (NS_taccess(backup, F_OK)) {
-        LOG(("backup_restore: backup file doesn't exist: " LOG_S, backup));
+        LOG(("backup_restore: backup file doesn't exist: " LOG_S, relBackup));
         return OK;
     }
 
@@ -867,12 +923,16 @@ static int backup_restore(const NS_tchar *path)
 }
 
 // Discard the backup of the specified file that was created by renaming it.
-static int backup_discard(const NS_tchar *path)
+static int backup_discard(const NS_tchar *path, const NS_tchar *relPath)
 {
     NS_tchar backup[MAXPATHLEN];
     NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
             NS_T("%s") BACKUP_EXT, path);
 
+    NS_tchar relBackup[MAXPATHLEN];
+    NS_tsnprintf(relBackup, sizeof(relBackup) / sizeof(relBackup[0]),
+            NS_T("%s") BACKUP_EXT, relPath);
+
     // Nothing to discard
     if (NS_taccess(backup, F_OK)) {
         return OK;
@@ -881,12 +941,12 @@ static int backup_discard(const NS_tchar *path)
     int rv = ensure_remove(backup);
 #if defined(_WIN32)
     if (rv && !sStagedUpdate && !sReplaceRequest) {
-        LOG(("backup_discard: unable to remove: " LOG_S, backup));
+        LOG(("backup_discard: unable to remove: " LOG_S, relBackup));
         NS_tchar path[MAXPATHLEN];
-        GetTempFileNameW(DELETE_DIR, L"moz", 0, path);
+        GetTempFileNameW(gDeleteDirPath, L"moz", 0, path);
         if (rename_file(backup, path)) {
             LOG(("backup_discard: failed to rename file:" LOG_S ", dst:" LOG_S,
-                        backup, path));
+                        relBackup, relPath));
             return WRITE_ERROR_DELETE_BACKUP;
         }
         // The MoveFileEx call to remove the file on OS reboot will fail if the
@@ -896,10 +956,10 @@ static int backup_discard(const NS_tchar *path)
         // applied, on reinstall, and on uninstall.
         if (MoveFileEx(path, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
             LOG(("backup_discard: file renamed and will be removed on OS " \
-                        "reboot: " LOG_S, path));
+                        "reboot: " LOG_S, relPath));
         } else {
             LOG(("backup_discard: failed to schedule OS reboot removal of " \
-                        "file: " LOG_S, path));
+                        "file: " LOG_S, relPath));
         }
     }
 #else
@@ -911,12 +971,13 @@ static int backup_discard(const NS_tchar *path)
 }
 
 // Helper function for post-processing a temporary backup.
-static void backup_finish(const NS_tchar *path, int status)
+static void backup_finish(const NS_tchar *path, const NS_tchar *relPath,
+        int status)
 {
     if (status == OK)
-        backup_discard(path);
+        backup_discard(path, relPath);
     else
-        backup_restore(path);
+        backup_restore(path, relPath);
 }
 
 //-----------------------------------------------------------------------------
@@ -954,7 +1015,7 @@ private:
 class RemoveFile : public Action
 {
 public:
-    RemoveFile() : mFile(nullptr), mSkip(0) { }
+    RemoveFile() : mSkip(0) { }
 
     int Parse(NS_tchar *line);
     int Prepare();
@@ -962,7 +1023,8 @@ public:
     void Finish(int status);
 
 private:
-    const NS_tchar *mFile;
+    std::unique_ptr<const NS_tchar> mFile;
+    std::unique_ptr<NS_tchar> mRelPath;
     int mSkip;
 };
 
@@ -971,10 +1033,18 @@ RemoveFile::Parse(NS_tchar *line)
 {
     // format "<deadfile>"
 
-    mFile = get_valid_path(&line);
-    if (!mFile)
+    NS_tchar* validPath = get_valid_path(&line);
+    if (!validPath)
         return PARSE_ERROR;
 
+    mRelPath = std::unique_ptr<NS_tchar>(new NS_tchar[MAXPATHLEN]);
+    NS_tstrcpy(mRelPath.get(), validPath);
+
+    mFile.reset(get_full_path(validPath));
+    if (!mFile) {
+        return PARSE_ERROR;
+    }
+
     return OK;
 }
 
@@ -982,33 +1052,33 @@ int
 RemoveFile::Prepare()
 {
     // Skip the file if it already doesn't exist.
-    int rv = NS_taccess(mFile, F_OK);
+    int rv = NS_taccess(mFile.get(), F_OK);
     if (rv) {
         mSkip = 1;
         mProgressCost = 0;
         return OK;
     }
 
-    LOG(("PREPARE REMOVEFILE " LOG_S, mFile));
+    LOG(("PREPARE REMOVEFILE " LOG_S, mRelPath.get()));
 
     // Make sure that we're actually a file...
     struct NS_tstat_t fileInfo;
-    rv = NS_tstat(mFile, &fileInfo);
+    rv = NS_tstat(mFile.get(), &fileInfo);
     if (rv) {
-        LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
+        LOG(("failed to read file status info: " LOG_S ", err: %d", mFile.get(),
                     errno));
         return READ_ERROR;
     }
 
     if (!S_ISREG(fileInfo.st_mode)) {
-        LOG(("path present, but not a file: " LOG_S, mFile));
+        LOG(("path present, but not a file: " LOG_S, mFile.get()));
         return DELETE_ERROR_EXPECTED_FILE;
     }
 
-    NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile, NS_T('/'));
+    NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile.get(), NS_T('/'));
     if (slash) {
         *slash = NS_T('\0');
-        rv = NS_taccess(mFile, W_OK);
+        rv = NS_taccess(mFile.get(), W_OK);
         *slash = NS_T('/');
     } else {
         rv = NS_taccess(NS_T("."), W_OK);
@@ -1028,11 +1098,11 @@ RemoveFile::Execute()
     if (mSkip)
         return OK;
 
-    LOG(("EXECUTE REMOVEFILE " LOG_S, mFile));
+    LOG(("EXECUTE REMOVEFILE " LOG_S, mRelPath.get()));
 
     // The file is checked for existence here and in Prepare since it might have
     // been removed by a separate instruction: bug 311099.
-    int rv = NS_taccess(mFile, F_OK);
+    int rv = NS_taccess(mFile.get(), F_OK);
     if (rv) {
         LOG(("file cannot be removed because it does not exist; skipping"));
         mSkip = 1;
@@ -1040,7 +1110,7 @@ RemoveFile::Execute()
     }
 
     // Rename the old file. It will be removed in Finish.
-    rv = backup_create(mFile);
+    rv = backup_create(mFile.get());
     if (rv) {
         LOG(("backup_create failed: %d", rv));
         return rv;
@@ -1055,15 +1125,15 @@ RemoveFile::Finish(int status)
     if (mSkip)
         return;
 
-    LOG(("FINISH REMOVEFILE " LOG_S, mFile));
+    LOG(("FINISH REMOVEFILE " LOG_S, mRelPath.get()));
 
-    backup_finish(mFile, status);
+    backup_finish(mFile.get(), mRelPath.get(), status);
 }
 
 class RemoveDir : public Action
 {
 public:
-    RemoveDir() : mDir(nullptr), mSkip(0) { }
+    RemoveDir() : mSkip(0) { }
 
     virtual int Parse(NS_tchar *line);
     virtual int Prepare(); // check that the source dir exists
@@ -1071,7 +1141,8 @@ public:
     virtual void Finish(int status);
 
 private:
-    const NS_tchar *mDir;
+    std::unique_ptr<NS_tchar> mDir;
+    std::unique_ptr<NS_tchar> mRelPath;
     int mSkip;
 };
 
@@ -1080,9 +1151,16 @@ RemoveDir::Parse(NS_tchar *line)
 {
     // format "<deaddir>/"
 
-    mDir = get_valid_path(&line, true);
-    if (!mDir)
+    NS_tchar* validPath = get_valid_path(&line, true);
+    if (!validPath)
+        return PARSE_ERROR;
+    mRelPath = std::unique_ptr<NS_tchar>(new NS_tchar[MAXPATHLEN]);
+    NS_tstrcpy(mRelPath.get(), validPath);
+
+    mDir.reset(get_full_path(validPath));
+    if (!mDir) {
         return PARSE_ERROR;
+    }
 
     return OK;
 }
@@ -1091,30 +1169,30 @@ int
 RemoveDir::Prepare()
 {
     // We expect the directory to exist if we are to remove it.
-    int rv = NS_taccess(mDir, F_OK);
+    int rv = NS_taccess(mDir.get(), F_OK);
     if (rv) {
         mSkip = 1;
         mProgressCost = 0;
         return OK;
     }
 
-    LOG(("PREPARE REMOVEDIR " LOG_S "/", mDir));
+    LOG(("PREPARE REMOVEDIR " LOG_S "/", mRelPath.get()));
 
     // Make sure that we're actually a dir.
     struct NS_tstat_t dirInfo;
-    rv = NS_tstat(mDir, &dirInfo);
+    rv = NS_tstat(mDir.get(), &dirInfo);
     if (rv) {
-        LOG(("failed to read directory status info: " LOG_S ", err: %d", mDir,
+        LOG(("failed to read directory status info: " LOG_S ", err: %d", mRelPath.get(),
                     errno));
         return READ_ERROR;
     }
 
     if (!S_ISDIR(dirInfo.st_mode)) {
-        LOG(("path present, but not a directory: " LOG_S, mDir));
+        LOG(("path present, but not a directory: " LOG_S, mRelPath.get()));
         return DELETE_ERROR_EXPECTED_DIR;
     }
 
-    rv = NS_taccess(mDir, W_OK);
+    rv = NS_taccess(mDir.get(), W_OK);
     if (rv) {
         LOG(("access failed: %d, %d", rv, errno));
         return WRITE_ERROR_DIR_ACCESS_DENIED;
@@ -1129,11 +1207,11 @@ RemoveDir::Execute()
     if (mSkip)
         return OK;
 
-    LOG(("EXECUTE REMOVEDIR " LOG_S "/", mDir));
+    LOG(("EXECUTE REMOVEDIR " LOG_S "/", mRelPath.get()));
 
     // The directory is checked for existence at every step since it might have
     // been removed by a separate instruction: bug 311099.
-    int rv = NS_taccess(mDir, F_OK);
+    int rv = NS_taccess(mDir.get(), F_OK);
     if (rv) {
         LOG(("directory no longer exists; skipping"));
         mSkip = 1;
@@ -1148,11 +1226,11 @@ RemoveDir::Finish(int status)
     if (mSkip || status != OK)
         return;
 
-    LOG(("FINISH REMOVEDIR " LOG_S "/", mDir));
+    LOG(("FINISH REMOVEDIR " LOG_S "/", mRelPath.get()));
 
     // The directory is checked for existence at every step since it might have
     // been removed by a separate instruction: bug 311099.
-    int rv = NS_taccess(mDir, F_OK);
+    int rv = NS_taccess(mDir.get(), F_OK);
     if (rv) {
         LOG(("directory no longer exists; skipping"));
         return;
@@ -1160,9 +1238,9 @@ RemoveDir::Finish(int status)
 
 
     if (status == OK) {
-        if (NS_trmdir(mDir)) {
+        if (NS_trmdir(mDir.get())) {
             LOG(("non-fatal error removing directory: " LOG_S "/, rv: %d, err: %d",
-                        mDir, rv, errno));
+                        mRelPath.get(), rv, errno));
         }
     }
 }
@@ -1170,9 +1248,7 @@ RemoveDir::Finish(int status)
 class AddFile : public Action
 {
 public:
-    AddFile() : mFile(nullptr)
-                , mAdded(false)
-    { }
+    AddFile() : mAdded(false) { }
 
     virtual int Parse(NS_tchar *line);
     virtual int Prepare();
@@ -1180,7 +1256,8 @@ public:
     virtual void Finish(int status);
 
 private:
-    const NS_tchar *mFile;
+    std::unique_ptr<NS_tchar> mFile;
+    std::unique_ptr<NS_tchar> mRelPath;
     bool mAdded;
 };
 
@@ -1189,9 +1266,18 @@ AddFile::Parse(NS_tchar *line)
 {
     // format "<newfile>"
 
-    mFile = get_valid_path(&line);
-    if (!mFile)
+    NS_tchar* validPath = get_valid_path(&line);
+    if (!validPath)
+        return PARSE_ERROR;
+
+    mRelPath = std::unique_ptr<NS_tchar>(new NS_tchar[MAXPATHLEN]);
+
+    NS_tstrcpy(mRelPath.get(), validPath);
+
+    mFile.reset(get_full_path(validPath));
+    if (!mFile) {
         return PARSE_ERROR;
+    }
 
     return OK;
 }
@@ -1199,7 +1285,7 @@ AddFile::Parse(NS_tchar *line)
 int
 AddFile::Prepare()
 {
-    LOG(("PREPARE ADD " LOG_S, mFile));
+    LOG(("PREPARE ADD " LOG_S, mRelPath.get()));
 
     return OK;
 }
@@ -1207,33 +1293,33 @@ AddFile::Prepare()
 int
 AddFile::Execute()
 {
-    LOG(("EXECUTE ADD " LOG_S, mFile));
+    LOG(("EXECUTE ADD " LOG_S, mRelPath.get()));
 
     int rv;
 
     // First make sure that we can actually get rid of any existing file.
-    rv = NS_taccess(mFile, F_OK);
+    rv = NS_taccess(mFile.get(), F_OK);
     if (rv == 0) {
-        rv = backup_create(mFile);
+        rv = backup_create(mFile.get());
         if (rv)
             return rv;
     } else {
-        rv = ensure_parent_dir(mFile);
+        rv = ensure_parent_dir(mFile.get());
         if (rv)
             return rv;
     }
 
 #ifdef _WIN32
     char sourcefile[MAXPATHLEN];
-    if (!WideCharToMultiByte(CP_UTF8, 0, mFile, -1, sourcefile, MAXPATHLEN,
-                nullptr, nullptr)) {
+    if (!WideCharToMultiByte(CP_UTF8, 0, mRelPath.get(), -1, sourcefile,
+                MAXPATHLEN, nullptr, nullptr)) {
         LOG(("error converting wchar to utf8: %d", GetLastError()));
         return STRING_CONVERSION_ERROR;
     }
 
-    rv = gArchiveReader.ExtractFile(sourcefile, mFile);
+    rv = gArchiveReader.ExtractFile(sourcefile, mFile.get());
 #else
-    rv = gArchiveReader.ExtractFile(mFile, mFile);
+    rv = gArchiveReader.ExtractFile(mRelPath.get(), mFile.get());
 #endif
     if (!rv) {
         mAdded = true;
@@ -1244,18 +1330,18 @@ AddFile::Execute()
 void
 AddFile::Finish(int status)
 {
-    LOG(("FINISH ADD " LOG_S, mFile));
+    LOG(("FINISH ADD " LOG_S, mRelPath.get()));
     // When there is an update failure and a file has been added it is removed
     // here since there might not be a backup to replace it.
     if (status && mAdded)
-        NS_tremove(mFile);
-    backup_finish(mFile, status);
+        NS_tremove(mFile.get());
+    backup_finish(mFile.get(), mRelPath.get(), status);
 }
 
 class PatchFile : public Action
 {
 public:
-    PatchFile() : mPatchIndex(-1), buf(nullptr) { }
+    PatchFile() : mPatchFile(nullptr), mPatchIndex(-1), buf(nullptr) { }
 
     virtual ~PatchFile();
 
@@ -1270,17 +1356,29 @@ private:
     static int sPatchIndex;
 
     const NS_tchar *mPatchFile;
-    const NS_tchar *mFile;
+    std::unique_ptr<NS_tchar> mFile;
+    std::unique_ptr<NS_tchar> mFileRelPath;
     int mPatchIndex;
     MBSPatchHeader header;
     unsigned char *buf;
     NS_tchar spath[MAXPATHLEN];
+    AutoFile mPatchStream;
 };
 
 int PatchFile::sPatchIndex = 0;
 
 PatchFile::~PatchFile()
 {
+    // Make sure mPatchStream gets unlocked on Windows; the system will do that,
+    // but not until some indeterminate future time, and we want determinism.
+    // Normally this happens at the end of Execute, when we close the stream;
+    // this call is here in case Execute errors out.
+#ifdef _WIN32
+    if (mPatchStream) {
+        UnlockFile((HANDLE)_get_osfhandle(fileno(mPatchStream)), 0, 0, -1, -1);
+    }
+#endif
+
     // delete the temporary patch file
     if (spath[0])
         NS_tremove(spath);
@@ -1296,7 +1394,7 @@ PatchFile::LoadSourceFile(FILE* ofile)
     int rv = fstat(fileno((FILE *)ofile), &os);
     if (rv) {
         LOG(("LoadSourceFile: unable to stat destination file: " LOG_S ", " \
-                    "err: %d", mFile, errno));
+                    "err: %d", mFileRelPath.get(), errno));
         return READ_ERROR;
     }
 
@@ -1317,7 +1415,7 @@ PatchFile::LoadSourceFile(FILE* ofile)
         size_t c = fread(rb, 1, count, ofile);
         if (c != count) {
             LOG(("LoadSourceFile: error reading destination file: " LOG_S,
-                        mFile));
+                        mFileRelPath.get()));
             return READ_ERROR;
         }
 
@@ -1353,9 +1451,16 @@ PatchFile::Parse(NS_tchar *line)
     if (!q)
         return PARSE_ERROR;
 
-    mFile = get_valid_path(&line);
-    if (!mFile)
+    NS_tchar* validPath = get_valid_path(&line);
+    if (!validPath)
         return PARSE_ERROR;
+    mFileRelPath = std::unique_ptr<NS_tchar>(new NS_tchar[MAXPATHLEN]);
+    NS_tstrcpy(mFileRelPath.get(), validPath);
+
+    mFile.reset(get_full_path(validPath));
+    if (!mFile) {
+        return PARSE_ERROR;
+    }
 
     return OK;
 }
@@ -1363,7 +1468,7 @@ PatchFile::Parse(NS_tchar *line)
 int
 PatchFile::Prepare()
 {
-    LOG(("PREPARE PATCH " LOG_S, mFile));
+    LOG(("PREPARE PATCH " LOG_S, mFileRelPath.get()));
 
     // extract the patch to a temporary file
     mPatchIndex = sPatchIndex++;
@@ -1373,11 +1478,17 @@ PatchFile::Prepare()
 
     NS_tremove(spath);
 
-    FILE *fp = NS_tfopen(spath, NS_T("wb"));
-    if (!fp)
+    mPatchStream = NS_tfopen(spath, NS_T("wb"));
+    if (!mPatchStream)
         return WRITE_ERROR;
 
 #ifdef _WIN32
+    // Lock the patch file, so it can't be messed with between
+    // when we're done creating it and when we go to apply it.
+    if (!LockFile((HANDLE)_get_osfhandle(fileno(mPatchStream)), 0, 0, -1, -1)) {
+        LOG(("Couldn't lock patch file: %d", GetLastError()));
+        return LOCK_ERROR_PATCH_FILE;
+    }
     char sourcefile[MAXPATHLEN];
     if (!WideCharToMultiByte(CP_UTF8, 0, mPatchFile, -1, sourcefile, MAXPATHLEN,
                 nullptr, nullptr)) {
@@ -1385,43 +1496,41 @@ PatchFile::Prepare()
         return STRING_CONVERSION_ERROR;
     }
 
-    int rv = gArchiveReader.ExtractFileToStream(sourcefile, fp);
+    int rv = gArchiveReader.ExtractFileToStream(sourcefile, mPatchStream);
 #else
-    int rv = gArchiveReader.ExtractFileToStream(mPatchFile, fp);
+    int rv = gArchiveReader.ExtractFileToStream(mPatchFile, mPatchStream);
 #endif
-    fclose(fp);
+
     return rv;
 }
 
 int
 PatchFile::Execute()
 {
-    LOG(("EXECUTE PATCH " LOG_S, mFile));
+    LOG(("EXECUTE PATCH " LOG_S, mFileRelPath.get()));
 
-    AutoFile pfile(NS_tfopen(spath, NS_T("rb")));
-    if (pfile == nullptr)
-        return READ_ERROR;
+    fseek(mPatchStream, 0, SEEK_SET);
 
-    int rv = MBS_ReadHeader(pfile, &header);
+    int rv = MBS_ReadHeader(mPatchStream, &header);
     if (rv)
         return rv;
 
     FILE *origfile = nullptr;
 #ifdef _WIN32
-    if (NS_tstrcmp(mFile, gCallbackRelPath) == 0) {
+    if (NS_tstrcmp(mFileRelPath.get(), gCallbackRelPath) == 0) {
         // Read from the copy of the callback when patching since the callback can't
         // be opened for reading to prevent the application from being launched.
         origfile = NS_tfopen(gCallbackBackupPath, NS_T("rb"));
     } else {
-        origfile = NS_tfopen(mFile, NS_T("rb"));
+        origfile = NS_tfopen(mFile.get(), NS_T("rb"));
     }
 #else
-    origfile = NS_tfopen(mFile, NS_T("rb"));
+    origfile = NS_tfopen(mFile.get(), NS_T("rb"));
 #endif
 
     if (!origfile) {
-        LOG(("unable to open destination file: " LOG_S ", err: %d", mFile,
-                    errno));
+        LOG(("unable to open destination file: " LOG_S ", err: %d",
+                    mFileRelPath.get(), errno));
         return READ_ERROR;
     }
 
@@ -1435,21 +1544,21 @@ PatchFile::Execute()
     // Rename the destination file if it exists before proceeding so it can be
     // used to restore the file to its original state if there is an error.
     struct NS_tstat_t ss;
-    rv = NS_tstat(mFile, &ss);
+    rv = NS_tstat(mFile.get(), &ss);
     if (rv) {
-        LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
-                    errno));
+        LOG(("failed to read file status info: " LOG_S ", err: %d",
+                    mFileRelPath.get(), errno));
         return READ_ERROR;
     }
 
-    rv = backup_create(mFile);
+    rv = backup_create(mFile.get());
     if (rv)
         return rv;
 
 #if defined(HAVE_POSIX_FALLOCATE)
-    AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+    AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode));
     posix_fallocate(fileno((FILE *)ofile), 0, header.dlen);
-#elif defined(WNT)
+#elif defined(_WIN32)
     bool shouldTruncate = true;
     // Creating the file, setting the size, and then closing the file handle
     // lessens fragmentation more than any other method tested. Other methods that
@@ -1458,7 +1567,7 @@ PatchFile::Execute()
     // 2. _get_osfhandle and then setting the size reduced fragmentation though
     //    not completely. There are also reports of _get_osfhandle failing on
     //    mingw.
-    HANDLE hfile = CreateFileW(mFile,
+    HANDLE hfile = CreateFileW(mFile.get(),
             GENERIC_WRITE,
             0,
             nullptr,
@@ -1475,10 +1584,10 @@ PatchFile::Execute()
         CloseHandle(hfile);
     }
 
-    AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"),
+    AutoFile ofile(ensure_open(mFile.get(), shouldTruncate ? NS_T("wb+") : NS_T("rb+"),
                 ss.st_mode));
 #elif defined(MACOSX)
-    AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+    AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode));
     // Modified code from FileUtils.cpp
     fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen};
     // Try to get a continuous chunk of disk space
@@ -1493,11 +1602,12 @@ PatchFile::Execute()
         ftruncate(fileno((FILE *)ofile), header.dlen);
     }
 #else
-    AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+    AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode));
 #endif
 
     if (ofile == nullptr) {
-        LOG(("unable to create new file: " LOG_S ", err: %d", mFile, errno));
+        LOG(("unable to create new file: " LOG_S ", err: %d", mFileRelPath.get(),
+                    errno));
         return WRITE_ERROR_OPEN_PATCH_FILE;
     }
 
@@ -1507,40 +1617,42 @@ PatchFile::Execute()
     }
 #endif
 
-    rv = MBS_ApplyPatch(&header, pfile, buf, ofile);
+    rv = MBS_ApplyPatch(&header, mPatchStream, buf, ofile);
 
     // Go ahead and do a bit of cleanup now to minimize runtime overhead.
-    // Set pfile to nullptr to make AutoFile close the file so it can be deleted
-    // on Windows.
-    pfile = nullptr;
+    // Make sure mPatchStream gets unlocked on Windows; the system will do that,
+    // but not until some indeterminate future time, and we want determinism.
+#ifdef XP_WIN
+    UnlockFile((HANDLE)_get_osfhandle(fileno(mPatchStream)), 0, 0, -1, -1);
+#endif
+    // Set mPatchStream to nullptr to make AutoFile close the file,
+    // so it can be deleted on Windows.
+    mPatchStream = nullptr;
     NS_tremove(spath);
     spath[0] = NS_T('\0');
     free(buf);
     buf = nullptr;
-
     return rv;
 }
 
 void
 PatchFile::Finish(int status)
 {
-    LOG(("FINISH PATCH " LOG_S, mFile));
+    LOG(("FINISH PATCH " LOG_S, mFileRelPath.get()));
 
-    backup_finish(mFile, status);
+    backup_finish(mFile.get(), mFileRelPath.get(), status);
 }
 
 class AddIfFile : public AddFile
 {
 public:
-    AddIfFile() : mTestFile(nullptr) { }
-
     virtual int Parse(NS_tchar *line);
     virtual int Prepare();
     virtual int Execute();
     virtual void Finish(int status);
 
 protected:
-    const NS_tchar *mTestFile;
+    std::unique_ptr<NS_tchar> mTestFile;
 };
 
 int
@@ -1548,7 +1660,7 @@ AddIfFile::Parse(NS_tchar *line)
 {
     // format "<testfile>" "<newfile>"
 
-    mTestFile = get_valid_path(&line);
+    mTestFile.reset(get_full_path(get_valid_path(&line)));
     if (!mTestFile)
         return PARSE_ERROR;
 
@@ -1564,7 +1676,7 @@ int
 AddIfFile::Prepare()
 {
     // If the test file does not exist, then skip this action.
-    if (NS_taccess(mTestFile, F_OK)) {
+    if (NS_taccess(mTestFile.get(), F_OK)) {
         mTestFile = nullptr;
         return OK;
     }
@@ -1593,15 +1705,13 @@ AddIfFile::Finish(int status)
 class AddIfNotFile : public AddFile
 {
 public:
-    AddIfNotFile() : mTestFile(NULL) { }
-
     virtual int Parse(NS_tchar *line);
     virtual int Prepare();
     virtual int Execute();
     virtual void Finish(int status);
 
 protected:
-    const NS_tchar *mTestFile;
+    std::unique_ptr<NS_tchar> mTestFile;
 };
 
 int
@@ -1609,7 +1719,7 @@ AddIfNotFile::Parse(NS_tchar *line)
 {
     // format "<testfile>" "<newfile>"
 
-    mTestFile = get_valid_path(&line);
+    mTestFile.reset(get_full_path(get_valid_path(&line)));
     if (!mTestFile)
         return PARSE_ERROR;
 
@@ -1625,7 +1735,7 @@ int
 AddIfNotFile::Prepare()
 {
     // If the test file exists, then skip this action.
-    if (!NS_taccess(mTestFile, F_OK)) {
+    if (!NS_taccess(mTestFile.get(), F_OK)) {
         mTestFile = NULL;
         return OK;
     }
@@ -1654,15 +1764,13 @@ AddIfNotFile::Finish(int status)
 class PatchIfFile : public PatchFile
 {
 public:
-    PatchIfFile() : mTestFile(nullptr) { }
-
     virtual int Parse(NS_tchar *line);
     virtual int Prepare(); // should check for patch file and for checksum here
     virtual int Execute();
     virtual void Finish(int status);
 
 private:
-    const NS_tchar *mTestFile;
+    std::unique_ptr<NS_tchar> mTestFile;
 };
 
 int
@@ -1670,7 +1778,7 @@ PatchIfFile::Parse(NS_tchar *line)
 {
     // format "<testfile>" "<patchfile>" "<filetopatch>"
 
-    mTestFile = get_valid_path(&line);
+    mTestFile.reset(get_full_path(get_valid_path(&line)));
     if (!mTestFile)
         return PARSE_ERROR;
 
@@ -1686,7 +1794,7 @@ int
 PatchIfFile::Prepare()
 {
     // If the test file does not exist, then skip this action.
-    if (NS_taccess(mTestFile, F_OK)) {
+    if (NS_taccess(mTestFile.get(), F_OK)) {
         mTestFile = nullptr;
         return OK;
     }
@@ -1714,6 +1822,136 @@ PatchIfFile::Finish(int status)
 
 //-----------------------------------------------------------------------------
 
+#ifdef _WIN32
+#include "nsWindowsRestart.cpp"
+#include "nsWindowsHelpers.h"
+#include "uachelper.h"
+#include "pathhash.h"
+
+/**
+ * Launch the post update application (helper.exe). It takes in the path of the
+ * callback application to calculate the path of helper.exe. For service updates
+ * this is called from both the system account and the current user account.
+ *
+ * @param  installationDir The path to the callback application binary.
+ * @param  updateInfoDir   The directory where update info is stored.
+ * @return true if there was no error starting the process.
+ */
+bool
+LaunchWinPostProcess(const WCHAR *installationDir,
+        const WCHAR *updateInfoDir)
+{
+    WCHAR workingDirectory[MAX_PATH + 1] = { L'\0' };
+    wcsncpy(workingDirectory, installationDir, MAX_PATH);
+
+    // Launch helper.exe to perform post processing (e.g. registry and log file
+    // modifications) for the update.
+    WCHAR inifile[MAX_PATH + 1] = { L'\0' };
+    wcsncpy(inifile, installationDir, MAX_PATH);
+    if (!PathAppendSafe(inifile, L"updater.ini")) {
+        return false;
+    }
+
+    WCHAR exefile[MAX_PATH + 1];
+    WCHAR exearg[MAX_PATH + 1];
+    WCHAR exeasync[10];
+    bool async = true;
+    if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", nullptr,
+                exefile, MAX_PATH + 1, inifile)) {
+        return false;
+    }
+
+    if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", nullptr, exearg,
+                MAX_PATH + 1, inifile)) {
+        return false;
+    }
+
+    if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE",
+                exeasync,
+                sizeof(exeasync)/sizeof(exeasync[0]),
+                inifile)) {
+        return false;
+    }
+
+    // Verify that exeFile doesn't contain relative paths
+    if (wcsstr(exefile, L"..") != nullptr) {
+        return false;
+    }
+
+    WCHAR exefullpath[MAX_PATH + 1] = { L'\0' };
+    wcsncpy(exefullpath, installationDir, MAX_PATH);
+    if (!PathAppendSafe(exefullpath, exefile)) {
+        return false;
+    }
+
+#if !defined(TEST_UPDATER) && defined(MOZ_MAINTENANCE_SERVICE)
+    if (sUsingService &&
+            !DoesBinaryMatchAllowedCertificates(installationDir, exefullpath)) {
+        return false;
+    }
+#endif
+
+    WCHAR dlogFile[MAX_PATH + 1];
+    if (!PathGetSiblingFilePath(dlogFile, exefullpath, L"uninstall.update")) {
+        return false;
+    }
+
+    WCHAR slogFile[MAX_PATH + 1] = { L'\0' };
+    wcsncpy(slogFile, updateInfoDir, MAX_PATH);
+    if (!PathAppendSafe(slogFile, L"update.log")) {
+        return false;
+    }
+
+    WCHAR dummyArg[14] = { L'\0' };
+    wcsncpy(dummyArg, L"argv0ignored ", sizeof(dummyArg) / sizeof(dummyArg[0]) - 1);
+
+    size_t len = wcslen(exearg) + wcslen(dummyArg);
+    WCHAR *cmdline = (WCHAR *) malloc((len + 1) * sizeof(WCHAR));
+    if (!cmdline) {
+        return false;
+    }
+
+    wcsncpy(cmdline, dummyArg, len);
+    wcscat(cmdline, exearg);
+
+    if (sUsingService ||
+            !_wcsnicmp(exeasync, L"false", 6) ||
+            !_wcsnicmp(exeasync, L"0", 2)) {
+        async = false;
+    }
+
+    // We want to launch the post update helper app to update the Windows
+    // registry even if there is a failure with removing the uninstall.update
+    // file or copying the update.log file.
+    CopyFileW(slogFile, dlogFile, false);
+
+    STARTUPINFOW si = {sizeof(si), 0};
+    si.lpDesktop = L"";
+    PROCESS_INFORMATION pi = {0};
+
+    bool ok = CreateProcessW(exefullpath,
+            cmdline,
+            nullptr,  // no special security attributes
+            nullptr,  // no special thread attributes
+            false,    // don't inherit filehandles
+            0,        // No special process creation flags
+            nullptr,  // inherit my environment
+            workingDirectory,
+            &si,
+            &pi);
+    free(cmdline);
+    if (ok) {
+        if (!async) {
+            WaitForSingleObject(pi.hProcess, INFINITE);
+        }
+        CloseHandle(pi.hProcess);
+        CloseHandle(pi.hThread);
+    }
+    return ok;
+}
+
+#endif
+
 static void
 LaunchCallbackApp(const NS_tchar *workingDir,
         int argc,
@@ -1734,8 +1972,7 @@ LaunchCallbackApp(const NS_tchar *workingDir,
     (void) argc; (void) usingService; // avoid warnings
     execv(argv[0], argv);
 #elif defined(MACOSX)
-    (void) usingService; // avoid warnings
-    LaunchChild(argc, argv);
+    LaunchChild(argc, (const char**)argv);
 #elif defined(WNT)
     // Do not allow the callback to run when running an update through the
     // service as session 0.  The unelevated updater.exe will do the launching.
@@ -1750,20 +1987,41 @@ LaunchCallbackApp(const NS_tchar *workingDir,
 static bool
 WriteStatusFile(const char* aStatus)
 {
-    NS_tchar filename[MAXPATHLEN];
+    NS_tchar filename[MAXPATHLEN] = {NS_T('\0')};
+#if defined(_WIN32)
+    // The temp file is not removed on failure since there is client code that
+    // will remove it.
+    GetTempFileNameW(gPatchDirPath, L"sta", 0, filename);
+#else
     NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
             NS_T("%s/update.status"), gPatchDirPath);
+#endif
 
     // Make sure that the directory for the update status file exists
     if (ensure_parent_dir(filename))
         return false;
 
-    AutoFile file(NS_tfopen(filename, NS_T("wb+")));
-    if (file == nullptr)
-        return false;
+    // This is scoped to make the AutoFile close the file so it is possible to
+    // move the temp file to the update.status file on Windows.
+    {
+        AutoFile file(NS_tfopen(filename, NS_T("wb+")));
+        if (file == nullptr) {
+            return false;
+        }
 
-    if (fwrite(aStatus, strlen(aStatus), 1, file) != 1)
+        if (fwrite(aStatus, strlen(aStatus), 1, file) != 1) {
+            return false;
+        }
+    }
+
+#if defined(_WIN32)
+    NS_tchar dstfilename[MAXPATHLEN] = {NS_T('\0')};
+    NS_tsnprintf(dstfilename, sizeof(dstfilename)/sizeof(dstfilename[0]),
+            NS_T("%s\\update.status"), gPatchDirPath);
+    if (MoveFileExW(filename, dstfilename, MOVEFILE_REPLACE_EXISTING) == 0) {
         return false;
+    }
+#endif
 
     return true;
 }
@@ -1985,6 +2243,22 @@ ProcessReplaceRequest()
         return rv;
     }
 
+#if !defined(_WIN32) && !defined(MACOSX)
+    // Platforms that have their updates directory in the installation directory
+    // need to have the last-update.log and backup-update.log files moved from the
+    // old installation directory to the new installation directory.
+    NS_tchar tmpLog[MAXPATHLEN];
+    NS_tsnprintf(tmpLog, sizeof(tmpLog)/sizeof(tmpLog[0]),
+            NS_T("%s/updates/last-update.log"), tmpDir);
+    if (!NS_taccess(tmpLog, F_OK)) {
+        NS_tchar destLog[MAXPATHLEN];
+        NS_tsnprintf(destLog, sizeof(destLog)/sizeof(destLog[0]),
+                NS_T("%s/updates/last-update.log"), destDir);
+        NS_tremove(destLog);
+        NS_trename(tmpLog, destLog);
+    }
+#endif
+
     LOG(("Now, remove the tmpDir"));
     rv = ensure_remove_recursive(tmpDir, true);
     if (rv) {
@@ -2164,7 +2438,18 @@ UpdateThreadFunc(void * /*param*/)
         }
     }
 
-    if (sReplaceRequest && rv) {
+    if (rv && (sReplaceRequest || sStagedUpdate)) {
+#ifdef _WIN32
+        // On Windows, the current working directory of the process should be changed
+        // so that it's not locked.
+        if (sStagedUpdate) {
+            NS_tchar sysDir[MAX_PATH + 1] = { L'\0' };
+            if (GetSystemDirectoryW(sysDir, MAX_PATH + 1)) {
+                NS_tchdir(sysDir);
+            }
+        }
+#endif
+        ensure_remove_recursive(gWorkingDirPath);
         // When attempting to replace the application, we should fall back
         // to non-staged updates in case of a failure.  We do this by
         // setting the status to pending, exiting the updater, and
@@ -2172,8 +2457,11 @@ UpdateThreadFunc(void * /*param*/)
         // startup path will see the pending status, and will start the
         // updater application again in order to apply the update without
         // staging.
-        ensure_remove_recursive(gWorkingDirPath);
-        WriteStatusFile(sUsingService ? "pending-service" : "pending");
+        if (sReplaceRequest) {
+            WriteStatusFile(sUsingService ? "pending-service" : "pending");
+        } else {
+            WriteStatusFile(rv);
+        }
 #ifdef TEST_UPDATER
         // Some tests need to use --test-process-updates again.
         putenv(const_cast<char*>("MOZ_TEST_PROCESS_UPDATES="));
@@ -2200,8 +2488,93 @@ UpdateThreadFunc(void * /*param*/)
     QuitProgressUI();
 }
 
+#ifdef MACOSX
+static void
+ServeElevatedUpdateThreadFunc(void* param)
+{
+    UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param;
+    gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv);
+    if (!gSucceeded) {
+        WriteStatusFile(ELEVATION_CANCELED);
+    }
+    QuitProgressUI();
+}
+
+void freeArguments(int argc, char** argv)
+{
+    for (int i = 0; i < argc; i++) {
+        free(argv[i]);
+    }
+    free(argv);
+}
+#endif
+
+int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv,
+        int callbackIndex
+#ifdef _WIN32
+        , const WCHAR* elevatedLockFilePath
+        , HANDLE updateLockFileHandle
+#elif MACOSX
+        , bool isElevated
+#endif
+        )
+{
+    if (argc > callbackIndex) {
+#if defined(_WIN32)
+        if (gSucceeded) {
+            if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
+                fprintf(stderr, "The post update process was not launched");
+            }
+
+            // The service update will only be executed if it is already installed.
+            // For first time installs of the service, the install will happen from
+            // the PostUpdate process. We do the service update process here
+            // because it's possible we are updating with updater.exe without the
+            // service if the service failed to apply the update. We want to update
+            // the service to a newer version in that case. If we are not running
+            // through the service, then MOZ_USING_SERVICE will not exist.
+            if (!sUsingService) {
+                StartServiceUpdate(gInstallDirPath);
+            }
+        }
+        EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
+#elif MACOSX
+        if (!isElevated) {
+            if (gSucceeded) {
+                LaunchMacPostProcess(gInstallDirPath);
+            }
+#endif
+
+            LaunchCallbackApp(argv[5],
+                    argc - callbackIndex,
+                    argv + callbackIndex,
+                    sUsingService);
+#ifdef XP_MACOSX
+        } // if (!isElevated)
+#endif /* XP_MACOSX */
+    }
+    return 0;
+}
+
 int NS_main(int argc, NS_tchar **argv)
 {
+    // The callback is the remaining arguments starting at callbackIndex.
+    // The argument specified by callbackIndex is the callback executable and the
+    // argument prior to callbackIndex is the working directory.
+    const int callbackIndex = 6;
+
+#ifdef MACOSX
+    bool isElevated =
+        strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") != 0;
+    if (isElevated) {
+        if (!ObtainUpdaterArguments(&argc, &argv)) {
+            // Won't actually get here because ObtainUpdaterArguments will terminate
+            // the current process on failure.
+            return 1;
+        }
+    }
+#endif
+
 #if defined(VERIFY_MAR_SIGNATURE) && !defined(_WIN32) && !defined(MACOSX)
     // On Windows and Mac we rely on native APIs to do verifications so we don't
     // need to initialize NSS at all there.
@@ -2215,7 +2588,13 @@ int NS_main(int argc, NS_tchar **argv)
     }
 #endif
 
-    InitProgressUI(&argc, &argv);
+#ifdef MACOSX
+    if (!isElevated) {
+#endif
+        InitProgressUI(&argc, &argv);
+#ifdef MACOSX
+    }
+#endif
 
     // To process an update the updater command line must at a minimum have the
     // directory path containing the updater.mar file to process as the first
@@ -2233,11 +2612,18 @@ int NS_main(int argc, NS_tchar **argv)
     // launched.
     if (argc < 4) {
         fprintf(stderr, "Usage: updater patch-dir install-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n");
+#ifdef MACOSX
+        if (isElevated) {
+            freeArguments(argc, argv);
+            CleanupElevatedMacUpdate(true);
+        }
+#endif
         return 1;
     }
 
     // The directory containing the update information.
     gPatchDirPath = argv[1];
+
     // The directory we're going to update to.
     // We copy this string because we need to remove trailing slashes.  The C++
     // standard says that it's always safe to write to strings pointed to by argv
@@ -2252,8 +2638,7 @@ int NS_main(int argc, NS_tchar **argv)
 #ifdef _WIN32
     bool useService = false;
     bool testOnlyFallbackKeyExists = false;
-    bool noServiceFallback = EnvHasValue("MOZ_NO_SERVICE_FALLBACK");
-    putenv(const_cast<char*>("MOZ_NO_SERVICE_FALLBACK="));
+    bool noServiceFallback = false;
 
     // We never want the service to be used unless we build with
     // the maintenance service.
@@ -2318,34 +2703,42 @@ int NS_main(int argc, NS_tchar **argv)
         *slash = NS_T('\0');
     }
 
+#ifdef MACOSX
+    if (!isElevated && !IsRecursivelyWritable(argv[2])) {
+        // If the app directory isn't recursively writeable, an elevated update is
+        // required.
+        UpdateServerThreadArgs threadArgs;
+        threadArgs.argc = argc;
+        threadArgs.argv = const_cast<const NS_tchar**>(argv);
+
+        Thread t1;
+        if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) {
+            // Show an indeterminate progress bar while an elevated update is in
+            // progress.
+            ShowProgressUI(true);
+        }
+        t1.Join();
+
+        LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex, false);
+        return gSucceeded ? 0 : 1;
+    }
+#endif
+
     if (EnvHasValue("MOZ_OS_UPDATE")) {
         sIsOSUpdate = true;
         putenv(const_cast<char*>("MOZ_OS_UPDATE="));
     }
 
-    if (sReplaceRequest) {
-        // If we're attempting to replace the application, try to append to the
-        // log generated when staging the staged update.
-#ifdef _WIN32
-        NS_tchar* logDir = gPatchDirPath;
-#else
-#ifdef MACOSX
-        NS_tchar* logDir = gPatchDirPath;
-#else
-        NS_tchar logDir[MAXPATHLEN];
-        NS_tsnprintf(logDir, sizeof(logDir)/sizeof(logDir[0]),
-                NS_T("%s/updated/updates"),
-                gInstallDirPath);
-#endif
-#endif
-
-        LogInitAppend(logDir, NS_T("last-update.log"), NS_T("update.log"));
-    } else {
-        LogInit(gPatchDirPath, NS_T("update.log"));
-    }
+    LogInit(gPatchDirPath, NS_T("update.log"));
 
     if (!WriteStatusFile("applying")) {
         LOG(("failed setting status to 'applying'"));
+#ifdef MACOSX
+        if (isElevated) {
+            freeArguments(argc, argv);
+            CleanupElevatedMacUpdate(true);
+        }
+#endif
         return 1;
     }
 
@@ -2360,6 +2753,38 @@ int NS_main(int argc, NS_tchar **argv)
     LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath));
 
 #ifdef _WIN32
+    if (_wcsnicmp(gWorkingDirPath, gInstallDirPath, MAX_PATH) != 0) {
+        if (!sStagedUpdate && !sReplaceRequest) {
+            WriteStatusFile(INVALID_APPLYTO_DIR_ERROR);
+            LOG(("Installation directory and working directory must be the same "
+                        "for non-staged updates. Exiting."));
+            LogFinish();
+            return 1;
+        }
+
+        NS_tchar workingDirParent[MAX_PATH];
+        NS_tsnprintf(workingDirParent,
+                sizeof(workingDirParent) / sizeof(workingDirParent[0]),
+                NS_T("%s"), gWorkingDirPath);
+        if (!PathRemoveFileSpecW(workingDirParent)) {
+            WriteStatusFile(REMOVE_FILE_SPEC_ERROR);
+            LOG(("Error calling PathRemoveFileSpecW: %d", GetLastError()));
+            LogFinish();
+            return 1;
+        }
+
+        if (_wcsnicmp(workingDirParent, gInstallDirPath, MAX_PATH) != 0) {
+            WriteStatusFile(INVALID_APPLYTO_DIR_STAGED_ERROR);
+            LOG(("The apply-to directory must be the same as or "
+                        "a child of the installation directory! Exiting."));
+            LogFinish();
+            return 1;
+        }
+    }
+#endif
+
+
+#ifdef _WIN32
     if (pid > 0) {
         HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid);
         // May return nullptr if the parent process has already gone away.
@@ -2378,25 +2803,11 @@ int NS_main(int argc, NS_tchar **argv)
         waitpid(pid, nullptr, 0);
 #endif
 
-    if (sReplaceRequest) {
-#ifdef _WIN32
-        // On Windows, the current working directory of the process should be changed
-        // so that it's not locked.
-        NS_tchar sysDir[MAX_PATH + 1] = { L'\0' };
-        if (GetSystemDirectoryW(sysDir, MAX_PATH + 1)) {
-            NS_tchdir(sysDir);
-        }
-#endif
-    }
-
-    // The callback is the remaining arguments starting at callbackIndex.
-    // The argument specified by callbackIndex is the callback executable and the
-    // argument prior to callbackIndex is the working directory.
-    const int callbackIndex = 6;
-
 #if defined(_WIN32)
+#ifdef MOZ_MAINTENANCE_SERVICE
     sUsingService = EnvHasValue("MOZ_USING_SERVICE");
     putenv(const_cast<char*>("MOZ_USING_SERVICE="));
+#endif
     // lastFallbackError keeps track of the last error for the service not being
     // used, in case of an error when fallback is not enabled we write the
     // error to the update.status file.
@@ -2541,7 +2952,9 @@ int NS_main(int argc, NS_tchar **argv)
                                 &baseKey) == ERROR_SUCCESS) {
                         RegCloseKey(baseKey);
                     } else {
+#ifdef TEST_UPDATER
                         useService = testOnlyFallbackKeyExists;
+#endif
                         if (!useService) {
                             lastFallbackError = FALLBACKKEY_NOKEY_ERROR;
                         }
@@ -2606,7 +3019,7 @@ int NS_main(int argc, NS_tchar **argv)
                 if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
                     CloseHandle(updateLockFileHandle);
                 }
-                WriteStatusPending(gPatchDirPath);
+                WriteStatusFile("pending");
                 return 0;
             }
 
@@ -2621,8 +3034,7 @@ int NS_main(int argc, NS_tchar **argv)
                 bool updateStatusSucceeded = false;
                 if (IsUpdateStatusSucceeded(updateStatusSucceeded) &&
                         updateStatusSucceeded) {
-                    if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false,
-                                nullptr)) {
+                    if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
                         fprintf(stderr, "The post update process which runs as the user"
                                 " for service update could not be launched.");
                     }
@@ -2673,7 +3085,7 @@ int NS_main(int argc, NS_tchar **argv)
                 // The elevated updater.exe is responsible for writing out the
                 // update.status file.
                 return 0;
-            } else if(useService) {
+            } else if (useService) {
                 // The service command was launched. The service is responsible for
                 // writing out the update.status file.
                 if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
@@ -2700,20 +3112,16 @@ int NS_main(int argc, NS_tchar **argv)
         ensure_remove_recursive(gWorkingDirPath);
     }
     if (!sReplaceRequest) {
-        // Change current directory to the directory where we need to apply the update.
-        if (NS_tchdir(gWorkingDirPath) != 0) {
-            // Try to create the destination directory if it doesn't exist
-            int rv = NS_tmkdir(gWorkingDirPath, 0755);
-            if (rv == OK && errno != EEXIST) {
-                // Try changing the current directory again
-                if (NS_tchdir(gWorkingDirPath) != 0) {
-                    // OK, time to give up!
-                    return 1;
-                }
-            } else {
-                // Failed to create the directory, bail out
-                return 1;
+        // Try to create the destination directory if it doesn't exist
+        int rv = NS_tmkdir(gWorkingDirPath, 0755);
+        if (rv != OK && errno != EEXIST) {
+#ifdef MACOSX
+            if (isElevated) {
+                freeArguments(argc, argv);
+                CleanupElevatedMacUpdate(true);
             }
+#endif
+            return 1;
         }
     }
 
@@ -2839,115 +3247,147 @@ int NS_main(int argc, NS_tchar **argv)
                     sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]),
                     NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]);
             NS_tremove(gCallbackBackupPath);
-            CopyFileW(argv[callbackIndex], gCallbackBackupPath, false);
-
-            // Since the process may be signaled as exited by WaitForSingleObject before
-            // the release of the executable image try to lock the main executable file
-            // multiple times before giving up.  If we end up giving up, we won't
-            // fail the update.
-            const int max_retries = 10;
-            int retries = 1;
-            DWORD lastWriteError = 0;
-            do {
-                // By opening a file handle without FILE_SHARE_READ to the callback
-                // executable, the OS will prevent launching the process while it is
-                // being updated.
-                callbackFile = CreateFileW(targetPath,
-                        DELETE | GENERIC_WRITE,
-                        // allow delete, rename, and write
-                        FILE_SHARE_DELETE | FILE_SHARE_WRITE,
-                        nullptr, OPEN_EXISTING, 0, nullptr);
-                if (callbackFile != INVALID_HANDLE_VALUE)
-                    break;
-
-                lastWriteError = GetLastError();
-                LOG(("NS_main: callback app file open attempt %d failed. " \
-                            "File: " LOG_S ". Last error: %d", retries,
-                            targetPath, lastWriteError));
-
-                Sleep(100);
-            } while (++retries <= max_retries);
-
-            // CreateFileW will fail if the callback executable is already in use.
-            if (callbackFile == INVALID_HANDLE_VALUE) {
-                // Only fail the update if the last error was not a sharing violation.
-                if (lastWriteError != ERROR_SHARING_VIOLATION) {
-                    LOG(("NS_main: callback app file in use, failed to exclusively open " \
-                                "executable file: " LOG_S, argv[callbackIndex]));
-                    LogFinish();
-                    if (lastWriteError == ERROR_ACCESS_DENIED) {
-                        WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
+            if(!CopyFileW(argv[callbackIndex], gCallbackBackupPath, true)) {
+                DWORD copyFileError = GetLastError();
+                LOG(("NS_main: failed to copy callback file " LOG_S
+                            " into place at " LOG_S, argv[callbackIndex], gCallbackBackupPath));
+                LogFinish();
+                if (copyFileError == ERROR_ACCESS_DENIED) {
+                    WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
                     } else {
                         WriteStatusFile(WRITE_ERROR_CALLBACK_APP);
                     }
 
-                    NS_tremove(gCallbackBackupPath);
                     EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
-                    LaunchCallbackApp(argv[5],
+                    LaunchCallbackApp(argv[callbackIndex],
                             argc - callbackIndex,
                             argv + callbackIndex,
                             sUsingService);
                     return 1;
                 }
-                LOG(("NS_main: callback app file in use, continuing without " \
-                            "exclusive access for executable file: " LOG_S,
-                            argv[callbackIndex]));
+
+                // Since the process may be signaled as exited by WaitForSingleObject before
+                // the release of the executable image try to lock the main executable file
+                // multiple times before giving up.  If we end up giving up, we won't
+                // fail the update.
+                const int max_retries = 10;
+                int retries = 1;
+                DWORD lastWriteError = 0;
+                do {
+                    // By opening a file handle wihout FILE_SHARE_READ to the callback
+                    // executable, the OS will prevent launching the process while it is
+                    // being updated.
+                    callbackFile = CreateFileW(targetPath,
+                            DELETE | GENERIC_WRITE,
+                            // allow delete, rename, and write
+                            FILE_SHARE_DELETE | FILE_SHARE_WRITE,
+                            nullptr, OPEN_EXISTING, 0, nullptr);
+                    if (callbackFile != INVALID_HANDLE_VALUE)
+                        break;
+
+                    lastWriteError = GetLastError();
+                    LOG(("NS_main: callback app file open attempt %d failed. " \
+                                "File: " LOG_S ". Last error: %d", retries,
+                                targetPath, lastWriteError));
+
+                    Sleep(100);
+                } while (++retries <= max_retries);
+
+                // CreateFileW will fail if the callback executable is already in use.
+                if (callbackFile == INVALID_HANDLE_VALUE) {
+                    // Only fail the update if the last error was not a sharing violation.
+                    if (lastWriteError != ERROR_SHARING_VIOLATION) {
+                        LOG(("NS_main: callback app file in use, failed to exclusively open " \
+                                    "executable file: " LOG_S, argv[callbackIndex]));
+                        LogFinish();
+                        if (lastWriteError == ERROR_ACCESS_DENIED) {
+                            WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
+                        } else {
+                            WriteStatusFile(WRITE_ERROR_CALLBACK_APP);
+                        }
+
+                        NS_tremove(gCallbackBackupPath);
+                        EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
+                        LaunchCallbackApp(argv[5],
+                                argc - callbackIndex,
+                                argv + callbackIndex,
+                                sUsingService);
+                        return 1;
+                    }
+                    LOG(("NS_main: callback app file in use, continuing without " \
+                                "exclusive access for executable file: " LOG_S,
+                                argv[callbackIndex]));
+                }
             }
         }
-    }
 
-    // DELETE_DIR is not required when staging an update.
-    if (!sStagedUpdate && !sReplaceRequest) {
-        // The directory to move files that are in use to on Windows. This directory
-        // will be deleted after the update is finished or on OS reboot using
-        // MoveFileEx if it contains files that are in use.
-        if (NS_taccess(DELETE_DIR, F_OK)) {
-            NS_tmkdir(DELETE_DIR, 0755);
+        // DELETE_DIR is not required when performing a staged update or replace
+        // request; it can be used during a replace request but then it doesn't
+        // use gDeleteDirPath.
+        if (!sStagedUpdate && !sReplaceRequest) {
+            // The directory to move files that are in use to on Windows. This directory
+            // will be deleted after the update is finished, on OS reboot using
+            // MoveFileEx if it contains files that are in use, or by the post update
+            // process after the update finishes. On Windows when performing a normal
+            // update (e.g. the update is not a staged update and is not a replace
+            // request) gWorkingDirPath is the same as gInstallDirPath and
+            // gWorkingDirPath is used because it is the destination directory.
+            NS_tsnprintf(gDeleteDirPath,
+                    sizeof(gDeleteDirPath) / sizeof(gDeleteDirPath[0]),
+                    NS_T("%s/%s"), gWorkingDirPath, DELETE_DIR);
+
+            if (NS_taccess(gDeleteDirPath, F_OK)) {
+                NS_tmkdir(gDeleteDirPath, 0755);
+            }
         }
-    }
-#endif /* WNT */
+#endif /* XP_WIN */
 
-    // Run update process on a background thread.  ShowProgressUI may return
-    // before QuitProgressUI has been called, so wait for UpdateThreadFunc to
-    // terminate.  Avoid showing the progress UI when staging an update.
-    std::thread updateThread(UpdateThreadFunc, nullptr);
-    if (!sStagedUpdate && !sReplaceRequest)
-    {
-        ShowProgressUI();
-    }
-    updateThread.join();
+        // Run update process on a background thread. ShowProgressUI may return
+        // before QuitProgressUI has been called, so wait for UpdateThreadFunc to
+        // terminate. Avoid showing the progress UI when staging an update, or if this
+        // is an elevated process on OSX.
+        std::thread t(UpdateThreadFunc, nullptr);
+        if (!sStagedUpdate && !sReplaceRequest
+#ifdef XP_MACOSX
+                && !isElevated
+#endif
+           ) {
+            ShowProgressUI();
+        }
+        t.join();
 
-#ifdef _WIN32
-    if (argc > callbackIndex && !sReplaceRequest) {
-        if (callbackFile != INVALID_HANDLE_VALUE) {
-            CloseHandle(callbackFile);
-        }
-        // Remove the copy of the callback executable.
-        NS_tremove(gCallbackBackupPath);
-    }
-
-    if (!sStagedUpdate && !sReplaceRequest && _wrmdir(DELETE_DIR)) {
-        LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
-                    DELETE_DIR, errno));
-        // The directory probably couldn't be removed due to it containing files
-        // that are in use and will be removed on OS reboot. The call to remove the
-        // directory on OS reboot is done after the calls to remove the files so the
-        // files are removed first on OS reboot since the directory must be empty
-        // for the directory removal to be successful. The MoveFileEx call to remove
-        // the directory on OS reboot will fail if the process doesn't have write
-        // access to the HKEY_LOCAL_MACHINE registry key but this is ok since the
-        // installer / uninstaller will delete the directory along with its contents
-        // after an update is applied, on reinstall, and on uninstall.
-        if (MoveFileEx(DELETE_DIR, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
-            LOG(("NS_main: directory will be removed on OS reboot: " LOG_S,
-                        DELETE_DIR));
-        } else {
-            LOG(("NS_main: failed to schedule OS reboot removal of " \
-                        "directory: " LOG_S, DELETE_DIR));
+#ifdef XP_WIN
+        if (argc > callbackIndex && !sReplaceRequest) {
+            if (callbackFile != INVALID_HANDLE_VALUE) {
+                CloseHandle(callbackFile);
+            }
+            // Remove the copy of the callback executable.
+            NS_tremove(gCallbackBackupPath);
+        }
+
+        if (!sStagedUpdate && !sReplaceRequest && _wrmdir(gDeleteDirPath)) {
+            LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
+                        DELETE_DIR, errno));
+            // The directory probably couldn't be removed due to it containing files
+            // that are in use and will be removed on OS reboot. The call to remove the
+            // directory on OS reboot is done after the calls to remove the files so the
+            // files are removed first on OS reboot since the directory must be empty
+            // for the directory removal to be successful. The MoveFileEx call to remove
+            // the directory on OS reboot will fail if the process doesn't have write
+            // access to the HKEY_LOCAL_MACHINE registry key but this is ok since the
+            // installer / uninstaller will delete the directory along with its contents
+            // after an update is applied, on reinstall, and on uninstall.
+            if (MoveFileEx(gDeleteDirPath, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
+                LOG(("NS_main: directory will be removed on OS reboot: " LOG_S,
+                            DELETE_DIR));
+            } else {
+                LOG(("NS_main: failed to schedule OS reboot removal of " \
+                            "directory: " LOG_S, DELETE_DIR));
+            }
         }
-    }
 #endif /* WNT */
 
+
 #ifdef MACOSX
     // When the update is successful remove the precomplete file in the root of
     // the application bundle and move the distribution directory from
@@ -2986,42 +3426,32 @@ int NS_main(int argc, NS_tchar **argv)
             }
         }
     }
+
+    if (isElevated) {
+        SetGroupOwnershipAndPermissions(gInstallDirPath);
+        freeArguments(argc, argv);
+        CleanupElevatedMacUpdate(false);
+    } else if (IsOwnedByGroupAdmin(gInstallDirPath)) {
+        // If the group ownership of the Firefox .app bundle was set to the "admin"
+        // group during a previous elevated update, we need to ensure that all files
+        // in the bundle have group ownership of "admin" as well as write permission
+        // for the group to not break updates in the future.
+        SetGroupOwnershipAndPermissions(gInstallDirPath);
+    }
 #endif /* MACOSX */
 
     LogFinish();
 
-    if (argc > callbackIndex) {
-#if defined(_WIN32)
-        if (gSucceeded) {
-            // The service update will only be executed if it is already installed.
-            // For first time installs of the service, the install will happen from
-            // the PostUpdate process. We do the service update process here
-            // because it's possible we are updating with updater.exe without the
-            // service if the service failed to apply the update. We want to update
-            // the service to a newer version in that case. If we are not running
-            // through the service, then MOZ_USING_SERVICE will not exist.
-            if (!sUsingService) {
-                if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
-                    LOG(("NS_main: The post update process could not be launched."));
-                }
-
-                StartServiceUpdate(gInstallDirPath);
-            }
-        }
-        EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
-#endif /* WNT */
-#ifdef MACOSX
-        if (gSucceeded) {
-            LaunchMacPostProcess(gInstallDirPath);
-        }
-#endif /* MACOSX */
-        LaunchCallbackApp(argv[5],
-                argc - callbackIndex,
-                argv + callbackIndex,
-                sUsingService);
-    }
+    int retVal = LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex
+#ifdef XP_WIN
+            , elevatedLockFilePath
+            , updateLockFileHandle
+#elif XP_MACOSX
+            , isElevated
+#endif
+            );
 
-    return gSucceeded ? 0 : 1;
+    return retVal ? retVal : (gSucceeded ? 0 : 1);
 }
 
 class ActionList
@@ -3151,9 +3581,9 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
 
     NS_tsnprintf(searchspec, sizeof(searchspec)/sizeof(searchspec[0]),
             NS_T("%s*"), dirpath);
-    const NS_tchar *pszSpec = get_full_path(searchspec);
+    std::unique_ptr<const NS_tchar> pszSpec(get_full_path(searchspec));
 
-    hFindFile = FindFirstFileW(pszSpec, &finddata);
+    hFindFile = FindFirstFileW(pszSpec.get(), &finddata);
     if (hFindFile != INVALID_HANDLE_VALUE) {
         do {
             // Don't process the current or parent directory.
@@ -3185,6 +3615,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
                                 quotedpath, rv));
                     return rv;
                 }
+                free(quotedpath);
 
                 list->Append(action);
             }
@@ -3204,6 +3635,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
                             quotedpath, rv));
             else
                 list->Append(action);
+            free(quotedpath);
         }
     }
 
@@ -3214,24 +3646,17 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
 int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
 {
     int rv = OK;
-    NS_tchar searchpath[MAXPATHLEN];
     NS_tchar foundpath[MAXPATHLEN];
     struct {
         dirent dent_buffer;
         char chars[MAXNAMLEN];
     } ent_buf;
     struct dirent* ent;
+    std::unique_ptr<NS_tchar> searchpath(get_full_path(dirpath));
 
-
-    NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
-            dirpath);
-    // Remove the trailing slash so the paths don't contain double slashes. The
-    // existence of the slash has already been checked in DoUpdate.
-    searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
-
-    DIR* dir = opendir(searchpath);
+    DIR* dir = opendir(searchpath.get());
     if (!dir) {
-        LOG(("add_dir_entries error on opendir: " LOG_S ", err: %d", searchpath,
+        LOG(("add_dir_entries error on opendir: " LOG_S ", err: %d", searchpath.get(),
                     errno));
         return UNEXPECTED_FILE_OPERATION_ERROR;
     }
@@ -3242,7 +3667,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
             continue;
 
         NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
-                NS_T("%s%s"), dirpath, ent->d_name);
+                NS_T("%s%s"), searchpath.get(), ent->d_name);
         struct stat64 st_buf;
         int test = stat64(foundpath, &st_buf);
         if (test) {
@@ -3261,7 +3686,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
             }
         } else {
             // Add the file to be removed to the ActionList.
-            NS_tchar *quotedpath = get_quoted_path(foundpath);
+            NS_tchar *quotedpath = get_quoted_path(get_relative_path(foundpath));
             if (!quotedpath) {
                 closedir(dir);
                 return PARSE_ERROR;
@@ -3282,7 +3707,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
     closedir(dir);
 
     // Add the directory to be removed to the ActionList.
-    NS_tchar *quotedpath = get_quoted_path(dirpath);
+    NS_tchar *quotedpath = get_quoted_path(get_relative_path(dirpath));
     if (!quotedpath)
         return PARSE_ERROR;
 
@@ -3306,14 +3731,12 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
     int rv = OK;
     FTS *ftsdir;
     FTSENT *ftsdirEntry;
-    NS_tchar searchpath[MAXPATHLEN];
+    std::unique_ptr<NS_tchar> searchpath(get_full_path(dirpath));
 
-    NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
-            dirpath);
     // Remove the trailing slash so the paths don't contain double slashes. The
     // existence of the slash has already been checked in DoUpdate.
-    searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
-    char* const pathargv[] = {searchpath, nullptr};
+    searchpath.get()[NS_tstrlen(searchpath.get()) - 1] = NS_T('\0');
+    char* const pathargv[] = {searchpath.get(), nullptr};
 
     // FTS_NOCHDIR is used so relative paths from the destination directory are
     // returned.
@@ -3324,7 +3747,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
 
     while ((ftsdirEntry = fts_read(ftsdir)) != nullptr) {
         NS_tchar foundpath[MAXPATHLEN];
-        NS_tchar *quotedpath;
+        NS_tchar *quotedpath = nullptr;
         Action *action = nullptr;
 
         switch (ftsdirEntry->fts_info) {
@@ -3342,13 +3765,14 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
                 // Add the file to be removed to the ActionList.
                 NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
                         NS_T("%s"), ftsdirEntry->fts_accpath);
-                quotedpath = get_quoted_path(foundpath);
+                quotedpath = get_quoted_path(get_relative_path(foundpath));
                 if (!quotedpath) {
                     rv = UPDATER_QUOTED_PATH_MEM_ERROR;
                     break;
                 }
                 action = new RemoveFile();
                 rv = action->Parse(quotedpath);
+                free(quotedpath);
                 if (!rv)
                     list->Append(action);
             break;
@@ -3359,7 +3783,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
                 // Add the directory to be removed to the ActionList.
                 NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
                         NS_T("%s/"), ftsdirEntry->fts_accpath);
-                quotedpath = get_quoted_path(foundpath);
+                quotedpath = get_quoted_path(get_relative_path(foundpath));
                 if (!quotedpath) {
                     rv = UPDATER_QUOTED_PATH_MEM_ERROR;
                     break;
@@ -3367,6 +3791,7 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
 
                 action = new RemoveDir();
                 rv = action->Parse(quotedpath);
+                free(quotedpath);
                 if (!rv)
                     list->Append(action);
             break;
@@ -3438,6 +3863,7 @@ GetManifestContents(const NS_tchar *manifest)
         size_t c = fread(rb, 1, count, mfile);
         if (c != count) {
             LOG(("GetManifestContents: error reading manifest file: " LOG_S, manifest));
+            free(mbuf);
             return nullptr;
         }
 
@@ -3451,8 +3877,10 @@ GetManifestContents(const NS_tchar *manifest)
     return rb;
 #else
     NS_tchar *wrb = (NS_tchar *) malloc((ms.st_size + 1) * sizeof(NS_tchar));
-    if (!wrb)
+    if (!wrb) {
+        free(mbuf);
         return nullptr;
+    }
 
     if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, rb, -1, wrb,
                 ms.st_size + 1)) {
@@ -3474,10 +3902,14 @@ int AddPreCompleteActions(ActionList *list)
     }
 
 #ifdef MACOSX
-    NS_tchar *rb = GetManifestContents(NS_T("Contents/Resources/precomplete"));
+    std::unique_ptr<NS_tchar> manifestPath(get_full_path(
+                NS_T("Contents/Resources/precomplete")));
 #else
-    NS_tchar *rb = GetManifestContents(NS_T("precomplete"));
+    std::unique_ptr<NS_tchar> manifestPath(get_full_path(
+                NS_T("precomplete")));
 #endif
+
+    NS_tchar *rb = GetManifestContents(manifestPath.get());
     if (rb == nullptr) {
         LOG(("AddPreCompleteActions: error getting contents of precomplete " \
                     "manifest"));
commit 171e29306ce02df328fb3b419908bd8a294fb44c
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Sep 8 07:54:56 2016 +0200

    correctly pass the callback executable to the updater
    
    Change-Id: I88e5c00911841282dbacf1685a3bd0ad0ecf05a7

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 94328c4f..92dfe83 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -91,7 +91,7 @@ char** createCommandLine()
     OUString aLibExecDirURL( "$BRAND_BASE_DIR/" );
     rtl::Bootstrap::expandMacros(aLibExecDirURL);
 
-    size_t nArgs = 7;
+    size_t nArgs = 8;
     char** pArgs = new char*[nArgs];
     {
         createStr(pUpdaterName, pArgs, 0);
@@ -115,10 +115,17 @@ char** createCommandLine()
         createStr(pPID, pArgs, 4);
     }
     {
-        OUString aSofficePathURL = aLibExecDirURL + OUString::fromUtf8(pSofficeExeName);
-        OUString aSofficePath = getPathFromURL(aSofficePathURL);
+        OUString aExeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
+        OUString aSofficePath = getPathFromURL(aExeDir);
         createStr(aSofficePath, pArgs, 5);
     }
+    {
+        OUString aSofficeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/" );
+        rtl::Bootstrap::expandMacros(aSofficeDir);
+        OUString aSofficePathURL = aSofficeDir + OUString::fromUtf8(pSofficeExeName);
+        OUString aSofficePath = getPathFromURL(aSofficePathURL);
+        createStr(aSofficePath, pArgs, 6);
+    }
     pArgs[nArgs - 1] = nullptr;
 
     return pArgs;
@@ -167,7 +174,7 @@ void Update()
     {
         printf("execv failed with error %d %s\n",errno,strerror(errno));
     }
-    for (size_t i = 0; i < 6; ++i)
+    for (size_t i = 0; i < 8; ++i)
     {
         delete[] pArgs[i];
     }
commit 47e92de52d7bdf3be1dc5ced6561d9623647a5dc
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Thu Sep 8 07:54:20 2016 +0200

    add the manifest file to the mar file
    
    Change-Id: I3640d11dba5178cdd9bc49a4630f287b1775640e

diff --git a/bin/update/make_full_update.sh b/bin/update/make_full_update.sh
index 138f747..2c0faef 100755
--- a/bin/update/make_full_update.sh
+++ b/bin/update/make_full_update.sh
@@ -48,6 +48,8 @@ updatemanifestv3="$workdir/updatev3.manifest"
 targetfiles="updatev2.manifest updatev3.manifest"
 
 mkdir -p "$workdir"
+echo "updatev2.manifest" >> $workdir/files.txt
+echo "updatev3.manifest" >> $workdir/files.txt
 
 # Generate a list of all files in the target directory.
 pushd "$targetdir"
commit 78b5effec897359de360ade197a906bffbd10175
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Sep 7 05:18:42 2016 +0200

    store the correct version string in the updater and the mar executable
    
    Change-Id: I52ca969b9fa84320614f77bd51b8aac736478c54

diff --git a/onlineupdate/Executable_mar.mk b/onlineupdate/Executable_mar.mk
index 628ca26..e6f18ef 100644
--- a/onlineupdate/Executable_mar.mk
+++ b/onlineupdate/Executable_mar.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_Executable_use_externals,mar,\
 	nss3 \
 ))
 
+
 ifeq ($(OS),WNT)
 $(eval $(call gb_Executable_add_libs,mar,\
     ws2_32.lib \
@@ -33,9 +34,16 @@ endif
 
 ifeq ($(filter WNT MACOSX,$(OS)),)
 $(eval $(call gb_Executable_use_externals,mar,nss3))
-$(eval $(call gb_Executable_add_defs,mar,-DMAR_NSS))
+
+$(eval $(call gb_Executable_add_defs,mar,\
+	-DMAR_NSS \
+))
 endif
 
+$(eval $(call gb_Executable_add_defs,mar,\
+	-DAPP_VERSION=\"$(LIBO_VERSION_MAJOR).$(LIBO_VERSION_MINOR).$(LIBO_VERSION_MICRO).$(LIBO_VERSION_PATCH)\" \
+))
+
 $(eval $(call gb_Executable_add_cobjects,mar,\
 	onlineupdate/source/libmar/sign/nss_secutil \
 	onlineupdate/source/libmar/sign/mar_sign \
diff --git a/onlineupdate/source/libmar/tool/mar.c b/onlineupdate/source/libmar/tool/mar.c
index 33159bd..232e4e0 100644
--- a/onlineupdate/source/libmar/tool/mar.c
+++ b/onlineupdate/source/libmar/tool/mar.c
@@ -19,8 +19,10 @@
 #include <errno.h>
 #endif
 
-#define MOZ_APP_VERSION "5" /* Dummy value; replace or remove in the
-                               future */
+#ifndef APP_VERSION
+#error "Missing APP_VERSION"
+#endif
+
 #define MAR_CHANNEL_ID "LOOnlineUpdater" /* Dummy value; replace or
                                             remove in the future */
 
@@ -37,7 +39,7 @@ int mar_repackage_and_sign(const char *NSSConfigDir,
                            const char * dest);
 
 static void print_version(void) {
-  printf("Version: %s\n", MOZ_APP_VERSION);
+  printf("Version: %s\n", APP_VERSION);
   printf("Default Channel ID: %s\n", MAR_CHANNEL_ID);
 }
 
@@ -126,7 +128,7 @@ int main(int argc, char **argv) {
   char *NSSConfigDir = NULL;
   const char *certNames[MAX_SIGNATURES];
   char *MARChannelID = MAR_CHANNEL_ID;
-  char *productVersion = MOZ_APP_VERSION;
+  char *productVersion = APP_VERSION;
 #ifndef NO_SIGN_VERIFY
   uint32_t k;
 #endif
commit bd57b56720c8770755d6e5888f7e8a5d0d7ab0ac
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Sep 7 05:17:55 2016 +0200

    make sure that the upload command succeeds
    
    Change-Id: I18988f949082763a06d6d44175e977b8c6c37cdd

diff --git a/bin/update/upload_builds.py b/bin/update/upload_builds.py
index 20d683d..e80acb1 100755
--- a/bin/update/upload_builds.py
+++ b/bin/update/upload_builds.py
@@ -20,7 +20,9 @@ def main():
 
     target_url, target_dir = upload_url.split(':')
 
-    subprocess.call(['ssh', target_url, "'mkdir -p %s'"%(target_dir)])
+    command = "ssh %s 'mkdir -p %s'"%(target_url, target_dir)
+    print(command)
+    subprocess.call(command, shell=True)
     for file in os.listdir(update_dir):
         if file.endswith('.mar'):
             subprocess.call(['scp', os.path.join(update_dir, file), upload_url])
commit 6ff43cc2dd72bf9a9060f5cd764b932a12be6fde
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Sep 6 04:50:33 2016 +0200

    reenable the download of the update files
    
    Change-Id: I123298d323253a83719033756ca7e0a83a2d157f

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 202b515..94328c4f 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -488,24 +488,9 @@ void update_checker()
     OUString aDownloadCheckURL = aDownloadCheckBaseURL + "update/1/" + aProductName +
         "/" + aVersion + "/" + aBuildID + "/" + aBuildTarget + "/" + aLocale +
         "/" + aChannel;
-    SAL_DEBUG(aDownloadCheckURL);
     OString aURL = OUStringToOString(aDownloadCheckURL, RTL_TEXTENCODING_UTF8);
 
-#if 1
     std::string response_body = download_content(aURL, false);
-    SAL_DEBUG(response_body);
-    exit(1);
-#else
-    std::string response_body;
-    if(std::ifstream is{"/lo/users/moggi/update.json", std::ios::binary | std::ios::ate})
-    {
-        auto size = is.tellg();
-        std::string str(size, '\0'); // construct string to stream size
-        is.seekg(0);
-        is.read(&str[0], size);
-        response_body = str;
-    }
-#endif
 
     try
     {
commit 1eb41b1986be00d55bd0df7bbc00aff48ec87cfa
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Sep 6 04:50:05 2016 +0200

    use correct syntac for platform string
    
    Change-Id: I525d92fe6df6f2f4884a8d4a1de6e1637fcf8931

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 2f88764..202b515 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -480,7 +480,7 @@ void update_checker()
     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}";
+    OUString aBuildTarget = "${_OS}_${_ARCH}";
     rtl::Bootstrap::expandMacros(aBuildTarget);
     OUString aLocale = "en-US";
     OUString aChannel = officecfg::Office::Update::Update::UpdateChannel::get();
commit f4ed6958823dcf3e0ec35d46d910a0bff16665bd
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Sep 6 04:49:37 2016 +0200

    file size is obviously an integer
    
    Change-Id: I7f816fd17a2c9d79415771763c6814f91827d961

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index a3bb82d..2f88764 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -277,8 +277,7 @@ update_file parse_update_file(const orcus::json::detail::node& rNode)
         throw invalid_update_info();
 
     aUpdateFile.aHash = toOUString(aHashNode.string_value().str());
-    aUpdateFile.nSize = toOUString(aSizeNode.string_value().str()).toUInt32();
-
+    aUpdateFile.nSize = static_cast<sal_uInt32>(aSizeNode.numeric_value());
     return aUpdateFile;
 }
 
commit d1be7bf6c626bfbb1583256226eeb6317b19f92a
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Sep 6 04:48:44 2016 +0200

    move most of the updater settings to ini file
    
    Also finally add the initial version of the upload scripts.
    
    Change-Id: I3ad5bcbeba60f0cf9700e5fe5001a24f162a3244

diff --git a/Makefile.gbuild b/Makefile.gbuild
index 903a7b8..140a6d7 100644
--- a/Makefile.gbuild
+++ b/Makefile.gbuild
@@ -35,8 +35,10 @@ create-update-info:
 	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_CERTIFICATE_NAME)" "$(UPDATE_CERTIFICATE_PATH)" "$(UPDATE_BASE_URL)"
-	MAR=$(INSTDIR)/program/mar $(SRCDIR)/bin/update/create_full_mar_for_languages.py "$(PRODUCTNAME)" "$(WORKDIR)" "$(UPDATE_DIR)" "$(MAR_DIR)/language" "$(MAR_NAME_PREFIX)" "$(UPDATE_CERTIFICATE_NAME)" "$(UPDATE_CERTIFICATE_PATH)" "$(UPDATE_BASE_URL)"
-	$(SRCDIR)/bin/update/create_build_config.py "$(PRODUCTNAME)" "$(VERSION)" "$(BUILDID)" "$(UPDATE_CHANNEL)" "$(PLATFORM)" "$(UPDATE_DIR)"
+	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)"
+	$(SRCDIR)/bin/update/upload_builds.py "$(PRODUCTNAME)" "$(BUILDID)" "$(PLATFORM)" "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
+	$(SRCDIR)/bin/update/upload_build_config.py "$(UPDATE_DIR)" "$(UPDATE_CONFIG)"
 
 # vim: set noet sw=4 ts=4:
diff --git a/bin/update/create_build_config.py b/bin/update/create_build_config.py
index 1342746..8d0cf0e 100755
--- a/bin/update/create_build_config.py
+++ b/bin/update/create_build_config.py
@@ -4,40 +4,39 @@ import json
 import sys
 import os
 
-def update_url(old_url, **kwargs):
-    new_url = old_url
-    for key, val in kwargs.items():
-        new_url = new_url.replace(key, val)
+from config import parse_config
 
-    return new_url
+from tools import replace_variables_in_string
 
 def update_all_url_entries(data, **kwargs):
-    data['complete']['url'] = update_url(data['complete']['url'], **kwargs)
+    data['complete']['url'] = replace_variables_in_string(data['complete']['url'], **kwargs)
     for language in data['languages']:
-        language['complete']['url'] = update_url(language['complete']['url'], **kwargs)
+        language['complete']['url'] = replace_variables_in_string(language['complete']['url'], **kwargs)
 
 def main(argv):
     if len(argv) < 7:
-        print("Usage: create_build_config.py $PRODUCTNAME $VERSION $BUILDID $UPDATECHANNEL $PLATFORM $TARGETDIR")
+        print("Usage: create_build_config.py $PRODUCTNAME $VERSION $BUILDID $PLATFORM $TARGETDIR $UPDATE_CONFIG")
+
+    config = parse_config(argv[6])
 
     data = { 'productName' : argv[1],
             'version' : argv[2],
             'buildNumber' : argv[3],
-            'updateChannel' : argv[4],
-            'platform' : argv[5]
+            'updateChannel' : config.channel,
+            'platform' : argv[4]
             }
 
     extra_data_files = ['complete_info.json', 'complete_lang_info.json']
 
     for extra_file in extra_data_files:
-        extra_file_path = os.path.join(argv[6], extra_file)
+        extra_file_path = os.path.join(argv[5], extra_file)
         with open(extra_file_path, "r") as f:
             extra_data = json.load(f)
             data.update(extra_data)
 
-    update_all_url_entries(data, channel=argv[4], platform=argv[5], buildid=argv[3], version=argv[2])
+    update_all_url_entries(data, channel=config.channel, platform=argv[4], buildid=argv[3], version=argv[2])
 
-    with open(os.path.join(argv[6], "build_config.json"), "w") as f:
+    with open(os.path.join(argv[5], "build_config.json"), "w") as f:
         json.dump(data, f, indent=4)
 
 if __name__ == "__main__":
diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
index 02870b3..2362f2c 100755
--- a/bin/update/create_full_mar.py
+++ b/bin/update/create_full_mar.py
@@ -6,6 +6,7 @@ import subprocess
 import json
 
 from tools import uncompress_file_to_dir, get_file_info
+from config import parse_config
 
 current_dir_path = os.path.dirname(os.path.realpath(__file__))
 
@@ -15,19 +16,19 @@ def make_mar_name(target_dir, filename_prefix):
 
 def main():

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list