1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "updater.hxx"
19 #include <comphelper/windowsStart.hxx>
23 #include <config_folders.h>
24 #include <rtl/bootstrap.hxx>
26 #include <officecfg/Office/Update.hxx>
28 #include <rtl/ustring.hxx>
29 #include <unotools/tempfile.hxx>
30 #include <unotools/configmgr.hxx>
31 #include <osl/file.hxx>
32 #include <rtl/process.h>
34 #include <curl/curl.h>
36 #include <orcus/json_document_tree.hpp>
37 #include <orcus/config.hpp>
38 #include <orcus/pstring.hpp>
39 #include <comphelper/hash.hxx>
41 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <officecfg/Setup.hxx>
49 class error_updater
: public std::exception
54 error_updater(const OString
& rStr
):
59 virtual const char* what() const throw() override
61 return maStr
.getStr();
66 static const char kUserAgent
[] = "LibreOffice UpdateChecker/1.0 (Linux)";
68 static const char kUserAgent
[] = "LibreOffice UpdateChecker/1.0 (unknown platform)";
72 const char* const pUpdaterName
= "updater";
73 const char* const pSofficeExeName
= "soffice";
75 const char* pUpdaterName
= "updater.exe";
76 const char* pSofficeExeName
= "soffice.exe";
78 #error "Need implementation"
81 OUString
normalizePath(const OUString
& rPath
)
83 OUString aPath
= rPath
.replaceAll("//", "/");
86 if (aPath
.endsWith("/"))
88 aPath
= aPath
.copy(0, aPath
.getLength() - 1);
91 while (aPath
.indexOf("/..") != -1)
93 sal_Int32 nIndex
= aPath
.indexOf("/..");
94 sal_Int32 i
= nIndex
- 1;
101 OUString aTempPath
= aPath
;
102 aPath
= aTempPath
.copy(0, i
) + aPath
.copy(nIndex
+ 3);
105 return aPath
.replaceAll("\\", "/");
108 void CopyFileToDir(const OUString
& rTempDirURL
, const OUString
& rFileName
, const OUString
& rOldDir
)
110 OUString aSourceURL
= rOldDir
+ "/" + rFileName
;
111 OUString aDestURL
= rTempDirURL
+ "/" + rFileName
;
113 osl::File::RC eError
= osl::File::copy(aSourceURL
, aDestURL
);
114 if (eError
!= osl::File::E_None
)
116 SAL_WARN("desktop.updater", "could not copy the file to a temp directory: " << rFileName
);
117 throw std::exception();
121 OUString
getPathFromURL(const OUString
& rURL
)
124 osl::FileBase::getSystemPathFromFileURL(rURL
, aPath
);
126 return normalizePath(aPath
);
129 void CopyUpdaterToTempDir(const OUString
& rInstallDirURL
, const OUString
& rTempDirURL
)
131 OUString aUpdaterName
= OUString::fromUtf8(pUpdaterName
);
132 CopyFileToDir(rTempDirURL
, aUpdaterName
, rInstallDirURL
);
137 #define tstrncpy std::strncpy
138 #elif defined(_WIN32)
139 typedef wchar_t CharT
;
140 #define tstrncpy std::wcsncpy
142 #error "Need an implementation"
145 void createStr(const OUString
& rStr
, CharT
** pArgs
, size_t i
)
148 OString aStr
= OUStringToOString(rStr
, RTL_TEXTENCODING_UTF8
);
149 #elif defined(_WIN32)
150 OUString aStr
= rStr
;
152 #error "Need an implementation"
154 CharT
* pStr
= new CharT
[aStr
.getLength() + 1];
155 tstrncpy(pStr
, aStr
.getStr(), aStr
.getLength());
156 pStr
[aStr
.getLength()] = '\0';
160 CharT
** createCommandLine()
162 OUString aInstallDir
= Updater::getInstallationPath();
164 size_t nCommandLineArgs
= rtl_getAppCommandArgCount();
165 size_t nArgs
= 8 + nCommandLineArgs
;
166 CharT
** pArgs
= new CharT
*[nArgs
];
168 OUString aUpdaterName
= OUString::fromUtf8(pUpdaterName
);
169 createStr(aUpdaterName
, pArgs
, 0);
172 // directory with the patch log
173 OUString aPatchDir
= Updater::getPatchDirURL();
174 rtl::Bootstrap::expandMacros(aPatchDir
);
175 OUString aTempDirPath
= getPathFromURL(aPatchDir
);
176 Updater::log("Patch Dir: " + aTempDirPath
);
177 createStr(aTempDirPath
, pArgs
, 1);
180 // the actual update directory
181 Updater::log("Install Dir: " + aInstallDir
);
182 createStr(aInstallDir
, pArgs
, 2);
185 // the temporary updated build
186 Updater::log("Working Dir: " + aInstallDir
);
187 createStr(aInstallDir
, pArgs
, 3);
192 #elif defined(_WIN32)
193 oslProcessInfo aInfo
;
194 aInfo
.Size
= sizeof(oslProcessInfo
);
195 osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER
, &aInfo
);
196 OUString aPID
= OUString::number(aInfo
.Ident
);
198 #error "Need an implementation"
200 createStr(aPID
, pArgs
, 4);
203 OUString aExeDir
= Updater::getExecutableDirURL();
204 OUString aSofficePath
= getPathFromURL(aExeDir
);
205 Updater::log("soffice Path: " + aSofficePath
);
206 createStr(aSofficePath
, pArgs
, 5);
209 // the executable to start after the successful update
210 OUString aExeDir
= Updater::getExecutableDirURL();
211 OUString aSofficePathURL
= aExeDir
+ OUString::fromUtf8(pSofficeExeName
);
212 OUString aSofficePath
= getPathFromURL(aSofficePathURL
);
213 createStr(aSofficePath
, pArgs
, 6);
216 // add the command line arguments from the soffice list
217 for (size_t i
= 0; i
< nCommandLineArgs
; ++i
)
219 OUString aCommandLineArg
;
220 rtl_getAppCommandArg(i
, &aCommandLineArg
.pData
);
221 createStr(aCommandLineArg
, pArgs
, 7 + i
);
224 pArgs
[nArgs
- 1] = nullptr;
238 update_file aUpdateFile
;
244 OUString aFromBuildID
;
245 OUString aSeeAlsoURL
;
248 update_file aUpdateFile
;
249 std::vector
<language_file
> aLanguageFiles
;
252 bool isUserWritable(const OUString
& rFileURL
)
254 osl::FileStatus
aStatus(osl_FileStatus_Mask_Attributes
);
255 osl::DirectoryItem aDirectoryItem
;
257 osl::FileBase::RC eRes
= osl::DirectoryItem::get(rFileURL
, aDirectoryItem
);
258 if (eRes
!= osl::FileBase::E_None
)
260 Updater::log("Could not get the directory item for: " + rFileURL
);
264 osl::FileBase::RC eResult
= aDirectoryItem
.getFileStatus(aStatus
);
265 if (eResult
!= osl::FileBase::E_None
)
267 Updater::log("Could not get the file status for: " + rFileURL
);
271 bool bReadOnly
= (aStatus
.getAttributes() & static_cast<sal_uInt64
>(osl_File_Attribute_ReadOnly
)) != 0;
274 Updater::log("Update location as determined by: " + rFileURL
+ " is read-only.");
285 utl::TempFile
aTempDir(nullptr, true);
286 OUString aTempDirURL
= aTempDir
.GetURL();
287 CopyUpdaterToTempDir(Updater::getExecutableDirURL(), aTempDirURL
);
289 OUString aUpdaterPath
= getPathFromURL(aTempDirURL
+ "/" + OUString::fromUtf8(pUpdaterName
));
291 Updater::log("Calling the updater with parameters: ");
292 CharT
** pArgs
= createCommandLine();
294 bool bSuccess
= true;
295 const char* pUpdaterTestReplace
= std::getenv("LIBO_UPDATER_TEST_REPLACE");
296 if (!pUpdaterTestReplace
)
299 OString aPath
= OUStringToOString(aUpdaterPath
, RTL_TEXTENCODING_UTF8
);
300 if (execv(aPath
.getStr(), pArgs
))
302 printf("execv failed with error %d %s\n",errno
,strerror(errno
));
305 #elif defined(_WIN32)
306 bSuccess
= WinLaunchChild((wchar_t*)aUpdaterPath
.getStr(), 8, pArgs
);
311 SAL_WARN("desktop.updater", "Updater executable path: " << aUpdaterPath
);
312 for (size_t i
= 0; i
< 8 + rtl_getAppCommandArgCount(); ++i
)
314 SAL_WARN("desktop.updater", pArgs
[i
]);
319 for (size_t i
= 0; i
< 8 + rtl_getAppCommandArgCount(); ++i
)
330 // Callback to get the response data from server.
331 size_t WriteCallback(void *ptr
, size_t size
,
332 size_t nmemb
, void *userp
)
337 std::string
* response
= static_cast<std::string
*>(userp
);
338 size_t real_size
= size
* nmemb
;
339 response
->append(static_cast<char *>(ptr
), real_size
);
345 class invalid_update_info
: public std::exception
349 class invalid_hash
: public std::exception
354 invalid_hash(const OUString
& rExpectedHash
, const OUString
& rReceivedHash
)
356 OUString aMsg
= "Invalid hash found.\nExpected: " + rExpectedHash
+ ";\nReceived: " + rReceivedHash
;
357 maMessage
= OUStringToOString(aMsg
, RTL_TEXTENCODING_UTF8
);
360 const char* what() const noexcept override
362 return maMessage
.getStr();
366 class invalid_size
: public std::exception
371 invalid_size(const size_t nExpectedSize
, const size_t nReceivedSize
)
373 OUString aMsg
= "Invalid file size found.\nExpected: " + OUString::number(nExpectedSize
) + ";\nReceived: " + OUString::number(nReceivedSize
);
374 maMessage
= OUStringToOString(aMsg
, RTL_TEXTENCODING_UTF8
);
377 const char* what() const noexcept override
379 return maMessage
.getStr();
383 OUString
toOUString(const std::string
& rStr
)
385 return OUString::fromUtf8(rStr
.c_str());
388 update_file
parse_update_file(orcus::json::node
& rNode
)
390 if (rNode
.type() != orcus::json::node_t::object
)
392 SAL_WARN("desktop.updater", "invalid update or language file entry");
393 throw invalid_update_info();
396 if (rNode
.child_count() < 4)
398 SAL_WARN("desktop.updater", "invalid update or language file entry");
399 throw invalid_update_info();
402 orcus::json::node aURLNode
= rNode
.child("url");
403 orcus::json::node aHashNode
= rNode
.child("hash");
404 orcus::json::node aHashTypeNode
= rNode
.child("hash_function");
405 orcus::json::node aSizeNode
= rNode
.child("size");
407 if (aHashTypeNode
.string_value() != "sha512")
409 SAL_WARN("desktop.updater", "invalid hash type");
410 throw invalid_update_info();
413 update_file aUpdateFile
;
414 aUpdateFile
.aURL
= toOUString(aURLNode
.string_value().str());
416 if (aUpdateFile
.aURL
.isEmpty())
417 throw invalid_update_info();
419 aUpdateFile
.aHash
= toOUString(aHashNode
.string_value().str());
420 aUpdateFile
.nSize
= static_cast<sal_uInt32
>(aSizeNode
.numeric_value());
424 update_info
parse_response(const std::string
& rResponse
)
426 orcus::json::document_tree aJsonDoc
;
427 orcus::json_config aConfig
;
428 aJsonDoc
.load(rResponse
, aConfig
);
430 auto aDocumentRoot
= aJsonDoc
.get_document_root();
431 if (aDocumentRoot
.type() != orcus::json::node_t::object
)
433 SAL_WARN("desktop.updater", "invalid root entries: " << rResponse
);
434 throw invalid_update_info();
437 auto aRootKeys
= aDocumentRoot
.keys();
438 if (std::find(aRootKeys
.begin(), aRootKeys
.end(), "error") != aRootKeys
.end())
440 throw invalid_update_info();
442 else if (std::find(aRootKeys
.begin(), aRootKeys
.end(), "response") != aRootKeys
.end())
444 update_info aUpdateInfo
;
445 auto aMsgNode
= aDocumentRoot
.child("response");
446 aUpdateInfo
.aMessage
= toOUString(aMsgNode
.string_value().str());
450 orcus::json::node aFromNode
= aDocumentRoot
.child("from");
451 if (aFromNode
.type() != orcus::json::node_t::string
)
453 throw invalid_update_info();
456 orcus::json::node aSeeAlsoNode
= aDocumentRoot
.child("see also");
457 if (aSeeAlsoNode
.type() != orcus::json::node_t::string
)
459 throw invalid_update_info();
462 orcus::json::node aUpdateNode
= aDocumentRoot
.child("update");
463 if (aUpdateNode
.type() != orcus::json::node_t::object
)
465 throw invalid_update_info();
468 orcus::json::node aLanguageNode
= aDocumentRoot
.child("languages");
469 if (aUpdateNode
.type() != orcus::json::node_t::object
)
471 throw invalid_update_info();
474 update_info aUpdateInfo
;
475 aUpdateInfo
.aFromBuildID
= toOUString(aFromNode
.string_value().str());
476 aUpdateInfo
.aSeeAlsoURL
= toOUString(aSeeAlsoNode
.string_value().str());
478 aUpdateInfo
.aUpdateFile
= parse_update_file(aUpdateNode
);
480 std::vector
<orcus::pstring
> aLanguages
= aLanguageNode
.keys();
481 for (auto itr
= aLanguages
.begin(), itrEnd
= aLanguages
.end(); itr
!= itrEnd
; ++itr
)
483 language_file aLanguageFile
;
484 auto aLangEntry
= aLanguageNode
.child(*itr
);
485 aLanguageFile
.aLangCode
= toOUString(itr
->str());
486 aLanguageFile
.aUpdateFile
= parse_update_file(aLangEntry
);
487 aUpdateInfo
.aLanguageFiles
.push_back(aLanguageFile
);
495 comphelper::Hash maHash
;
498 WriteDataFile(SvStream
* pStream
):
499 maHash(comphelper::HashType::SHA512
),
506 auto final_hash
= maHash
.finalize();
507 std::stringstream aStrm
;
508 for (auto& i
: final_hash
)
510 aStrm
<< std::setw(2) << std::setfill('0') << std::hex
<< (int)i
;
513 return toOUString(aStrm
.str());
517 // Callback to get the response data from server to a file.
518 size_t WriteCallbackFile(void *ptr
, size_t size
,
519 size_t nmemb
, void *userp
)
524 WriteDataFile
* response
= static_cast<WriteDataFile
*>(userp
);
525 size_t real_size
= size
* nmemb
;
526 response
->mpStream
->WriteBytes(ptr
, real_size
);
527 response
->maHash
.update(static_cast<const unsigned char*>(ptr
), real_size
);
531 std::string
download_content(const OString
& rURL
, bool bFile
, OUString
& rHash
)
533 Updater::log("Download: " + rURL
);
534 CURL
* curl
= curl_easy_init();
537 return std::string();
539 curl_easy_setopt(curl
, CURLOPT_URL
, rURL
.getStr());
540 curl_easy_setopt(curl
, CURLOPT_USERAGENT
, kUserAgent
);
541 bool bUseProxy
= false;
545 curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str());
546 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
550 char buf
[] = "Expect:";
551 curl_slist
* headerlist
= nullptr;
552 headerlist
= curl_slist_append(headerlist
, buf
);
553 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, headerlist
);
554 curl_easy_setopt(curl
, CURLOPT_FOLLOWLOCATION
, 1); // follow redirects
555 // only allow redirect to http:// and https://
556 curl_easy_setopt(curl
, CURLOPT_REDIR_PROTOCOLS
, CURLPROTO_HTTP
| CURLPROTO_HTTPS
);
558 std::string response_body
;
559 utl::TempFile aTempFile
;
560 WriteDataFile
aFile(aTempFile
.GetStream(StreamMode::WRITE
));
563 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, WriteCallback
);
564 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
,
565 static_cast<void *>(&response_body
));
567 aTempFile
.EnableKillingFile(true);
571 OUString aTempFileURL
= aTempFile
.GetURL();
572 OString aTempFileURLOString
= OUStringToOString(aTempFileURL
, RTL_TEXTENCODING_UTF8
);
573 response_body
.append(aTempFileURLOString
.getStr(), aTempFileURLOString
.getLength());
575 aTempFile
.EnableKillingFile(false);
577 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, WriteCallbackFile
);
578 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
,
579 static_cast<void *>(&aFile
));
582 // Fail if 400+ is returned from the web server.
583 curl_easy_setopt(curl
, CURLOPT_FAILONERROR
, 1);
585 CURLcode cc
= curl_easy_perform(curl
);
587 curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &http_code
);
588 if (http_code
!= 200)
590 SAL_WARN("desktop.updater", "download did not succeed. Error code: " << http_code
);
591 throw error_updater("download did not succeed");
596 SAL_WARN("desktop.updater", "curl error: " << cc
);
597 throw error_updater("curl error");
601 rHash
= aFile
.getHash();
603 return response_body
;
606 void handle_file_error(osl::FileBase::RC eError
, const OUString
& rMsg
)
610 case osl::FileBase::E_None
:
613 SAL_WARN("desktop.updater", "file error code: " << eError
<< ", " << rMsg
);
614 throw error_updater(OUStringToOString(rMsg
, RTL_TEXTENCODING_UTF8
));
618 void download_file(const OUString
& rURL
, size_t nFileSize
, const OUString
& rHash
, const OUString
& aFileName
)
620 Updater::log("Download File: " + rURL
+ "; FileName: " + aFileName
);
621 OString aURL
= OUStringToOString(rURL
, RTL_TEXTENCODING_UTF8
);
623 std::string temp_file
= download_content(aURL
, true, aHash
);
624 if (temp_file
.empty())
625 throw error_updater("empty temp file string");
627 OUString aTempFile
= OUString::fromUtf8(temp_file
.c_str());
628 Updater::log("TempFile: " + aTempFile
);
629 osl::File
aDownloadedFile(aTempFile
);
630 osl::FileBase::RC eError
= aDownloadedFile
.open(1);
631 handle_file_error(eError
, "Could not open the download file: " + aTempFile
);
633 sal_uInt64 nSize
= 0;
634 eError
= aDownloadedFile
.getSize(nSize
);
635 handle_file_error(eError
, "Could not get the file size of the downloaded file: " + aTempFile
);
636 if (nSize
!= nFileSize
)
638 SAL_WARN("desktop.updater", "File sizes don't match. File might be corrupted.");
639 throw invalid_size(nFileSize
, nSize
);
644 SAL_WARN("desktop.updater", "File hash don't match. File might be corrupted.");
645 throw invalid_hash(rHash
, aHash
);
648 OUString
aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
649 rtl::Bootstrap::expandMacros(aPatchDirURL
);
650 osl::Directory::create(aPatchDirURL
);
652 OUString aDestFile
= aPatchDirURL
+ aFileName
;
653 Updater::log("Destination File: " + aDestFile
);
654 aDownloadedFile
.close();
655 eError
= osl::File::move(aTempFile
, aDestFile
);
656 handle_file_error(eError
, "Could not move the file from the Temp directory to the user config: TempFile: " + aTempFile
+ "; DestFile: " + aDestFile
);
661 void update_checker()
663 OUString
aBrandBaseDir("${BRAND_BASE_DIR}");
664 rtl::Bootstrap::expandMacros(aBrandBaseDir
);
665 bool bUserWritable
= isUserWritable(aBrandBaseDir
);
668 Updater::log("Can't update as the update location is not user writable");
672 OUString aDownloadCheckBaseURL
= officecfg::Office::Update::Update::URL::get();
673 static const char* pDownloadCheckBaseURLEnv
= std::getenv("LIBO_UPDATER_URL");
674 if (pDownloadCheckBaseURLEnv
)
676 aDownloadCheckBaseURL
= OUString::createFromAscii(pDownloadCheckBaseURLEnv
);
679 OUString aProductName
= utl::ConfigManager::getProductName();
680 OUString aBuildID
= Updater::getBuildID();
682 static const char* pBuildIdEnv
= std::getenv("LIBO_UPDATER_BUILD");
685 aBuildID
= OUString::createFromAscii(pBuildIdEnv
);
688 OUString aBuildTarget
= "${_OS}_${_ARCH}";
689 rtl::Bootstrap::expandMacros(aBuildTarget
);
690 OUString aChannel
= Updater::getUpdateChannel();
691 static const char* pUpdateChannelEnv
= std::getenv("LIBO_UPDATER_CHANNEL");
692 if (pUpdateChannelEnv
)
694 aChannel
= OUString::createFromAscii(pUpdateChannelEnv
);
697 OUString aDownloadCheckURL
= aDownloadCheckBaseURL
+ "update/check/1/" + aProductName
+
698 "/" + aBuildID
+ "/" + aBuildTarget
+ "/" + aChannel
;
699 OString aURL
= OUStringToOString(aDownloadCheckURL
, RTL_TEXTENCODING_UTF8
);
700 Updater::log("Update check: " + aURL
);
705 std::string response_body
= download_content(aURL
, false, aHash
);
706 if (!response_body
.empty())
709 update_info aUpdateInfo
= parse_response(response_body
);
710 if (aUpdateInfo
.aUpdateFile
.aURL
.isEmpty())
712 // No update currently available
713 // add entry to updating.log with the message
714 SAL_WARN("desktop.updater", "Message received from the updater: " << aUpdateInfo
.aMessage
);
715 Updater::log("Server response: " + aUpdateInfo
.aMessage
);
719 css::uno::Sequence
<OUString
> aInstalledLanguages(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
720 std::set
<OUString
> aInstalledLanguageSet(std::begin(aInstalledLanguages
), std::end(aInstalledLanguages
));
721 download_file(aUpdateInfo
.aUpdateFile
.aURL
, aUpdateInfo
.aUpdateFile
.nSize
, aUpdateInfo
.aUpdateFile
.aHash
, "update.mar");
722 for (auto& lang_update
: aUpdateInfo
.aLanguageFiles
)
724 // only download the language packs for installed languages
725 if (aInstalledLanguageSet
.find(lang_update
.aLangCode
) != aInstalledLanguageSet
.end())
727 OUString aFileName
= "update_" + lang_update
.aLangCode
+ ".mar";
728 download_file(lang_update
.aUpdateFile
.aURL
, lang_update
.aUpdateFile
.nSize
, lang_update
.aUpdateFile
.aHash
, aFileName
);
731 OUString aSeeAlsoURL
= aUpdateInfo
.aSeeAlsoURL
;
732 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
733 comphelper::ConfigurationChanges::create());
734 officecfg::Office::Update::Update::SeeAlso::set(aSeeAlsoURL
, batch
);
739 catch (const invalid_update_info
&)
741 SAL_WARN("desktop.updater", "invalid update information");
742 Updater::log(OString("warning: invalid update info"));
744 catch (const error_updater
& e
)
746 SAL_WARN("desktop.updater", "error during the update check: " << e
.what());
747 Updater::log(OString("warning: error by the updater") + e
.what());
749 catch (const invalid_size
& e
)
751 SAL_WARN("desktop.updater", e
.what());
752 Updater::log(OString("warning: invalid size"));
754 catch (const invalid_hash
& e
)
756 SAL_WARN("desktop.updater", e
.what());
757 Updater::log(OString("warning: invalid hash"));
761 SAL_WARN("desktop.updater", "unknown error during the update check");
762 Updater::log(OString("warning: unknown exception"));
766 OUString
Updater::getUpdateInfoLog()
768 OUString
aUpdateInfoURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/updating.log");
769 rtl::Bootstrap::expandMacros(aUpdateInfoURL
);
771 return aUpdateInfoURL
;
774 OUString
Updater::getPatchDirURL()
776 OUString
aPatchDirURL("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/patch/");
777 rtl::Bootstrap::expandMacros(aPatchDirURL
);
782 OUString
Updater::getUpdateFileURL()
784 return getPatchDirURL() + "update.mar";
787 OUString
Updater::getInstallationPath()
789 OUString
aInstallDir( "$BRAND_BASE_DIR/");
790 rtl::Bootstrap::expandMacros(aInstallDir
);
792 return getPathFromURL(aInstallDir
);
795 OUString
Updater::getExecutableDirURL()
797 OUString
aExeDir( "$BRAND_BASE_DIR/" LIBO_BIN_FOLDER
"/" );
798 rtl::Bootstrap::expandMacros(aExeDir
);
803 void Updater::log(const OUString
& rMessage
)
805 SAL_INFO("desktop.updater", rMessage
);
806 OUString aUpdateLog
= getUpdateInfoLog();
807 SvFileStream
aLog(aUpdateLog
, StreamMode::STD_READWRITE
);
808 aLog
.Seek(aLog
.Tell() + aLog
.remainingSize()); // make sure we are at the end
809 aLog
.WriteLine(OUStringToOString(rMessage
, RTL_TEXTENCODING_UTF8
));
812 void Updater::log(const OString
& rMessage
)
814 SAL_INFO("desktop.updater", rMessage
);
815 OUString aUpdateLog
= getUpdateInfoLog();
816 SvFileStream
aLog(aUpdateLog
, StreamMode::STD_READWRITE
);
817 aLog
.Seek(aLog
.Tell() + aLog
.remainingSize()); // make sure we are at the end
818 aLog
.WriteLine(rMessage
);
821 void Updater::log(const char* pMessage
)
823 SAL_INFO("desktop.updater", pMessage
);
824 OUString aUpdateLog
= getUpdateInfoLog();
825 SvFileStream
aLog(aUpdateLog
, StreamMode::STD_READWRITE
);
826 aLog
.Seek(aLog
.Tell() + aLog
.remainingSize()); // make sure we are at the end
827 aLog
.WriteCharPtr(pMessage
);
830 OUString
Updater::getBuildID()
832 OUString
aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}");
833 rtl::Bootstrap::expandMacros(aBuildID
);
838 OUString
Updater::getUpdateChannel()
840 OUString
aUpdateChannel("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":UpdateChannel}");
841 rtl::Bootstrap::expandMacros(aUpdateChannel
);
843 return aUpdateChannel
;
846 void Updater::removeUpdateFiles()
848 Updater::log("Removing: " + getUpdateFileURL());
849 osl::File::remove(getUpdateFileURL());
851 OUString aPatchDirURL
= getPatchDirURL();
852 osl::Directory
aDir(aPatchDirURL
);
855 osl::FileBase::RC eRC
;
858 osl::DirectoryItem aItem
;
859 eRC
= aDir
.getNextItem(aItem
);
860 if (eRC
== osl::FileBase::E_None
)
862 osl::FileStatus
aStatus(osl_FileStatus_Mask_All
);
863 if (aItem
.getFileStatus(aStatus
) != osl::FileBase::E_None
)
866 if (!aStatus
.isRegular())
869 OUString aURL
= aStatus
.getFileURL();
870 if (!aURL
.endsWith(".mar"))
873 Updater::log("Removing. " + aURL
);
874 osl::File::remove(aURL
);
877 while (eRC
== osl::FileBase::E_None
);
880 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */