[Libreoffice-commits] core.git: Branch 'feature/mar-updater' - 23 commits - bin/update desktop/source onlineupdate/Executable_mbsdiff.mk onlineupdate/inc onlineupdate/Module_onlineupdate.mk onlineupdate/source Repository.mk vcl/unx

Markus Mohrhard markus.mohrhard at googlemail.com
Tue Apr 25 18:43:26 UTC 2017


Rebased ref, commits from common ancestor:
commit f722d61953c86f4b773b1b35d6a181950b493079
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Apr 25 20:41:15 2017 +0200

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

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

    add mbsdiff as build executable
    
    Change-Id: I68c9b14937c219ee142386b72047a6995d004f47

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

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

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

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

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

    if the update_dir does not exist continue with the update check

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

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

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

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

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

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

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

    normalize path for updater

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

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

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

    first stab at normalizing updater path
    
    Change-Id: I5ef2253068595c41577330395810b0797eff8cbb

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

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

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

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

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

    ignore SIGPIPE in glx test process
    
    Change-Id: I31977f86290b4fd7e0869af85f5132ae7cd9d5fd

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

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

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

    version entry is no more
    
    Change-Id: I5011deec4a3b00b22d68d5dff594586d74d717ba

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

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

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

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

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

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

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

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

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

    use consistent method names
    
    Change-Id: I19e066b7e4c4ba1fc1b0802e80260a6d9b0d9b9a

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

    follow redirects when downloading update files
    
    Change-Id: Ic6679aa3d150499b354ccb396c136178d662bb67

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

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

diff --git a/desktop/source/app/updater.cxx b/desktop/source/app/updater.cxx
index 0ca03bc9de9e..5b4b5c1ebac3 100644
--- a/desktop/source/app/updater.cxx
+++ b/desktop/source/app/updater.cxx
@@ -38,17 +38,22 @@ class error_updater : public std::exception
 {
 };
 
-static const char kUserAgent[] = "UpdateChecker/1.0 (Linux)";
+#ifdef UNX
+static const char kUserAgent[] = "LibreOffice UpdateChecker/1.0 (Linux)";
+#else
+static const char kUserAgent[] = "LibreOffice UpdateChecker/1.0 (unknown platform)";
+#endif
 
 #ifdef UNX
 const char* pUpdaterName = "updater";
+const char* pSofficeExeName = "soffice";
 #elif defined(WNT)
 const char* pUpdaterName = "updater.exe";
+const char* pSofficeExeName = "soffice.exe";
 #else
 #error "Need implementation"
 #endif
 
-const char* pSofficeExeName = "soffice";
 
 void CopyFileToDir(const OUString& rTempDirURL, const OUString rFileName, const OUString& rOldDir)
 {


More information about the Libreoffice-commits mailing list