diff options
Diffstat (limited to 'onlineupdate/source/update/updater')
35 files changed, 0 insertions, 7634 deletions
diff --git a/onlineupdate/source/update/updater/Makefile.in b/onlineupdate/source/update/updater/Makefile.in deleted file mode 100644 index 57813b36a20c..000000000000 --- a/onlineupdate/source/update/updater/Makefile.in +++ /dev/null @@ -1,28 +0,0 @@ -# vim:set ts=8 sw=8 sts=8 noet: -# 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/. - -# For changes here, also consider ./updater-xpcshell/Makefile.in - -# This is how the xpcshellCertificate.der file is generated, in case we ever -# have to regenerate it. -# ./certutil -L -d modules/libmar/tests/unit/data -n mycert -r > xpcshellCertificate.der -xpcshellCert.h: xpcshellCertificate.der - -ifdef MOZ_WIDGET_GTK -libs:: updater.png - $(NSINSTALL) -D $(DIST)/bin/icons - $(INSTALL) $(IFLAGS1) $^ $(DIST)/bin/icons -endif - -ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) -libs:: - $(NSINSTALL) -D $(DIST)/bin/updater.app - rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/updater.app - sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \ - iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings - $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS - $(NSINSTALL) $(DIST)/bin/updater $(DIST)/bin/updater.app/Contents/MacOS - rm -f $(DIST)/bin/updater -endif diff --git a/onlineupdate/source/update/updater/archivereader.cxx b/onlineupdate/source/update/updater/archivereader.cxx deleted file mode 100644 index d669211437e9..000000000000 --- a/onlineupdate/source/update/updater/archivereader.cxx +++ /dev/null @@ -1,349 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <string.h> -#include <stdlib.h> -#include <fcntl.h> -#include "bzlib.h" -#include "archivereader.h" -#include "errors.h" -#ifdef _WIN32 -#include "updatehelper.h" -#endif - -// These are generated at compile time based on the DER file for the channel -// being used -#ifdef VERIFY_MAR_SIGNATURE -#ifdef TEST_UPDATER -#include "../xpcshellCert.h" -#else -#include "onlineupdate/primaryCert.h" -#include "onlineupdate/secondaryCert.h" -#endif -#endif - -#if defined(_WIN32) -#define UPDATER_NO_STRING_GLUE_STL -#endif -#include "nsVersionComparator.h" -#undef UPDATER_NO_STRING_GLUE_STL - -#if defined(UNIX) -# include <sys/types.h> -#elif defined(_WIN32) -# include <io.h> -#endif - -static int inbuf_size = 262144; -static int outbuf_size = 262144; -static char *inbuf = nullptr; -static char *outbuf = nullptr; - -/** - * Performs a verification on the opened MAR file with the passed in - * certificate name ID and type ID. - * - * @param archive The MAR file to verify the signature on. - * @param certData The certificate data. - * @return OK on success, CERT_VERIFY_ERROR on failure. -*/ -template<uint32_t SIZE> -int -VerifyLoadedCert(MarFile *archive, const uint8_t (&certData)[SIZE]) -{ - (void)archive; - (void)certData; - -#ifdef VERIFY_MAR_SIGNATURE - const uint32_t size = SIZE; - const uint8_t* const data = &certData[0]; - if (mar_verify_signatures(archive, &data, &size, 1)) - { - return CERT_VERIFY_ERROR; - } -#endif - - return OK; -} - -/** - * Performs a verification on the opened MAR file. Both the primary and backup - * keys stored are stored in the current process and at least the primary key - * will be tried. Success will be returned as long as one of the two - * signatures verify. - * - * @return OK on success -*/ -int -ArchiveReader::VerifySignature() -{ - if (!mArchive) - { - return ARCHIVE_NOT_OPEN; - } - -#ifndef VERIFY_MAR_SIGNATURE - return OK; -#else -#ifdef TEST_UPDATER - int rv = VerifyLoadedCert(mArchive, xpcshellCertData); -#else - int rv = VerifyLoadedCert(mArchive, primaryCertData); - if (rv != OK) - { - rv = VerifyLoadedCert(mArchive, secondaryCertData); - } -#endif - return rv; -#endif -} - -/** - * Verifies that the MAR file matches the current product, channel, and version - * - * @param MARChannelID The MAR channel name to use, only updates from MARs - * with a matching MAR channel name will succeed. - * If an empty string is passed, no check will be done - * for the channel name in the product information block. - * If a comma separated list of values is passed then - * one value must match. - * @param appVersion The application version to use, only MARs with an - * application version >= to appVersion will be applied. - * @return OK on success - * COULD_NOT_READ_PRODUCT_INFO_BLOCK if the product info block - * could not be read. - * MARCHANNEL_MISMATCH_ERROR if update-settings.ini's MAR - * channel ID doesn't match the MAR - * file's MAR channel ID. - * VERSION_DOWNGRADE_ERROR if the application version for - * this updater is newer than the - * one in the MAR. - */ -int -ArchiveReader::VerifyProductInformation(const char *MARChannelID, - const char *appVersion) -{ - if (!mArchive) - { - return ARCHIVE_NOT_OPEN; - } - - ProductInformationBlock productInfoBlock; - int rv = mar_read_product_info_block(mArchive, - &productInfoBlock); - if (rv != OK) - { - return COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR; - } - - // Only check the MAR channel name if specified, it should be passed in from - // the update-settings.ini file. - if (MARChannelID && strlen(MARChannelID)) - { - // Check for at least one match in the comma separated list of values. - const char *delimiter = " ,\t"; - // Make a copy of the string in case a read only memory buffer - // was specified. strtok modifies the input buffer. - char channelCopy[512] = { 0 }; - strncpy(channelCopy, MARChannelID, sizeof(channelCopy) - 1); - char *channel = strtok(channelCopy, delimiter); - rv = MAR_CHANNEL_MISMATCH_ERROR; - while (channel) - { - if (!strcmp(channel, productInfoBlock.MARChannelID)) - { - rv = OK; - break; - } - channel = strtok(nullptr, delimiter); - } - } - - if (rv == OK) - { - /* Compare both versions to ensure we don't have a downgrade - -1 if appVersion is older than productInfoBlock.productVersion - 1 if appVersion is newer than productInfoBlock.productVersion - 0 if appVersion is the same as productInfoBlock.productVersion - This even works with strings like: - - 12.0a1 being older than 12.0a2 - - 12.0a2 being older than 12.0b1 - - 12.0a1 being older than 12.0 - - 12.0 being older than 12.1a1 */ - int versionCompareResult = - mozilla::CompareVersions(appVersion, productInfoBlock.productVersion); - if (1 == versionCompareResult) - { - rv = VERSION_DOWNGRADE_ERROR; - } - } - - free((void *)productInfoBlock.MARChannelID); - free((void *)productInfoBlock.productVersion); - return rv; -} - -int -ArchiveReader::Open(const NS_tchar *path) -{ - if (mArchive) - Close(); - - if (!inbuf) - { - inbuf = (char *)malloc(inbuf_size); - if (!inbuf) - { - // Try again with a smaller buffer. - inbuf_size = 1024; - inbuf = (char *)malloc(inbuf_size); - if (!inbuf) - return ARCHIVE_READER_MEM_ERROR; - } - } - - if (!outbuf) - { - outbuf = (char *)malloc(outbuf_size); - if (!outbuf) - { - // Try again with a smaller buffer. - outbuf_size = 1024; - outbuf = (char *)malloc(outbuf_size); - if (!outbuf) - return ARCHIVE_READER_MEM_ERROR; - } - } - -#ifdef _WIN32 - mArchive = mar_wopen(path); -#else - mArchive = mar_open(path); -#endif - if (!mArchive) - return READ_ERROR; - - return OK; -} - -void -ArchiveReader::Close() -{ - if (mArchive) - { - mar_close(mArchive); - mArchive = nullptr; - } - - if (inbuf) - { - free(inbuf); - inbuf = nullptr; - } - - if (outbuf) - { - free(outbuf); - outbuf = nullptr; - } -} - -int -ArchiveReader::ExtractFile(const char *name, const NS_tchar *dest) -{ - const MarItem *item = mar_find_item(mArchive, name); - if (!item) - return READ_ERROR; - -#ifdef _WIN32 - FILE* fp = _wfopen(dest, L"wb+"); -#else - int fd = creat(dest, item->flags); - if (fd == -1) - return WRITE_ERROR; - - FILE *fp = fdopen(fd, "wb"); -#endif - if (!fp) - return WRITE_ERROR; - - int rv = ExtractItemToStream(item, fp); - - fclose(fp); - return rv; -} - -int -ArchiveReader::ExtractFileToStream(const char *name, FILE *fp) -{ - const MarItem *item = mar_find_item(mArchive, name); - if (!item) - return READ_ERROR; - - return ExtractItemToStream(item, fp); -} - -int -ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp) -{ - /* decompress the data chunk by chunk */ - - bz_stream strm; - int offset, inlen, ret = OK; - - memset(&strm, 0, sizeof(strm)); - if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK) - return UNEXPECTED_BZIP_ERROR; - - offset = 0; - for (;;) - { - if (!item->length) - { - ret = UNEXPECTED_MAR_ERROR; - break; - } - - if (offset < (int) item->length && strm.avail_in == 0) - { - inlen = mar_read(mArchive, item, offset, inbuf, inbuf_size); - if (inlen <= 0) - return READ_ERROR; - offset += inlen; - strm.next_in = inbuf; - strm.avail_in = inlen; - } - - strm.next_out = outbuf; - strm.avail_out = outbuf_size; - - ret = BZ2_bzDecompress(&strm); - if (ret != BZ_OK && ret != BZ_STREAM_END) - { - ret = UNEXPECTED_BZIP_ERROR; - break; - } - - int outlen = outbuf_size - strm.avail_out; - if (outlen) - { - if (fwrite(outbuf, outlen, 1, fp) != 1) - { - ret = WRITE_ERROR_EXTRACT; - break; - } - } - - if (ret == BZ_STREAM_END) - { - ret = OK; - break; - } - } - - BZ2_bzDecompressEnd(&strm); - return ret; -} diff --git a/onlineupdate/source/update/updater/archivereader.h b/onlineupdate/source/update/updater/archivereader.h deleted file mode 100644 index 090b787f9cf5..000000000000 --- a/onlineupdate/source/update/updater/archivereader.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef ArchiveReader_h__ -#define ArchiveReader_h__ - -#include <stdio.h> -#include <onlineupdate/mar.h> -#include "types.hxx" - -// This class provides an API to extract files from an update archive. -class ArchiveReader -{ -public: - ArchiveReader() : mArchive(nullptr) {} - ~ArchiveReader() - { - Close(); - } - - int Open(const NS_tchar *path); - int VerifySignature(); - int VerifyProductInformation(const char *MARChannelID, - const char *appVersion); - void Close(); - - int ExtractFile(const char *item, const NS_tchar *destination); - int ExtractFileToStream(const char *item, FILE *fp); - -private: - int ExtractItemToStream(const MarItem *item, FILE *fp); - - MarFile *mArchive; -}; - -#endif // ArchiveReader_h__ diff --git a/onlineupdate/source/update/updater/bspatch.cxx b/onlineupdate/source/update/updater/bspatch.cxx deleted file mode 100644 index 219c4d74cafa..000000000000 --- a/onlineupdate/source/update/updater/bspatch.cxx +++ /dev/null @@ -1,198 +0,0 @@ -/*- - * Copyright 2003,2004 Colin Percival - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Changelog: - * 2005-04-26 - Define the header as a C structure, add a CRC32 checksum to - * the header, and make all the types 32-bit. - * --Benjamin Smedberg <benjamin@smedbergs.us> - */ - -#include "bspatch.h" -#include "errors.h" - -#include <algorithm> -#include <sys/stat.h> -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <string.h> -#include <limits.h> - -#if defined(_WIN32) -# include <io.h> -#else -# include <unistd.h> -#endif - -#ifdef _WIN32 -# include <winsock2.h> -#else -# include <arpa/inet.h> -#endif - -#ifndef SSIZE_MAX -# define SSIZE_MAX LONG_MAX -#endif - -int -MBS_ReadHeader(FILE* file, MBSPatchHeader *header) -{ - size_t s = fread(header, 1, sizeof(MBSPatchHeader), file); - if (s != sizeof(MBSPatchHeader)) - return READ_ERROR; - - header->slen = ntohl(header->slen); - header->scrc32 = ntohl(header->scrc32); - header->dlen = ntohl(header->dlen); - header->cblen = ntohl(header->cblen); - header->difflen = ntohl(header->difflen); - header->extralen = ntohl(header->extralen); - - struct stat hs; - s = fstat(fileno(file), &hs); - if (s) - return READ_ERROR; - - if (memcmp(header->tag, "MBDIFF10", 8) != 0) - return UNEXPECTED_BSPATCH_ERROR; - - if (sizeof(MBSPatchHeader) + - header->cblen + - header->difflen + - header->extralen != uint32_t(hs.st_size)) - return UNEXPECTED_BSPATCH_ERROR; - - return OK; -} - -int -MBS_ApplyPatch(const MBSPatchHeader *header, FILE* patchFile, - unsigned char *fbuffer, FILE* file) -{ - unsigned char *fbufend = fbuffer + header->slen; - - unsigned char *buf = (unsigned char*) malloc(header->cblen + - header->difflen + - header->extralen); - if (!buf) - return BSPATCH_MEM_ERROR; - - int rv = OK; - - size_t r = header->cblen + header->difflen + header->extralen; - unsigned char *wb = buf; - while (r) - { - const size_t count = std::min(r, size_t(SSIZE_MAX)); - size_t c = fread(wb, 1, count, patchFile); - if (c != count) - { - rv = READ_ERROR; - goto end; - } - - r -= c; - wb += c; - } - - { - MBSPatchTriple *ctrlsrc = (MBSPatchTriple*) buf; - unsigned char *diffsrc = buf + header->cblen; - unsigned char *extrasrc = diffsrc + header->difflen; - - MBSPatchTriple *ctrlend = (MBSPatchTriple*) diffsrc; - unsigned char *diffend = extrasrc; - unsigned char *extraend = extrasrc + header->extralen; - - do - { - ctrlsrc->x = ntohl(ctrlsrc->x); - ctrlsrc->y = ntohl(ctrlsrc->y); - ctrlsrc->z = ntohl(ctrlsrc->z); - -#ifdef DEBUG_bsmedberg - printf("Applying block:\n" - " x: %u\n" - " y: %u\n" - " z: %i\n", - ctrlsrc->x, - ctrlsrc->y, - ctrlsrc->z); -#endif - - /* Add x bytes from oldfile to x bytes from the diff block */ - - if (fbuffer + ctrlsrc->x > fbufend || - diffsrc + ctrlsrc->x > diffend) - { - rv = UNEXPECTED_BSPATCH_ERROR; - goto end; - } - for (uint32_t i = 0; i < ctrlsrc->x; ++i) - { - diffsrc[i] += fbuffer[i]; - } - if ((uint32_t) fwrite(diffsrc, 1, ctrlsrc->x, file) != ctrlsrc->x) - { - rv = WRITE_ERROR_PATCH_FILE; - goto end; - } - fbuffer += ctrlsrc->x; - diffsrc += ctrlsrc->x; - - /* Copy y bytes from the extra block */ - - if (extrasrc + ctrlsrc->y > extraend) - { - rv = UNEXPECTED_BSPATCH_ERROR; - goto end; - } - if ((uint32_t) fwrite(extrasrc, 1, ctrlsrc->y, file) != ctrlsrc->y) - { - rv = WRITE_ERROR_PATCH_FILE; - goto end; - } - extrasrc += ctrlsrc->y; - - /* "seek" forwards in oldfile by z bytes */ - - if (fbuffer + ctrlsrc->z > fbufend) - { - rv = UNEXPECTED_BSPATCH_ERROR; - goto end; - } - fbuffer += ctrlsrc->z; - - /* and on to the next control block */ - - ++ctrlsrc; - } - while (ctrlsrc < ctrlend); - } - -end: - free(buf); - return rv; -} diff --git a/onlineupdate/source/update/updater/gen_cert_header.py b/onlineupdate/source/update/updater/gen_cert_header.py deleted file mode 100755 index 3f3798cfb425..000000000000 --- a/onlineupdate/source/update/updater/gen_cert_header.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -import os -import sys -import binascii - -try: - from configparser import ConfigParser -except ImportError: - from ConfigParser import SafeConfigParser as ConfigParser - -def file_byte_generator(filename): - with open(filename, "rb") as f: - block = f.read() - return block - -def eprint(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) - -def create_header(array_name, in_filename): - if sys.version_info >= (3,0): - hexified = ["0x" + binascii.hexlify(bytes([inp])).decode('ascii') for inp in file_byte_generator(in_filename)] - else: - hexified = ["0x" + binascii.hexlify(inp).decode('ascii') for inp in file_byte_generator(in_filename)] - print("const uint8_t " + array_name + "[] = {") - print(", ".join(hexified)) - print("};") - return 0 - -if __name__ == '__main__': - if len(sys.argv) < 3: - eprint('ERROR: usage: gen_cert_header.py array_name update_config_file') - sys.exit(1) - - if not os.path.exists(sys.argv[2]): - eprint('The config file %s does not exist'%(sys.argv[2])) - sys.exit(1) - - config = ConfigParser() - config.read(sys.argv[2]) - sys.exit(create_header(sys.argv[1], config.get('Updater', 'certificate-der'))) diff --git a/onlineupdate/source/update/updater/launchchild_osx.mm b/onlineupdate/source/update/updater/launchchild_osx.mm deleted file mode 100644 index 9e4e08d372fe..000000000000 --- a/onlineupdate/source/update/updater/launchchild_osx.mm +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <Cocoa/Cocoa.h> -#include <CoreServices/CoreServices.h> -#include <crt_externs.h> -#include <stdlib.h> -#include <stdio.h> -#include <spawn.h> -#include "readstrings.h" - -// Prefer the currently running architecture (this is the same as the -// architecture that launched the updater) and fallback to CPU_TYPE_ANY if it -// is no longer available after the update. -static cpu_type_t pref_cpu_types[2] = { -#if defined(__i386__) - CPU_TYPE_X86, -#elif defined(__x86_64__) - CPU_TYPE_X86_64, -#elif defined(__ppc__) - CPU_TYPE_POWERPC, -#endif - CPU_TYPE_ANY }; - -void LaunchChild(int argc, char **argv) -{ - // Initialize spawn attributes. - posix_spawnattr_t spawnattr; - if (posix_spawnattr_init(&spawnattr) != 0) { - printf("Failed to init posix spawn attribute."); - return; - } - - // Set spawn attributes. - size_t attr_count = 2; - size_t attr_ocount = 0; - if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, &attr_ocount) != 0 || - attr_ocount != attr_count) { - printf("Failed to set binary preference on posix spawn attribute."); - posix_spawnattr_destroy(&spawnattr); - return; - } - - // "posix_spawnp" uses null termination for arguments rather than a count. - // Note that we are not duplicating the argument strings themselves. - char** argv_copy = (char**)malloc((argc + 1) * sizeof(char*)); - if (!argv_copy) { - printf("Failed to allocate memory for arguments."); - posix_spawnattr_destroy(&spawnattr); - return; - } - for (int i = 0; i < argc; i++) { - argv_copy[i] = argv[i]; - } - argv_copy[argc] = NULL; - - // Pass along our environment. - char** envp = NULL; - char*** cocoaEnvironment = _NSGetEnviron(); - if (cocoaEnvironment) { - envp = *cocoaEnvironment; - } - - int result = posix_spawnp(NULL, argv_copy[0], NULL, &spawnattr, argv_copy, envp); - - free(argv_copy); - posix_spawnattr_destroy(&spawnattr); - - if (result != 0) { - printf("Process spawn failed with code %d!", result); - } -} - -void -LaunchMacPostProcess(const char* aAppBundle) -{ - // Launch helper to perform post processing for the update; this is the Mac - // analogue of LaunchWinPostProcess (PostUpdateWin). - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSString* iniPath = [NSString stringWithUTF8String:aAppBundle]; - iniPath = - [iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"]; - - NSFileManager* fileManager = [NSFileManager defaultManager]; - if (![fileManager fileExistsAtPath:iniPath]) { - // the file does not exist; there is nothing to run - [pool release]; - return; - } - - int readResult; - char values[2][MAX_TEXT_LEN]; - readResult = ReadStrings([iniPath UTF8String], - "ExeRelPath\0ExeArg\0", - 2, - values, - "PostUpdateMac"); - if (readResult) { - [pool release]; - return; - } - - NSString *exeRelPath = [NSString stringWithUTF8String:values[0]]; - NSString *exeArg = [NSString stringWithUTF8String:values[1]]; - if (!exeArg || !exeRelPath) { - [pool release]; - return; - } - - NSString* exeFullPath = [NSString stringWithUTF8String:aAppBundle]; - exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath]; - - char optVals[1][MAX_TEXT_LEN]; - readResult = ReadStrings([iniPath UTF8String], - "ExeAsync\0", - 1, - optVals, - "PostUpdateMac"); - - NSTask *task = [[NSTask alloc] init]; - [task setLaunchPath:exeFullPath]; - [task setArguments:[NSArray arrayWithObject:exeArg]]; - [task launch]; - if (!readResult) { - NSString *exeAsync = [NSString stringWithUTF8String:optVals[0]]; - if ([exeAsync isEqualToString:@"false"]) { - [task waitUntilExit]; - } - } - // ignore the return value of the task, there's nothing we can do with it - [task release]; - - [pool release]; -} diff --git a/onlineupdate/source/update/updater/loaddlls.cxx b/onlineupdate/source/update/updater/loaddlls.cxx deleted file mode 100644 index 6a0c8a61ee91..000000000000 --- a/onlineupdate/source/update/updater/loaddlls.cxx +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - - -#ifdef _WIN32 -#ifndef UNICODE -#define UNICODE -#endif -#include <windows.h> - -// Delayed load libraries are loaded when the first symbol is used. -// The following ensures that we load the delayed loaded libraries from the -// system directory. -struct AutoLoadSystemDependencies -{ - AutoLoadSystemDependencies() - { - // Remove the current directory from the search path for dynamically loaded - // DLLs as a precaution. This call has no effect for delay load DLLs. - SetDllDirectory(L""); - - HMODULE module = ::GetModuleHandleW(L"kernel32.dll"); - if (module) - { - // SetDefaultDllDirectories is always available on Windows 8 and above. It - // is also available on Windows Vista, Windows Server 2008, and - // Windows 7 when MS KB2533623 has been applied. - decltype(SetDefaultDllDirectories)* setDefaultDllDirectories = - (decltype(SetDefaultDllDirectories)*) GetProcAddress(module, "SetDefaultDllDirectories"); - if (setDefaultDllDirectories) - { - setDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32); - return; - } - } - - // TODO: moggi: do we need all that code? - // When SetDefaultDllDirectories is not available, fallback to preloading - // dlls. The order that these are loaded does not matter since they are - // loaded using the LOAD_WITH_ALTERED_SEARCH_PATH flag. -#ifdef HAVE_64BIT_BUILD - // DLLs for Firefox x64 on Windows 7 (x64). - // Note: dwmapi.dll is preloaded since a crash will try to load it from the - // application's directory. - static LPCWSTR delayDLLs[] = { L"apphelp.dll", - L"cryptbase.dll", - L"cryptsp.dll", - L"dwmapi.dll", - L"mpr.dll", - L"ntmarta.dll", - L"profapi.dll", - L"propsys.dll", - L"sspicli.dll", - L"wsock32.dll" - }; - -#else - // DLLs for Firefox x86 on Windows XP through Windows 7 (x86 and x64). - // Note: dwmapi.dll is preloaded since a crash will try to load it from the - // application's directory. - static LPCWSTR delayDLLs[] = { L"apphelp.dll", - L"crypt32.dll", - L"cryptbase.dll", - L"cryptsp.dll", - L"dwmapi.dll", - L"mpr.dll", - L"msasn1.dll", - L"ntmarta.dll", - L"profapi.dll", - L"propsys.dll", - L"psapi.dll", - L"secur32.dll", - L"sspicli.dll", - L"userenv.dll", - L"uxtheme.dll", - L"ws2_32.dll", - L"ws2help.dll", - L"wsock32.dll" - }; -#endif - - WCHAR systemDirectory[MAX_PATH + 1] = { L'\0' }; - // If GetSystemDirectory fails we accept that we'll load the DLLs from the - // normal search path. - GetSystemDirectoryW(systemDirectory, MAX_PATH + 1); - size_t systemDirLen = wcslen(systemDirectory); - - // Make the system directory path terminate with a slash - if (systemDirectory[systemDirLen - 1] != L'\\' && systemDirLen) - { - systemDirectory[systemDirLen] = L'\\'; - ++systemDirLen; - // No need to re-null terminate - } - - // For each known DLL ensure it is loaded from the system32 directory - for (size_t i = 0; i < sizeof(delayDLLs) / sizeof(delayDLLs[0]); ++i) - { - size_t fileLen = wcslen(delayDLLs[i]); - wcsncpy(systemDirectory + systemDirLen, delayDLLs[i], - MAX_PATH - systemDirLen); - if (systemDirLen + fileLen <= MAX_PATH) - { - systemDirectory[systemDirLen + fileLen] = L'\0'; - } - else - { - systemDirectory[MAX_PATH] = L'\0'; - } - LPCWSTR fullModulePath = systemDirectory; // just for code readability - // LOAD_WITH_ALTERED_SEARCH_PATH makes a dll look in its own directory for - // dependencies and is only available on Win 7 and below. - LoadLibraryExW(fullModulePath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); - } - } -} loadDLLs; -#endif diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Info.plist b/onlineupdate/source/update/updater/macbuild/Contents/Info.plist deleted file mode 100644 index f104b55b9920..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Info.plist +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleExecutable</key> - <string>updater</string> - <key>CFBundleIconFile</key> - <string>updater.icns</string> - <key>CFBundleIdentifier</key> - <string>org.mozilla.updater</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleSignature</key> - <string>????</string> - <key>CFBundleVersion</key> - <string>1.0</string> - <key>NSMainNibFile</key> - <string>MainMenu</string> - <key>NSPrincipalClass</key> - <string>NSApplication</string> - <key>LSMinimumSystemVersion</key> - <string>10.5</string> - <key>LSMinimumSystemVersionByArchitecture</key> - <dict> - <key>i386</key> - <string>10.5.0</string> - <key>x86_64</key> - <string>10.6.0</string> - </dict> -</dict> -</plist> diff --git a/onlineupdate/source/update/updater/macbuild/Contents/PkgInfo b/onlineupdate/source/update/updater/macbuild/Contents/PkgInfo deleted file mode 100644 index bd04210fb49f..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/PkgInfo +++ /dev/null @@ -1 +0,0 @@ -APPL????
\ No newline at end of file diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in deleted file mode 100644 index bca4022e755a..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in +++ /dev/null @@ -1,7 +0,0 @@ -/* 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/. */ - -/* Localized versions of Info.plist keys */ - -CFBundleName = "%APP_NAME% Software Update"; diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib b/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib deleted file mode 100644 index 6cfb50406bcf..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib +++ /dev/null @@ -1,19 +0,0 @@ -{ - IBClasses = ( - { - CLASS = FirstResponder; - LANGUAGE = ObjC; - SUPERCLASS = NSObject; -}, - { - CLASS = UpdaterUI; - LANGUAGE = ObjC; - OUTLETS = { - progressBar = NSProgressIndicator; - progressTextField = NSTextField; - }; - SUPERCLASS = NSObject; -} - ); - IBVersion = 1; -}
\ No newline at end of file diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib b/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib deleted file mode 100644 index 15091783707b..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>IBDocumentLocation</key> - <string>111 162 356 240 0 0 1440 878 </string> - <key>IBEditorPositions</key> - <dict> - <key>29</key> - <string>106 299 84 44 0 0 1440 878 </string> - </dict> - <key>IBFramework Version</key> - <string>489.0</string> - <key>IBOpenObjects</key> - <array> - <integer>21</integer> - <integer>29</integer> - </array> - <key>IBSystem Version</key> - <string>10J567</string> -</dict> -</plist> diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib Binary files differdeleted file mode 100644 index 61ff026009dc..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib +++ /dev/null diff --git a/onlineupdate/source/update/updater/macbuild/Contents/Resources/updater.icns b/onlineupdate/source/update/updater/macbuild/Contents/Resources/updater.icns Binary files differdeleted file mode 100644 index d7499c6692db..000000000000 --- a/onlineupdate/source/update/updater/macbuild/Contents/Resources/updater.icns +++ /dev/null diff --git a/onlineupdate/source/update/updater/progressui-unused/progressui_gonk.cxx b/onlineupdate/source/update/updater/progressui-unused/progressui_gonk.cxx deleted file mode 100644 index 2878aa2f0bb7..000000000000 --- a/onlineupdate/source/update/updater/progressui-unused/progressui_gonk.cxx +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=8 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <assert.h> -#include <stdio.h> - -#include <string> - -#include "android/log.h" - -#include "progressui.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoUpdater" , ## args) - -int InitProgressUI(int *argc, char ***argv) -{ - return 0; -} - -int ShowProgressUI() -{ - LOG("Starting to apply update ...\n"); - return 0; -} - -void QuitProgressUI() -{ - LOG("Finished applying update\n"); -} - -void UpdateProgressUI(float progress) -{ - assert(0.0f <= progress && progress <= 100.0f); - - static const size_t kProgressBarLength = 50; - static size_t sLastNumBars; - size_t numBars = size_t(float(kProgressBarLength) * progress / 100.0f); - if (numBars == sLastNumBars) - { - return; - } - sLastNumBars = numBars; - - size_t numSpaces = kProgressBarLength - numBars; - std::string bars(numBars, '='); - std::string spaces(numSpaces, ' '); - LOG("Progress [ %s%s ]\n", bars.c_str(), spaces.c_str()); -} diff --git a/onlineupdate/source/update/updater/progressui-unused/progressui_osx.mm b/onlineupdate/source/update/updater/progressui-unused/progressui_osx.mm deleted file mode 100644 index 8e3ce01eb836..000000000000 --- a/onlineupdate/source/update/updater/progressui-unused/progressui_osx.mm +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#import <Cocoa/Cocoa.h> -#include <stdio.h> -#include <unistd.h> -#include "progressui.h" -#include "readstrings.h" -#include "errors.h" - -#define TIMER_INTERVAL 0.2 - -static float sProgressVal; // between 0 and 100 -static BOOL sQuit = FALSE; -static StringTable sLabels; -static const char *sUpdatePath; - -@interface UpdaterUI : NSObject -{ - IBOutlet NSProgressIndicator *progressBar; - IBOutlet NSTextField *progressTextField; -} -@end - -@implementation UpdaterUI - --(void)awakeFromNib -{ - NSWindow *w = [progressBar window]; - - [w setTitle:[NSString stringWithUTF8String:sLabels.title]]; - [progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info]]; - - NSRect origTextFrame = [progressTextField frame]; - [progressTextField sizeToFit]; - - int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width; - - if (widthAdjust > 0) { - NSRect f; - f.size.width = w.frame.size.width + widthAdjust; - f.size.height = w.frame.size.height; - [w setFrame:f display:YES]; - } - - [w center]; - - [progressBar setIndeterminate:NO]; - [progressBar setDoubleValue:0.0]; - - [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self - selector:@selector(updateProgressUI:) - userInfo:nil repeats:YES] retain]; - - // Make sure we are on top initially - [NSApp activateIgnoringOtherApps:YES]; -} - -// called when the timer goes off --(void)updateProgressUI:(NSTimer *)aTimer -{ - if (sQuit) { - [aTimer invalidate]; - [aTimer release]; - - // It seems to be necessary to activate and hide ourselves before we stop, - // otherwise the "run" method will not return until the user focuses some - // other app. The activate step is necessary if we are not the active app. - // This is a big hack, but it seems to do the trick. - [NSApp activateIgnoringOtherApps:YES]; - [NSApp hide:self]; - [NSApp stop:self]; - } - - float progress = sProgressVal; - - [progressBar setDoubleValue:(double)progress]; -} - -// leave this as returning a BOOL instead of NSApplicationTerminateReply -// for backward compatibility -- (BOOL)applicationShouldTerminate:(NSApplication *)sender -{ - return sQuit; -} - -@end - -int -InitProgressUI(int *pargc, char ***pargv) -{ - sUpdatePath = (*pargv)[1]; - - return 0; -} - -int -ShowProgressUI() -{ - // Only show the Progress UI if the process is taking a significant amount of - // time where a significant amount of time is defined as .5 seconds after - // ShowProgressUI is called sProgress is less than 70. - usleep(500000); - - if (sQuit || sProgressVal > 70.0f) - return 0; - - char path[PATH_MAX]; - snprintf(path, sizeof(path), "%s/updater.ini", sUpdatePath); - if (ReadStrings(path, &sLabels) != OK) - return -1; - - // Continue the update without showing the Progress UI if any of the supplied - // strings are larger than MAX_TEXT_LEN (Bug 628829). - if (!(strlen(sLabels.title) < MAX_TEXT_LEN - 1 && - strlen(sLabels.info) < MAX_TEXT_LEN - 1)) - return -1; - - [NSApplication sharedApplication]; - [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; - [NSApp run]; - - return 0; -} - -// Called on a background thread -void -QuitProgressUI() -{ - sQuit = TRUE; -} - -// Called on a background thread -void -UpdateProgressUI(float progress) -{ - sProgressVal = progress; // 32-bit writes are atomic -} diff --git a/onlineupdate/source/update/updater/progressui.h b/onlineupdate/source/update/updater/progressui.h deleted file mode 100644 index a3e4913fc32f..000000000000 --- a/onlineupdate/source/update/updater/progressui.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef PROGRESSUI_H__ -#define PROGRESSUI_H__ - -#include "updatedefines.h" -#include "types.hxx" - -#if defined(_WIN32) -#define NS_main wmain -#else -#define NS_main main -#endif - -// Called to perform any initialization of the widget toolkit -int InitProgressUI(int* argc, NS_tchar*** argv); - -#if defined(_WIN32) -// Called on the main thread at startup -int ShowProgressUI(bool indeterminate = false, bool initUIStrings = true); -int InitProgressUIStrings(); -#else -// Called on the main thread at startup -int ShowProgressUI(); -#endif -// May be called from any thread -void QuitProgressUI(); - -// May be called from any thread: progress is a number between 0 and 100 -void UpdateProgressUI(float progress); - -#endif // PROGRESSUI_H__ diff --git a/onlineupdate/source/update/updater/progressui_gtk.cxx b/onlineupdate/source/update/updater/progressui_gtk.cxx deleted file mode 100644 index 961e4cdd92b9..000000000000 --- a/onlineupdate/source/update/updater/progressui_gtk.cxx +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if defined(UNIX) || defined(MACOSX) -#include <stdio.h> -#include <gtk/gtk.h> -#include <unistd.h> -#include "progressui.h" -#include "readstrings.h" -#include "errors.h" -#include <string.h> -#include "progressui_gtk_icon.h" - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -#define TIMER_INTERVAL 100 - -static float sProgressVal; // between 0 and 100 -static gboolean sQuit = FALSE; -static gboolean sEnableUI; -static guint sTimerID; - -static GtkWidget *sWin; -static GtkWidget *sLabel; -static GtkWidget *sProgressBar; - -static const char *sProgramPath; - -static gboolean -UpdateDialog(gpointer /*data*/) -{ - if (sQuit) - { - gtk_widget_hide(sWin); - gtk_main_quit(); - } - - float progress = sProgressVal; - - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sProgressBar), - progress / 100.0); - - return TRUE; -} - -static gboolean -OnDeleteEvent(GtkWidget * /*widget*/, GdkEvent * /*event*/, gpointer /*user_data*/) -{ - return TRUE; -} - -int -InitProgressUI(int *pargc, char ***pargv) -{ - sProgramPath = (*pargv)[0]; - - sEnableUI = gtk_init_check(pargc, pargv); - return 0; -} - -int -ShowProgressUI() -{ - if (!sEnableUI) - return -1; - - // Only show the Progress UI if the process is taking a significant amount of - // time where a significant amount of time is defined as .5 seconds after - // ShowProgressUI is called sProgress is less than 70. - usleep(500000); - - if (sQuit || sProgressVal > 70.0f) - return 0; - - char ini_path[PATH_MAX]; - snprintf(ini_path, sizeof(ini_path), "%s.ini", sProgramPath); - - StringTable strings; - if (ReadStrings(ini_path, &strings) != OK) - { - strcpy(strings.title, "LibreOffice Update"); - strcpy(strings.info, "Please wait while we update your installation."); - } - - sWin = gtk_window_new(GTK_WINDOW_TOPLEVEL); - if (!sWin) - return -1; - - static GdkPixbuf *pixbuf; - - g_signal_connect(G_OBJECT(sWin), "delete_event", - G_CALLBACK(OnDeleteEvent), nullptr); - - gtk_window_set_title(GTK_WINDOW(sWin), strings.title); - gtk_window_set_type_hint(GTK_WINDOW(sWin), GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_position(GTK_WINDOW(sWin), GTK_WIN_POS_CENTER_ALWAYS); - gtk_window_set_resizable(GTK_WINDOW(sWin), FALSE); - gtk_window_set_decorated(GTK_WINDOW(sWin), TRUE); - gtk_window_set_deletable(GTK_WINDOW(sWin),FALSE); - pixbuf = gdk_pixbuf_new_from_xpm_data (icon_data); - gtk_window_set_icon(GTK_WINDOW(sWin), pixbuf); - g_object_unref(pixbuf); - - GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_box_set_homogeneous(GTK_BOX(vbox), true); - sLabel = gtk_label_new(strings.info); - gtk_misc_set_alignment(GTK_MISC(sLabel), 0.0f, 0.0f); - sProgressBar = gtk_progress_bar_new(); - - gtk_box_pack_start(GTK_BOX(vbox), sLabel, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), sProgressBar, TRUE, TRUE, 0); - - sTimerID = g_timeout_add(TIMER_INTERVAL, UpdateDialog, nullptr); - - gtk_container_set_border_width(GTK_CONTAINER(sWin), 10); - gtk_container_add(GTK_CONTAINER(sWin), vbox); - gtk_widget_show_all(sWin); - - gtk_main(); - return 0; -} - -// Called on a background thread -void -QuitProgressUI() -{ - sQuit = TRUE; -} - -// Called on a background thread -void -UpdateProgressUI(float progress) -{ - sProgressVal = progress; // 32-bit writes are atomic -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#endif // defined(UNIX) || defined(MACOSX) diff --git a/onlineupdate/source/update/updater/progressui_gtk_icon.h b/onlineupdate/source/update/updater/progressui_gtk_icon.h deleted file mode 100644 index 6660c071f0b1..000000000000 --- a/onlineupdate/source/update/updater/progressui_gtk_icon.h +++ /dev/null @@ -1,205 +0,0 @@ -/* XPM */ -static const char *icon_data[] = { -/* columns rows colors chars-per-pixel */ -"32 32 167 2 ", -" c #915B05", -". c #955F0C", -"X c #95610D", -"o c #8F6013", -"O c #8C601D", -"+ c #966311", -"@ c #9A6615", -"# c #9A6817", -"$ c #9C6B1D", -"% c #8B652A", -"& c #966B26", -"* c #976D28", -"= c #9C7129", -"- c #8E6D34", -"; c #A17025", -": c #A2752E", -"> c #AB7A2B", -", c #A77A34", -"< c #A97C33", -"1 c #8D7751", -"2 c #8D7A57", -"3 c #8A7658", -"4 c #A17D42", -"5 c #8E7E63", -"6 c #AE823B", -"7 c #B88635", -"8 c #B2853B", -"9 c #BB8A3A", -"0 c #C08B36", -"q c #AA864A", -"w c #AF894D", -"e c #BC8D42", -"r c #AA8B57", -"t c #B38F56", -"y c #B79256", -"u c #968468", -"i c #958A73", -"p c #9B8970", -"a c #938D7D", -"s c #9D927A", -"d c #A3916F", -"f c #AD966D", -"g c #B1996D", -"h c #BF9F6E", -"j c #A89473", -"k c #B59D75", -"l c #BEA375", -"z c #C08F42", -"x c #D29E4B", -"c c #C69C5C", -"v c #DBA44D", -"b c #D5A351", -"n c #DCA651", -"m c #DFAA56", -"M c #D8A75A", -"N c #DCAA5B", -"B c #C79E60", -"V c #C09F6E", -"C c #C8A162", -"Z c #CCA66A", -"A c #DEAE62", -"S c #D6AD6E", -"D c #DEB16A", -"F c #C1A272", -"G c #C6AA7E", -"H c #D3AE73", -"J c #D8AF71", -"K c #DEB676", -"L c #D8B47C", -"P c #E2B266", -"I c #E3B36A", -"U c #E5B974", -"Y c #E3BB7C", -"T c #8B8C85", -"R c #8D8E88", -"E c #918F83", -"W c #8F908C", -"Q c #9A9483", -"! c #92938E", -"~ c #98968B", -"^ c #9E9788", -"/ c #939591", -"( c #969894", -") c #9C9A94", -"_ c #9C9E99", -"` c #A19C94", -"' c #A29E99", -"] c #9FA19C", -"[ c #ADA189", -"{ c #B9A486", -"} c #AEA695", -"| c #A1A29C", -" . c #A9A89F", -".. c #B7AE98", -"X. c #A4A6A2", -"o. c #A6A9A4", -"O. c #AAABA7", -"+. c #ACACA9", -"@. c #AEB1AB", -"#. c #B0B2AE", -"$. c #B3B5B1", -"%. c #B6B8B2", -"&. c #B9BBB7", -"*. c #BBBCBA", -"=. c #C3AD8A", -"-. c #CDB288", -";. c #C9B495", -":. c #D3BC96", -">. c #E3BD84", -",. c #E1BF88", -"<. c #D2BEA0", -"1. c #C8BFB0", -"2. c #BFC1BB", -"3. c #D8C095", -"4. c #E5C087", -"5. c #EAC385", -"6. c #E6C289", -"7. c #E8C288", -"8. c #E4C492", -"9. c #E6C99B", -"0. c #EBCD9E", -"q. c #D4C1A5", -"w. c #D8C5A7", -"e. c #CBC2B1", -"r. c #C1C4BE", -"t. c #D1C7B7", -"y. c #DFCEB4", -"u. c #E7CDA5", -"i. c #EDD0A3", -"p. c #E6D0AF", -"a. c #EED5AC", -"s. c #E6D2B0", -"d. c #EDD6B3", -"f. c #EBD7B9", -"g. c #ECD9BC", -"h. c #F3DBB5", -"j. c #C4C5C3", -"k. c #C6C9C3", -"l. c #C9CCC6", -"z. c #CCCDCA", -"x. c #D4CFC3", -"c. c #CFD0CC", -"v. c #D1D2CF", -"b. c #D3D4D3", -"n. c #D6D8D5", -"m. c #DADAD6", -"M. c #DADBDA", -"N. c #E7D8C0", -"B. c #ECDCC2", -"V. c #DFE1DE", -"C. c #F3E1C3", -"Z. c #F2E4CC", -"A. c #ECE2D4", -"S. c #EEE7DA", -"D. c #F1E5D2", -"F. c #F7E9D6", -"G. c #F0E8DC", -"H. c #E3E3E3", -"J. c #E7E8E7", -"K. c #E8E8E7", -"L. c #ECECEB", -"P. c #F4EFE6", -"I. c #F5F1EB", -"U. c #F3F4F3", -"Y. c #F8F5F1", -"T. c #FAF9F7", -"R. c #FFFFFF", -/* pixels */ -"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.F X ; A.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.< u.H # S.R.R.R.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.T.y.F l R., d.a.Z # G.R.R.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.R.R.R.A.V , + w :., y.< f.Y 8.C # P.R.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.R.R.G : -.N.I.Y.T.t X . f.5.n 4.e # T.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.R.R.$ p.F.Z.Z.D.Y.F ..l s.h.U D 6.# :.R.R.", -"R.R.R.R.R.R.R.R.R.R.R.U.l.* u.d.i.d.B.I.y k 3., C.5.N >.> h R.R.", -"R.R.R.R.R.R.R.R.R.U.%.W ] , 8.0.0.| R T T T T T T ~ Q >.< h R.R.", -"R.R.R.R.R.R.R.R.n.W ] 2.k.q 3.h.a.| v.U.U.L.L.L.L.U.o.9.< V R.R.", -"R.R.R.R.R.R.R.z.R @.j.k.z.q K 6 ) M.R.R.R.R.R.R.R.o.L > F R.R.", -"R.R.R.R.R.R.M.W $.2.k.l.j.r 0.8.6.! b.R.R.R.R.R.R.R.o.p.8 -.R.R.", -"R.R.R.R.R.T.! @.2.k.l.O.W 6 4.I N E j.R.R.R.R.R.$./ T J 9 w.R.R.", -"R.R.R.R.R.*._ 2.r.l.] X.U., Y A v a k.R.R.L.R.R.U.E 0 x 7 w.R.R.", -"R.R.R.R.R.! %.r.k.@.| T.R., Y N v a j.R.R.@.U.R.R.*.r b 7 <.R.R.", -"R.R.R.R.n.! r.k.k.W L.R.R., Y A v f M.R.R.O.&.R.R.H.a M 9 ;.T.R.", -"R.R.R.R.&.X.j.l.$.O.R.R.T., Y P n g M.R.R.o.W R.R.R.R D 9 { L.T.", -"R.R.w + 2 @.l.c. .1 + . q.: >.P m g ! ! / T E L.R.R._ K e j H.R.", -"R.R.6 Z. .%.c.b.' <.a.c =.= Y P m N M M M M s H.R.R.X.>.z u n.T.", -"R.R., Z.} $.v.n.O.=.i.c { * U 7.7.5.7.4.4.4.Q L.R.R.] ,.8 5 n.T.", -"R.R.6 Z...@.n.M.&.[ i.B =.5 . @ @ @ @ @ @ # R T.R.R.! @ o ] V.T.", -"R.R., A.x._ m.V.m.! G.:.;.z.+.' ` ` ` ^ ) W $.R.R.K.T ) $.b.U.R.", -"R.T., L K R m.H.K.#.[ y ;.U.J.H.H.H.H.H.b.W L.R.R.j.+.H.L.U.R.R.", -"R.M.& H A j #.K.L.L.| 1 + # # # # # $ t./ c.R.R.T./ H.R.T.R.R.R.", -"L.O.O S 8.6.W M.U.T.Y.O.) e.g.f.a.w.d ! b.R.R.R.&.+.R.R.R.R.R.R.", -"U.2.% - ( U.T.R.R.M.+.W R T _ *.U.R.R.R.b.( U.R.R.R.R.R.R.", -"R.U.V.n.b.b.b.o._ L.R.R.R.R.R.T.R.R.R.R.R.R.z./ J.R.R.R.R.R.R.R.", -"R.R.R.R.T.R.R.T.j./ c.R.R.R.R.R.R.R.R.R.U.#.( L.R.R.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.R.T.4 ^ ) j.J.T.R.R.U.M.$.! &.T.R.R.R.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.T.M.& H Z g a T R T E i Q L.R.R.R.R.R.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.U.+.O S ,.>.7.>.7.,.6.< 3 H.R.R.R.R.R.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.U.2.% # $ & $ $ $ $ & X p L.R.R.R.R.R.R.R.R.R.R.R.", -"R.R.R.R.R.R.R.R.Y.m.e.1.1.1.1.1.1.e.t.L.R.R.R.R.R.R.R.R.R.R.R.R." -}; diff --git a/onlineupdate/source/update/updater/progressui_null.cxx b/onlineupdate/source/update/updater/progressui_null.cxx deleted file mode 100644 index 66d294a133a0..000000000000 --- a/onlineupdate/source/update/updater/progressui_null.cxx +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(MACOSX) && !defined(UNIX) && !defined(_WIN32) -#include "progressui.h" - -int InitProgressUI(int *argc, char ***argv) -{ - return 0; -} - -int ShowProgressUI() -{ - return 0; -} - -void QuitProgressUI() -{ -} - -void UpdateProgressUI(float progress) -{ -} -#endif // !defined(MACOSX) && !defined(UNIX) && !defined(_WIN32) diff --git a/onlineupdate/source/update/updater/progressui_win.cxx b/onlineupdate/source/update/updater/progressui_win.cxx deleted file mode 100644 index 7ef23cfabfdf..000000000000 --- a/onlineupdate/source/update/updater/progressui_win.cxx +++ /dev/null @@ -1,348 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifdef _WIN32 -#include <stdio.h> -#ifndef UNICODE -#define UNICODE -#endif -#include <windows.h> -#include <commctrl.h> -#include <process.h> -#include <io.h> - -#include "resource.h" -#include "progressui.h" -#include "readstrings.h" -#include "errors.h" - -#define TIMER_ID 1 -#define TIMER_INTERVAL 100 - -#define RESIZE_WINDOW(hwnd, extrax, extray) \ - { \ - RECT windowSize; \ - GetWindowRect(hwnd, &windowSize); \ - SetWindowPos(hwnd, 0, 0, 0, windowSize.right - windowSize.left + extrax, \ - windowSize.bottom - windowSize.top + extray, \ - SWP_NOMOVE | SWP_NOZORDER); \ - } - -#define MOVE_WINDOW(hwnd, dx, dy) \ - { \ - RECT rc; \ - POINT pt; \ - GetWindowRect(hwnd, &rc); \ - pt.x = rc.left; \ - pt.y = rc.top; \ - ScreenToClient(GetParent(hwnd), &pt); \ - SetWindowPos(hwnd, 0, pt.x + dx, pt.y + dy, 0, 0, \ - SWP_NOSIZE | SWP_NOZORDER); \ - } - -static float sProgress; // between 0 and 100 -static BOOL sQuit = FALSE; -static BOOL sIndeterminate = FALSE; -static StringTable sUIStrings; - -static BOOL -GetStringsFile(WCHAR filename[MAX_PATH]) -{ - if (!GetModuleFileNameW(nullptr, filename, MAX_PATH)) - return FALSE; - - WCHAR *dot = wcsrchr(filename, '.'); - if (!dot || wcsicmp(dot + 1, L"exe")) - return FALSE; - - wcscpy(dot + 1, L"ini"); - return TRUE; -} - -static void -UpdateDialog(HWND hDlg) -{ - int pos = int(sProgress + 0.5f); - HWND hWndPro = GetDlgItem(hDlg, IDC_PROGRESS); - SendMessage(hWndPro, PBM_SETPOS, pos, 0); -} - -// The code in this function is from MSDN: -// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp -static void -CenterDialog(HWND hDlg) -{ - RECT rc, rcOwner, rcDlg; - - // Get the owner window and dialog box rectangles. - HWND desktop = GetDesktopWindow(); - - GetWindowRect(desktop, &rcOwner); - GetWindowRect(hDlg, &rcDlg); - CopyRect(&rc, &rcOwner); - - // Offset the owner and dialog box rectangles so that - // right and bottom values represent the width and - // height, and then offset the owner again to discard - // space taken up by the dialog box. - - OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect(&rc, -rc.left, -rc.top); - OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); - - // The new position is the sum of half the remaining - // space and the owner's original position. - - SetWindowPos(hDlg, - HWND_TOP, - rcOwner.left + (rc.right / 2), - rcOwner.top + (rc.bottom / 2), - 0, 0, // ignores size arguments - SWP_NOSIZE); -} - -static void -InitDialog(HWND hDlg) -{ - WCHAR szwTitle[MAX_TEXT_LEN]; - WCHAR szwInfo[MAX_TEXT_LEN]; - - MultiByteToWideChar(CP_UTF8, 0, sUIStrings.title, -1, szwTitle, - sizeof(szwTitle)/sizeof(szwTitle[0])); - MultiByteToWideChar(CP_UTF8, 0, sUIStrings.info, -1, szwInfo, - sizeof(szwInfo)/sizeof(szwInfo[0])); - - SetWindowTextW(hDlg, szwTitle); - SetWindowTextW(GetDlgItem(hDlg, IDC_INFO), szwInfo); - - // Set dialog icon - HICON hIcon = LoadIcon(GetModuleHandle(nullptr), - MAKEINTRESOURCE(IDI_DIALOG)); - if (hIcon) - SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon); - - HWND hWndPro = GetDlgItem(hDlg, IDC_PROGRESS); - SendMessage(hWndPro, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - if (sIndeterminate) - { - LONG_PTR val = GetWindowLongPtr(hWndPro, GWL_STYLE); - SetWindowLongPtr(hWndPro, GWL_STYLE, val|PBS_MARQUEE); - SendMessage(hWndPro,(UINT) PBM_SETMARQUEE,(WPARAM) TRUE,(LPARAM)50 ); - } - - // Resize the dialog to fit all of the text if necessary. - RECT infoSize, textSize; - HWND hWndInfo = GetDlgItem(hDlg, IDC_INFO); - - // Get the control's font for calculating the new size for the control - HDC hDCInfo = GetDC(hWndInfo); - HFONT hInfoFont; - HFONT hOldFont = 0; - hInfoFont = (HFONT)SendMessage(hWndInfo, WM_GETFONT, 0, 0); - - if (hInfoFont) - hOldFont = (HFONT)SelectObject(hDCInfo, hInfoFont); - - // Measure the space needed for the text on a single line. DT_CALCRECT means - // nothing is drawn. - if (DrawText(hDCInfo, szwInfo, -1, &textSize, - DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE)) - { - GetClientRect(hWndInfo, &infoSize); - SIZE extra; - // Calculate the additional space needed for the text by subtracting from - // the rectangle returned by DrawText the existing client rectangle's width - // and height. - extra.cx = (textSize.right - textSize.left) - \ - (infoSize.right - infoSize.left); - extra.cy = (textSize.bottom - textSize.top) - \ - (infoSize.bottom - infoSize.top); - if (extra.cx < 0) - extra.cx = 0; - if (extra.cy < 0) - extra.cy = 0; - if ((extra.cx > 0) || (extra.cy > 0)) - { - RESIZE_WINDOW(hDlg, extra.cx, extra.cy); - RESIZE_WINDOW(hWndInfo, extra.cx, extra.cy); - RESIZE_WINDOW(hWndPro, extra.cx, 0); - MOVE_WINDOW(hWndPro, 0, extra.cy); - } - } - - if (hOldFont) - SelectObject(hDCInfo, hOldFont); - - ReleaseDC(hWndInfo, hDCInfo); - - CenterDialog(hDlg); // make dialog appear in the center of the screen - - SetTimer(hDlg, TIMER_ID, TIMER_INTERVAL, nullptr); -} - -// Message handler for update dialog. -static LRESULT CALLBACK -DialogProc(HWND hDlg, UINT message, WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - switch (message) - { - case WM_INITDIALOG: - InitDialog(hDlg); - return TRUE; - - case WM_TIMER: - if (sQuit) - { - EndDialog(hDlg, 0); - } - else - { - UpdateDialog(hDlg); - } - return TRUE; - - case WM_COMMAND: - return TRUE; - } - return FALSE; -} - -int -InitProgressUI(int* /*argc*/, WCHAR*** /*argv*/) -{ - return 0; -} - -/** - * Initializes the progress UI strings - * - * @return 0 on success, -1 on error -*/ -int -InitProgressUIStrings() -{ - // If we do not have updater.ini, then we should not bother showing UI. - WCHAR filename[MAX_PATH]; - if (!GetStringsFile(filename)) - { - strcpy(sUIStrings.title, "LibreOffice Update"); - strcpy(sUIStrings.info, "Please wait while we update your installation."); - return 0; - } - - if (_waccess(filename, 04)) - { - strcpy(sUIStrings.title, "LibreOffice Update"); - strcpy(sUIStrings.info, "Please wait while we update your installation."); - return 0; - } - - // If the updater.ini doesn't have the required strings, then we should not - // bother showing UI. - if (ReadStrings(filename, &sUIStrings) != OK) - { - strcpy(sUIStrings.title, "LibreOffice Update"); - strcpy(sUIStrings.info, "Please wait while we update your installation."); - } - - return 0; -} - -int -ShowProgressUI(bool indeterminate, bool initUIStrings) -{ - sIndeterminate = indeterminate; - if (!indeterminate) - { - // Only show the Progress UI if the process is taking a significant amount of - // time where a significant amount of time is defined as .5 seconds after - // ShowProgressUI is called sProgress is less than 70. - Sleep(500); - - if (sQuit || sProgress > 70.0f) - return 0; - } - - // Don't load the UI if there's an <exe_name>.Local directory for redirection. - WCHAR appPath[MAX_PATH + 1] = { L'\0' }; - if (!GetModuleFileNameW(nullptr, appPath, MAX_PATH)) - { - return -1; - } - - if (wcslen(appPath) + wcslen(L".Local") >= MAX_PATH) - { - return -1; - } - - wcscat(appPath, L".Local"); - - if (!_waccess(appPath, 04)) - { - return -1; - } - - // Don't load the UI if the strings for the UI are not provided. - if (initUIStrings && InitProgressUIStrings() == -1) - { - return -1; - } - - if (!GetModuleFileNameW(nullptr, appPath, MAX_PATH)) - { - return -1; - } - - // Use an activation context that supports visual styles for the controls. - ACTCTXW actx = {0}; - actx.cbSize = sizeof(ACTCTXW); - actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID; - actx.hModule = GetModuleHandle(NULL); // Use the embedded manifest - // This is needed only for Win XP but doesn't cause a problem with other - // versions of Windows. - actx.lpSource = appPath; - actx.lpResourceName = MAKEINTRESOURCE(IDR_COMCTL32_MANIFEST); - - HANDLE hactx = CreateActCtxW(&actx); - ULONG_PTR actxCookie = NULL; - if (hactx != INVALID_HANDLE_VALUE) - { - // Push the specified activation context to the top of the activation stack. - ActivateActCtx(hactx, &actxCookie); - } - - INITCOMMONCONTROLSEX icc = - { - sizeof(INITCOMMONCONTROLSEX), - ICC_PROGRESS_CLASS - }; - InitCommonControlsEx(&icc); - - DialogBox(GetModuleHandle(nullptr), - MAKEINTRESOURCE(IDD_DIALOG), nullptr, - (DLGPROC) DialogProc); - - if (hactx != INVALID_HANDLE_VALUE) - { - // Deactivate the context now that the comctl32.dll is loaded. - DeactivateActCtx(0, actxCookie); - } - - return 0; -} - -void -QuitProgressUI() -{ - sQuit = TRUE; -} - -void -UpdateProgressUI(float progress) -{ - sProgress = progress; // 32-bit writes are atomic -} -#endif // _WIN32 diff --git a/onlineupdate/source/update/updater/resource.h b/onlineupdate/source/update/updater/resource.h deleted file mode 100644 index 6b6091c7b8bb..000000000000 --- a/onlineupdate/source/update/updater/resource.h +++ /dev/null @@ -1,29 +0,0 @@ -/* 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/. */ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by updater.rc -// -#define IDD_DIALOG 101 -#define IDC_PROGRESS 1000 -#define IDC_INFO 1002 -#define IDI_DIALOG 1003 -#define TYPE_CERT 512 -#define IDR_PRIMARY_CERT 1004 -#define IDR_BACKUP_CERT 1005 -#define IDS_UPDATER_IDENTITY 1006 -#define IDR_XPCSHELL_CERT 1007 -#define IDR_COMCTL32_MANIFEST 17 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1008 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/onlineupdate/source/update/updater/updater-common.build b/onlineupdate/source/update/updater/updater-common.build deleted file mode 100644 index 6516a4843c43..000000000000 --- a/onlineupdate/source/update/updater/updater-common.build +++ /dev/null @@ -1,119 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -srcs = [ - 'archivereader.cpp', - 'bspatch.cpp', - 'updater.cpp', -] - -have_progressui = 0 - -if CONFIG['VERIFY_MAR_SIGNATURE']: - USE_LIBS += [ - 'verifymar', - ] - -if CONFIG['OS_ARCH'] == 'WINNT': - have_progressui = 1 - srcs += [ - 'loaddlls.cpp', - 'progressui_win.cpp', - 'win_dirent.cpp', - ] - RCINCLUDE = '%supdater.rc' % updater_rel_path - DEFINES['UNICODE'] = True - DEFINES['_UNICODE'] = True - DEFINES['NOMINMAX'] = True - USE_STATIC_LIBS = True - - # Pick up nsWindowsRestart.cpp - LOCAL_INCLUDES += [ - '/toolkit/xre', - ] - USE_LIBS += [ - 'updatecommon-standalone', - ] - OS_LIBS += [ - 'comctl32', - 'ws2_32', - 'shell32', - 'shlwapi', - 'crypt32', - 'advapi32', - ] -elif CONFIG['OS_ARCH'] == 'Linux' and CONFIG['VERIFY_MAR_SIGNATURE']: - USE_LIBS += [ - 'nss', - 'signmar', - 'updatecommon', - ] - OS_LIBS += CONFIG['NSPR_LIBS'] -else: - USE_LIBS += [ - 'updatecommon', - ] - -USE_LIBS += [ - 'mar', -] - -if CONFIG['MOZ_NATIVE_BZ2']: - OS_LIBS += CONFIG['MOZ_BZ2_LIBS'] -else: - USE_LIBS += [ - 'bz2', - ] - -if CONFIG['MOZ_ENABLE_GTK']: - have_progressui = 1 - srcs += [ - 'progressui_gtk.cpp', - ] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': - have_progressui = 1 - srcs += [ - 'launchchild_osx.mm', - 'progressui_osx.mm', - ] - OS_LIBS += [ - '-framework Cocoa', - '-framework Security', - ] - -if have_progressui == 0: - srcs += [ - 'progressui_null.cpp', - ] - -SOURCES += sorted(srcs) - -DEFINES['NS_NO_XPCOM'] = True -DISABLE_STL_WRAPPING = True -for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'): - DEFINES[var] = '"%s"' % CONFIG[var] - -LOCAL_INCLUDES += [ - '/toolkit/mozapps/update/common', - '/xpcom/glue', -] - -DELAYLOAD_DLLS += [ - 'crypt32.dll', - 'comctl32.dll', - 'userenv.dll', - 'wsock32.dll', -] - -if CONFIG['_MSC_VER']: - WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] -elif CONFIG['OS_ARCH'] == 'WINNT': - WIN32_EXE_LDFLAGS += ['-municode'] - -if CONFIG['MOZ_WIDGET_GTK']: - CXXFLAGS += CONFIG['TK_CFLAGS'] - OS_LIBS += CONFIG['TK_LIBS'] diff --git a/onlineupdate/source/update/updater/updater-xpcshell/Makefile.in b/onlineupdate/source/update/updater/updater-xpcshell/Makefile.in deleted file mode 100644 index 21364883435f..000000000000 --- a/onlineupdate/source/update/updater/updater-xpcshell/Makefile.in +++ /dev/null @@ -1,32 +0,0 @@ -# vim:set ts=8 sw=8 sts=8 noet: -# 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/. - -# For changes here, also consider ../Makefile.in - -XPCSHELLTESTROOT = $(abspath $(DEPTH))/_tests/xpcshell/toolkit/mozapps/update/tests -MOCHITESTROOT = $(abspath $(DEPTH))/_tests/testing/mochitest/chrome/toolkit/mozapps/update/tests - -include $(topsrcdir)/config/rules.mk - -libs:: -ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) - # Copy for xpcshell tests - $(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app - rsync -a -C --exclude '*.in' $(srcdir)/../macbuild/Contents $(XPCSHELLTESTROOT)/data/updater-xpcshell.app - sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \ - iconv -f UTF-8 -t UTF-16 > $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings - $(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS/updater-xpcshell - $(NSINSTALL) $(PROGRAM) $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS - rm -f $(PROGRAM) - rm -Rf $(XPCSHELLTESTROOT)/data/updater.app - mv $(XPCSHELLTESTROOT)/data/updater-xpcshell.app $(XPCSHELLTESTROOT)/data/updater.app - mv $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater - - # Copy for mochitest chrome tests - rsync -a -C $(XPCSHELLTESTROOT)/data/updater.app $(MOCHITESTROOT)/data/updater.app -else - cp $(PROGRAM) $(XPCSHELLTESTROOT)/data/updater$(BIN_SUFFIX) - cp $(PROGRAM) $(MOCHITESTROOT)/data/updater$(BIN_SUFFIX) -endif diff --git a/onlineupdate/source/update/updater/updater-xpcshell/moz.build b/onlineupdate/source/update/updater/updater-xpcshell/moz.build deleted file mode 100644 index ba5c844cfc10..000000000000 --- a/onlineupdate/source/update/updater/updater-xpcshell/moz.build +++ /dev/null @@ -1,13 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -Program('updater-xpcshell') - -updater_rel_path = '../' -DIST_INSTALL = False -DEFINES['TEST_UPDATER'] = True -include('../updater-common.build') -FAIL_ON_WARNINGS = True diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx deleted file mode 100644 index 321d43a53936..000000000000 --- a/onlineupdate/source/update/updater/updater.cxx +++ /dev/null @@ -1,4594 +0,0 @@ -/* 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/. */ - -/** - * Manifest Format - * --------------- - * - * contents = 1*( line ) - * line = method LWS *( param LWS ) CRLF - * CRLF = "\r\n" - * LWS = 1*( " " | "\t" ) - * - * Available methods for the manifest file: - * - * updatev2.manifest - * ----------------- - * method = "add" | "add-if" | "patch" | "patch-if" | "remove" | - * "rmdir" | "rmrfdir" | type - * - * 'type' is the update type (e.g. complete or partial) and when present MUST - * be the first entry in the update manifest. The type is used to support - * downgrades by causing the actions defined in precomplete to be performed. - * - * updatev3.manifest - * ----------------- - * method = "add" | "add-if" | "add-if-not" | "patch" | "patch-if" | - * "remove" | "rmdir" | "rmrfdir" | type - * - * 'add-if-not' adds a file if it doesn't exist. - * - * precomplete - * ----------- - * method = "remove" | "rmdir" - */ -#include "bspatch.h" -#include "progressui.h" -#include "archivereader.h" -#include "readstrings.h" -#include "errors.h" -#include "bzlib.h" -#include <thread> -#include <vector> - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <limits.h> -#include <errno.h> -#include <algorithm> -#include <memory> - -#include <config_version.h> - -#include "updatelogging.h" - -#include <onlineupdate/mozilla/Compiler.h> -#include <onlineupdate/mozilla/Types.h> - -#ifdef _WIN32 -#include <comphelper/windowsStart.hxx> -#include "uachelper.h" -#include "pathhash.h" - -// TODO:moggi taken from the mozilla code -- find a better solution -#define INVALID_APPLYTO_DIR_ERROR 74 -#define REMOVE_FILE_SPEC_ERROR 71 -#define INVALID_APPLYTO_DIR_STAGED_ERROR 72 - -#endif - - -// Amount of the progress bar to use in each of the 3 update stages, -// should total 100.0. -#define PROGRESS_PREPARE_SIZE 20.0f -#define PROGRESS_EXECUTE_SIZE 75.0f -#define PROGRESS_FINISH_SIZE 5.0f - -// Amount of time in ms to wait for the parent process to close -#ifdef _WIN32 -#define PARENT_WAIT 5000 -#endif - -#if defined(MACOSX) -// These functions are defined in launchchild_osx.mm -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 -# define SSIZE_MAX LONG_MAX -#endif - -// We want to use execv to invoke the callback executable on platforms where -// we were launched using execv. See nsUpdateDriver.cpp. -#if defined(UNIX) && !defined(MACOSX) -#define USE_EXECV -#endif - -#if defined(VERIFY_MAR_SIGNATURE) && !defined(_WIN32) && !defined(MACOSX) -#include <nss.h> -#include <nspr.h> -#endif - -#ifdef _WIN32 -#ifdef 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 -// return code specified. This prevents multiple launches of the callback -// application by preventing the elevated process from launching the callback. -#define EXIT_WHEN_ELEVATED(path, handle, retCode) \ -{ \ - if (handle != INVALID_HANDLE_VALUE) { \ - CloseHandle(handle); \ - } \ - if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \ - LogFinish(); \ - return retCode; \ - } \ -} -#endif - -//----------------------------------------------------------------------------- - -// 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. -#if defined __GNUC__ -extern "C" __attribute__((visibility("default"))) unsigned int BZ2_crc32Table[256]; -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -extern "C" __global unsigned int BZ2_crc32Table[256]; -#else -extern "C" unsigned int BZ2_crc32Table[256]; -#endif - -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; -} - -//----------------------------------------------------------------------------- - -// A simple stack based container for a FILE struct that closes the -// file descriptor from its destructor. -class AutoFile -{ -public: - explicit AutoFile(FILE* file = nullptr) - : mFile(file) - { - } - - ~AutoFile() - { - if (mFile != nullptr) - fclose(mFile); - } - - AutoFile &operator=(FILE* file) - { - if (mFile != 0) - fclose(mFile); - mFile = file; - return *this; - } - - operator FILE*() - { - return mFile; - } - - FILE* get() - { - return mFile; - } - -private: - FILE* mFile; -}; - -struct MARChannelStringTable -{ - MARChannelStringTable() - { - MARChannelID[0] = '\0'; - } - - char MARChannelID[MAX_TEXT_LEN]; -}; - -//----------------------------------------------------------------------------- - -static NS_tchar* gPatchDirPath; -static NS_tchar gInstallDirPath[MAXPATHLEN]; -static NS_tchar gWorkingDirPath[MAXPATHLEN]; -static bool gSucceeded = false; -static bool sStagedUpdate = false; -static bool sReplaceRequest = false; -static bool sUsingService = false; - -#ifdef _WIN32 -// The current working directory specified in the command line. -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"); -static const NS_tchar kNL[] = NS_T("\r\n"); -static const NS_tchar kQuote[] = NS_T("\""); - -static NS_tchar* -mstrtok(const NS_tchar *delims, NS_tchar **str) -{ - if (!*str || !**str) - { - *str = nullptr; - return nullptr; - } - - // skip leading "whitespace" - NS_tchar *ret = *str; - const NS_tchar *d; - do - { - for (d = delims; *d != NS_T('\0'); ++d) - { - if (*ret == *d) - { - ++ret; - break; - } - } - } - while (*d); - - if (!*ret) - { - *str = ret; - return nullptr; - } - - NS_tchar *i = ret; - do - { - for (d = delims; *d != NS_T('\0'); ++d) - { - if (*i == *d) - { - *i = NS_T('\0'); - *str = ++i; - return ret; - } - } - ++i; - } - while (*i); - - *str = nullptr; - return ret; -} - -#if defined(_WIN32) && defined(MAINTENANCE_SERVICE) -static bool -EnvHasValue(const char *name) -{ - const char *val = getenv(name); - return (val && *val); -} -#endif - -/** - * Converts a relative update path to an absolute path related to the working - * or install directory. Allocates a new NS_tchar[] based path! - * - * @param relpath - * The relative path to convert to a full path. - * @return valid filesystem full path or nullptr if memory allocation fails. - */ -static NS_tchar* -new_absolute_path(const NS_tchar *relpath) -{ - NS_tchar *destpath = sStagedUpdate ? gWorkingDirPath : gInstallDirPath; - size_t lendestpath = NS_tstrlen(destpath); - size_t lenrelpath = NS_tstrlen(relpath); - NS_tchar *s = new NS_tchar[lendestpath + lenrelpath + 2]; - - NS_tchar *c = s; - - NS_tstrcpy(c, destpath); - c += lendestpath; - NS_tstrcat(c, NS_T("/")); - c++; - - NS_tstrcat(c, relpath); - c += lenrelpath; - *c = NS_T('\0'); - return s; -} - -namespace { - -bool is_userprofile_in_instdir() -{ - return false; - /* - // the algorithm is: - // 1.) if userprofile path length is smaller than installation dir, - // the profile is surely not in instdir - // 2.) else comparing the two paths looking only at the installation dir - // characters should yield an equal string - NS_tchar userprofile[MAXPATHLEN]; - NS_tstrcpy(userprofile, gPatchDirPath); - NS_tchar *slash = (NS_tchar *) NS_tstrrchr(userprofile, NS_T('/')); - if (slash) - *slash = NS_T('\0'); - - size_t userprofile_len = NS_tstrlen(userprofile); - size_t installdir_len = NS_tstrlen(gInstallDirPath); - - if (userprofile_len < installdir_len) - return false; - - return NS_tstrncmp(userprofile, gInstallDirPath, installdir_len) == 0; - */ -} - -} - -/** - * Get a pointer in the absolute path, relative to the working or install - * directory. Returns itself, if not absolute or outside of the directory. - * - * @param abs_path - * An absolute 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_offset(const NS_tchar *abs_path) -{ - // If the path isn't absolute, just return it as-is. -#ifdef _WIN32 - if (abs_path[1] != ':' && abs_path[2] != '\\') - { -#else - if (abs_path[0] != '/') - { -#endif - return abs_path; - } - - NS_tchar *prefix = sStagedUpdate ? gWorkingDirPath : gInstallDirPath; - - size_t len = NS_tstrlen(prefix); - if (NS_tstrlen(abs_path) <= len) - return abs_path; - if (0 != NS_tstrncmp(abs_path, prefix, len)) - return abs_path; - return abs_path + len + 1; -} - -/** - * Gets the platform specific path and performs simple checks to the path. If - * the path checks don't pass nullptr will be returned. - * - * @param line - * The line from the manifest that contains the path. - * @param isdir - * Whether the path is a directory path. Defaults to false. - * @return valid filesystem path or nullptr if the path checks fail. - */ -static NS_tchar* -get_valid_path(NS_tchar **line, bool isdir = false) -{ - NS_tchar *path = mstrtok(kQuote, line); - if (!path) - { - LOG(("get_valid_path: unable to determine path: " LOG_S, line)); - return nullptr; - } - - // All paths must be relative from the current working directory - if (path[0] == NS_T('/')) - { - LOG(("get_valid_path: path must be relative: " LOG_S, path)); - return nullptr; - } - -#ifdef _WIN32 - // All paths must be relative from the current working directory - if (path[0] == NS_T('\\') || path[1] == NS_T(':')) - { - LOG(("get_valid_path: path must be relative: " LOG_S, path)); - return nullptr; - } -#endif - - if (isdir) - { - // Directory paths must have a trailing forward slash. - if (path[NS_tstrlen(path) - 1] != NS_T('/')) - { - LOG(("get_valid_path: directory paths must have a trailing forward " \ - "slash: " LOG_S, path)); - return nullptr; - } - - // Remove the trailing forward slash because stat on Windows will return - // ENOENT if the path has a trailing slash. - path[NS_tstrlen(path) - 1] = NS_T('\0'); - } - - // Don't allow relative paths that resolve to a parent directory. - if (NS_tstrstr(path, NS_T("..")) != nullptr) - { - LOG(("get_valid_path: paths must not contain '..': " LOG_S, path)); - return nullptr; - } - - return path; -} - -static NS_tchar* -get_quoted_path(const NS_tchar *path) -{ - size_t lenQuote = NS_tstrlen(kQuote); - size_t lenPath = NS_tstrlen(path); - size_t len = lenQuote + lenPath + lenQuote + 1; - - NS_tchar *s = (NS_tchar *) malloc(len * sizeof(NS_tchar)); - if (!s) - return nullptr; - - NS_tchar *c = s; - NS_tstrcpy(c, kQuote); - c += lenQuote; - NS_tstrcat(c, path); - c += lenPath; - NS_tstrcat(c, kQuote); - c += lenQuote; - *c = NS_T('\0'); - c++; - return s; -} - -static void ensure_write_permissions(const NS_tchar *path) -{ -#ifdef _WIN32 - (void) _wchmod(path, _S_IREAD | _S_IWRITE); -#else - struct stat fs; - if (!stat(path, &fs) && !(fs.st_mode & S_IWUSR)) - { - (void)chmod(path, fs.st_mode | S_IWUSR); - } -#endif -} - -static int ensure_remove(const NS_tchar *path) -{ - ensure_write_permissions(path); - int rv = NS_tremove(path); - if (rv) - LOG(("ensure_remove: failed to remove file: " LOG_S ", rv: %d, err: %d", - path, rv, errno)); - return rv; -} - -// Remove the directory pointed to by path and all of its files and sub-directories. -static int ensure_remove_recursive(const NS_tchar *path, - bool continueEnumOnFailure = false) -{ - // We use lstat rather than stat here so that we can successfully remove - // symlinks. - struct NS_tstat_t sInfo; - int rv = NS_tlstat(path, &sInfo); - if (rv) - { - // This error is benign - return rv; - } - if (!S_ISDIR(sInfo.st_mode)) - { - return ensure_remove(path); - } - - NS_tDIR *dir; - NS_tdirent *entry; - - dir = NS_topendir(path); - if (!dir) - { - LOG(("ensure_remove_recursive: unable to open directory: " LOG_S - ", rv: %d, err: %d", path, rv, errno)); - return rv; - } - - while ((entry = NS_treaddir(dir)) != 0) - { - if (NS_tstrcmp(entry->d_name, NS_T(".")) && - NS_tstrcmp(entry->d_name, NS_T(".."))) - { - NS_tchar childPath[MAXPATHLEN]; - NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]), - NS_T("%s/%s"), path, entry->d_name); - rv = ensure_remove_recursive(childPath); - if (rv && !continueEnumOnFailure) - { - break; - } - } - } - - NS_tclosedir(dir); - - if (rv == OK) - { - ensure_write_permissions(path); - rv = NS_trmdir(path); - if (rv) - { - LOG(("ensure_remove_recursive: unable to remove directory: " LOG_S - ", rv: %d, err: %d", path, rv, errno)); - } - } - return rv; -} - -static bool is_read_only(const NS_tchar *flags) -{ - size_t length = NS_tstrlen(flags); - if (length == 0) - return false; - - // Make sure the string begins with "r" - if (flags[0] != NS_T('r')) - return false; - - // Look for "r+" or "r+b" - if (length > 1 && flags[1] == NS_T('+')) - return false; - - // Look for "rb+" - if (NS_tstrcmp(flags, NS_T("rb+")) == 0) - return false; - - return true; -} - -static FILE* ensure_open(const NS_tchar *path, const NS_tchar *flags, unsigned int options) -{ - ensure_write_permissions(path); - FILE* f = NS_tfopen(path, flags); - if (is_read_only(flags)) - { - // Don't attempt to modify the file permissions if the file is being opened - // in read-only mode. - return f; - } - if (NS_tchmod(path, options) != 0) - { - if (f != nullptr) - { - fclose(f); - } - return nullptr; - } - struct NS_tstat_t ss; - if (NS_tstat(path, &ss) != 0 || ss.st_mode != options) - { - if (f != nullptr) - { - fclose(f); - } - return nullptr; - } - return f; -} - -// Ensure that the directory containing this file exists. -static int ensure_parent_dir(const NS_tchar *path) -{ - int rv = OK; - - NS_tchar *slash = (NS_tchar *) NS_tstrrchr(path, NS_T('/')); - if (slash) - { - *slash = NS_T('\0'); - rv = ensure_parent_dir(path); - // Only attempt to create the directory if we're not at the root - if (rv == OK && *path) - { - rv = NS_tmkdir(path, 0755); - // If the directory already exists, then ignore the error. - if (rv < 0 && errno != EEXIST) - { - LOG(("ensure_parent_dir: failed to create directory: " LOG_S ", " \ - "err: %d", path, errno)); - rv = WRITE_ERROR; - } - else - { - rv = OK; - } - } - *slash = NS_T('/'); - } - return rv; -} - -#ifdef UNIX -static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest) -{ - // Copy symlinks by creating a new symlink to the same target - NS_tchar target[MAXPATHLEN + 1] = {NS_T('\0')}; - int rv = readlink(path, target, MAXPATHLEN); - if (rv == -1) - { - LOG(("ensure_copy_symlink: failed to read the link: " LOG_S ", err: %d", - path, errno)); - return READ_ERROR; - } - rv = symlink(target, dest); - if (rv == -1) - { - LOG(("ensure_copy_symlink: failed to create the new link: " LOG_S ", target: " LOG_S " err: %d", - dest, target, errno)); - return READ_ERROR; - } - return 0; -} -#endif - -// Copy the file named path onto a new file named dest. -static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) -{ -#ifdef _WIN32 - // Fast path for Windows - bool result = CopyFileW(path, dest, false); - if (!result) - { - LOG(("ensure_copy: failed to copy the file " LOG_S " over to " LOG_S ", lasterr: %x", - path, dest, GetLastError())); - return WRITE_ERROR_FILE_COPY; - } - return OK; -#else - struct NS_tstat_t ss; - int rv = NS_tlstat(path, &ss); - if (rv) - { - LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d", - path, errno)); - return READ_ERROR; - } - -#ifdef UNIX - if (S_ISLNK(ss.st_mode)) - { - return ensure_copy_symlink(path, dest); - } -#endif - - AutoFile infile(ensure_open(path, NS_T("rb"), ss.st_mode)); - if (!infile) - { - LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d", - path, errno)); - return READ_ERROR; - } - AutoFile outfile(ensure_open(dest, NS_T("wb"), ss.st_mode)); - if (!outfile) - { - LOG(("ensure_copy: failed to open the file for writing: " LOG_S ", err: %d", - dest, errno)); - return WRITE_ERROR; - } - - // This block size was chosen pretty arbitrarily but seems like a reasonable - // compromise. For example, the optimal block size on a modern macOS machine - // is 100k */ - const int blockSize = 32 * 1024; - void* buffer = malloc(blockSize); - if (!buffer) - return UPDATER_MEM_ERROR; - - while (!feof(infile.get())) - { - size_t read = fread(buffer, 1, blockSize, infile); - if (ferror(infile.get())) - { - LOG(("ensure_copy: failed to read the file: " LOG_S ", err: %d", - path, errno)); - free(buffer); - return READ_ERROR; - } - - size_t written = 0; - - while (written < read) - { - size_t nCount = read - written; - size_t chunkWritten = fwrite(buffer, 1, nCount, outfile); - if (chunkWritten != nCount) - { - LOG(("ensure_copy: failed to write the file: " LOG_S ", err: %d", - dest, errno)); - free(buffer); - return WRITE_ERROR_FILE_COPY; - } - - written += chunkWritten; - } - } - - rv = NS_tchmod(dest, ss.st_mode); - - free(buffer); - return rv; -#endif -} - -template <unsigned N> -struct copy_recursive_skiplist -{ - NS_tchar paths[N][MAXPATHLEN]; - - void append(unsigned index, const NS_tchar *path, const NS_tchar *suffix) - { - NS_tsnprintf(paths[index], MAXPATHLEN, NS_T("%s/%s"), path, suffix); - } - - void append(unsigned index, const NS_tchar* path) - { - NS_tstrcpy(paths[index], path); - } - - bool find(const NS_tchar *path) - { - for (int i = 0; i < static_cast<int>(N); ++i) - { - if (!NS_tstricmp(paths[i], path)) - { - return true; - } - } - return false; - } -}; - -// Copy all of the files and subdirectories under path to a new directory named dest. -// The path names in the skiplist will be skipped and will not be copied. -template <unsigned N> -static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest, - copy_recursive_skiplist<N>& skiplist) -{ - struct NS_tstat_t sInfo; - int rv = NS_tlstat(path, &sInfo); - if (rv) - { - LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d", - path, rv, errno)); - return READ_ERROR; - } - -#ifdef UNIX - if (S_ISLNK(sInfo.st_mode)) - { - return ensure_copy_symlink(path, dest); - } -#endif - - if (!S_ISDIR(sInfo.st_mode)) - { - return ensure_copy(path, dest); - } - - rv = NS_tmkdir(dest, sInfo.st_mode); - if (rv < 0 && errno != EEXIST) - { - LOG(("ensure_copy_recursive: could not create destination directory: " LOG_S ", rv: %d, err: %d", - path, rv, errno)); - return WRITE_ERROR; - } - - NS_tDIR *dir; - NS_tdirent *entry; - - dir = NS_topendir(path); - if (!dir) - { - LOG(("ensure_copy_recursive: path is not a directory: " LOG_S ", rv: %d, err: %d", - path, rv, errno)); - return READ_ERROR; - } - - while ((entry = NS_treaddir(dir)) != 0) - { - if (NS_tstrcmp(entry->d_name, NS_T(".")) && - NS_tstrcmp(entry->d_name, NS_T(".."))) - { - NS_tchar childPath[MAXPATHLEN]; - NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]), - NS_T("%s/%s"), path, entry->d_name); - if (skiplist.find(childPath)) - { - continue; - } - NS_tchar childPathDest[MAXPATHLEN]; - NS_tsnprintf(childPathDest, sizeof(childPathDest)/sizeof(childPathDest[0]), - NS_T("%s/%s"), dest, entry->d_name); - rv = ensure_copy_recursive(childPath, childPathDest, skiplist); - if (rv) - { - break; - } - } - } - NS_tclosedir(dir); - return rv; -} - -// Renames the specified file to the new file specified. If the destination file -// exists it is removed. -static int rename_file(const NS_tchar *spath, const NS_tchar *dpath, - bool allowDirs = false) -{ - int rv = ensure_parent_dir(dpath); - if (rv) - return rv; - - struct NS_tstat_t spathInfo; - rv = NS_tstat(spath, &spathInfo); - if (rv) - { - LOG(("rename_file: failed to read file status info: " LOG_S ", " \ - "err: %d", spath, errno)); - return READ_ERROR; - } - - if (!S_ISREG(spathInfo.st_mode)) - { - if (allowDirs && !S_ISDIR(spathInfo.st_mode)) - { - LOG(("rename_file: path present, but not a file: " LOG_S ", err: %d", - spath, errno)); - return RENAME_ERROR_EXPECTED_FILE; - } - else - { - LOG(("rename_file: proceeding to rename the directory")); - } - } - - if (!NS_taccess(dpath, F_OK)) - { - if (ensure_remove(dpath)) - { - LOG(("rename_file: destination file exists and could not be " \ - "removed: " LOG_S, dpath)); - return WRITE_ERROR_DELETE_FILE; - } - } - - if (NS_trename(spath, dpath) != 0) - { - LOG(("rename_file: failed to rename file - src: " LOG_S ", " \ - "dst:" LOG_S ", err: %d", spath, dpath, errno)); - return WRITE_ERROR; - } - - return OK; -} - -#ifdef _WIN32 -// Remove the directory pointed to by path and all of its files and -// sub-directories. If a file is in use move it to the tobedeleted directory -// and attempt to schedule removal of the file on reboot -static int remove_recursive_on_reboot(const NS_tchar *path, const NS_tchar *deleteDir) -{ - struct NS_tstat_t sInfo; - int rv = NS_tlstat(path, &sInfo); - if (rv) - { - // This error is benign - return rv; - } - - if (!S_ISDIR(sInfo.st_mode)) - { - NS_tchar tmpDeleteFile[MAXPATHLEN]; - GetTempFileNameW(deleteDir, L"rep", 0, tmpDeleteFile); - NS_tremove(tmpDeleteFile); - rv = rename_file(path, tmpDeleteFile, false); - if (MoveFileEx(rv ? path : tmpDeleteFile, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) - { - LOG(("remove_recursive_on_reboot: file will be removed on OS reboot: " - LOG_S, rv ? path : tmpDeleteFile)); - } - else - { - LOG(("remove_recursive_on_reboot: failed to schedule OS reboot removal of " - "file: " LOG_S, rv ? path : tmpDeleteFile)); - } - return rv; - } - - NS_tDIR *dir; - NS_tdirent *entry; - - dir = NS_topendir(path); - if (!dir) - { - LOG(("remove_recursive_on_reboot: unable to open directory: " LOG_S - ", rv: %d, err: %d", - path, rv, errno)); - return rv; - } - - while ((entry = NS_treaddir(dir)) != 0) - { - if (NS_tstrcmp(entry->d_name, NS_T(".")) && - NS_tstrcmp(entry->d_name, NS_T(".."))) - { - NS_tchar childPath[MAXPATHLEN]; - NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]), - NS_T("%s/%s"), path, entry->d_name); - // There is no need to check the return value of this call since this - // function is only called after an update is successful and there is not - // much that can be done to recover if it isn't successful. There is also - // no need to log the value since it will have already been logged. - remove_recursive_on_reboot(childPath, deleteDir); - } - } - - NS_tclosedir(dir); - - if (rv == OK) - { - ensure_write_permissions(path); - rv = NS_trmdir(path); - if (rv) - { - LOG(("remove_recursive_on_reboot: unable to remove directory: " LOG_S - ", rv: %d, err: %d", path, rv, errno)); - } - } - return rv; -} -#endif - -//----------------------------------------------------------------------------- - -// Create a backup of the specified file by renaming it. -static int backup_create(const NS_tchar *path) -{ - NS_tchar backup[MAXPATHLEN]; - NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]), - NS_T("%s") BACKUP_EXT, path); - - return rename_file(path, backup); -} - -// 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, 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, relBackup)); - return OK; - } - - return rename_file(backup, path); -} - -// Discard the backup of the specified file that was created by renaming it. -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; - } - - int rv = ensure_remove(backup); -#if defined(_WIN32) - if (rv && !sStagedUpdate && !sReplaceRequest) - { - LOG(("backup_discard: unable to remove: " LOG_S, relBackup)); - NS_tchar path[MAXPATHLEN]; - GetTempFileNameW(gDeleteDirPath, L"moz", 0, path); - if (rename_file(backup, path)) - { - LOG(("backup_discard: failed to rename file:" LOG_S ", dst:" LOG_S, - relBackup, relPath)); - return WRITE_ERROR_DELETE_BACKUP; - } - // The MoveFileEx call to remove the file 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 containing the file along with its contents after an update is - // 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, relPath)); - } - else - { - LOG(("backup_discard: failed to schedule OS reboot removal of " \ - "file: " LOG_S, relPath)); - } - } -#else - if (rv) - return WRITE_ERROR_DELETE_BACKUP; -#endif - - return OK; -} - -// Helper function for post-processing a temporary backup. -static void backup_finish(const NS_tchar *path, const NS_tchar *relPath, - int status) -{ - if (status == OK) - backup_discard(path, relPath); - else - backup_restore(path, relPath); -} - -//----------------------------------------------------------------------------- - -static int DoUpdate(ArchiveReader& ArchiveReader); - -class Action -{ -public: - Action() : mProgressCost(1), mNext(nullptr) { } - virtual ~Action() { } - - virtual int Parse(NS_tchar *line) = 0; - - // Do any preprocessing to ensure that the action can be performed. Execute - // will be called if this Action and all others return OK from this method. - virtual int Prepare() = 0; - - // Perform the operation. Return OK to indicate success. After all actions - // have been executed, Finish will be called. A requirement of Execute is - // that its operation be reversible from Finish. - virtual int Execute() = 0; - - // Finish is called after execution of all actions. If status is OK, then - // all actions were successfully executed. Otherwise, some action failed. - virtual void Finish(int status) = 0; - - int mProgressCost; -private: - Action* mNext; - - friend class ActionList; -}; - -class RemoveFile : public Action -{ -public: - RemoveFile() : mSkip(0) { } - - int Parse(NS_tchar *line); - int Prepare(); - int Execute(); - void Finish(int status); - -private: - std::unique_ptr<const NS_tchar[]> mFile; - std::unique_ptr<NS_tchar[]> mRelPath; - int mSkip; -}; - -int -RemoveFile::Parse(NS_tchar *line) -{ - // format "<deadfile>" - - NS_tchar* validPath = get_valid_path(&line); - if (!validPath) - return PARSE_ERROR; - - mRelPath.reset(new NS_tchar[MAXPATHLEN]); - NS_tstrcpy(mRelPath.get(), validPath); - - mFile.reset(new_absolute_path(validPath)); - if (!mFile) - { - return PARSE_ERROR; - } - - return OK; -} - -int -RemoveFile::Prepare() -{ - // Skip the file if it already doesn't exist. - int rv = NS_taccess(mFile.get(), F_OK); - if (rv) - { - mSkip = 1; - mProgressCost = 0; - return OK; - } - - LOG(("PREPARE REMOVEFILE " LOG_S, mRelPath.get())); - - // Make sure that we're actually a file... - struct NS_tstat_t fileInfo; - rv = NS_tstat(mFile.get(), &fileInfo); - if (rv) - { - 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.get())); - return DELETE_ERROR_EXPECTED_FILE; - } - - NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile.get(), NS_T('/')); - if (slash) - { - *slash = NS_T('\0'); - rv = NS_taccess(mFile.get(), W_OK); - *slash = NS_T('/'); - } - else - { - rv = NS_taccess(NS_T("."), W_OK); - } - - if (rv) - { - LOG(("access failed: %d", errno)); - return WRITE_ERROR_FILE_ACCESS_DENIED; - } - - return OK; -} - -int -RemoveFile::Execute() -{ - if (mSkip) - return OK; - - 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.get(), F_OK); - if (rv) - { - LOG(("file cannot be removed because it does not exist; skipping")); - mSkip = 1; - return OK; - } - - // Rename the old file. It will be removed in Finish. - rv = backup_create(mFile.get()); - if (rv) - { - LOG(("backup_create failed: %d", rv)); - return rv; - } - - return OK; -} - -void -RemoveFile::Finish(int status) -{ - if (mSkip) - return; - - LOG(("FINISH REMOVEFILE " LOG_S, mRelPath.get())); - - backup_finish(mFile.get(), mRelPath.get(), status); -} - -class RemoveDir : public Action -{ -public: - RemoveDir() : mSkip(0) { } - - virtual int Parse(NS_tchar *line); - virtual int Prepare(); // check that the source dir exists - virtual int Execute(); - virtual void Finish(int status); - -private: - std::unique_ptr<NS_tchar[]> mDir; - std::unique_ptr<NS_tchar[]> mRelPath; - int mSkip; -}; - -int -RemoveDir::Parse(NS_tchar *line) -{ - // format "<deaddir>/" - - NS_tchar* validPath = get_valid_path(&line, true); - if (!validPath) - return PARSE_ERROR; - - mRelPath.reset(new NS_tchar[MAXPATHLEN]); - NS_tstrcpy(mRelPath.get(), validPath); - - mDir.reset(new_absolute_path(validPath)); - if (!mDir) - { - return PARSE_ERROR; - } - - return OK; -} - -int -RemoveDir::Prepare() -{ - // We expect the directory to exist if we are to remove it. - int rv = NS_taccess(mDir.get(), F_OK); - if (rv) - { - mSkip = 1; - mProgressCost = 0; - return OK; - } - - LOG(("PREPARE REMOVEDIR " LOG_S "/", mRelPath.get())); - - // Make sure that we're actually a dir. - struct NS_tstat_t dirInfo; - rv = NS_tstat(mDir.get(), &dirInfo); - if (rv) - { - 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, mRelPath.get())); - return DELETE_ERROR_EXPECTED_DIR; - } - - rv = NS_taccess(mDir.get(), W_OK); - if (rv) - { - LOG(("access failed: %d, %d", rv, errno)); - return WRITE_ERROR_DIR_ACCESS_DENIED; - } - - return OK; -} - -int -RemoveDir::Execute() -{ - if (mSkip) - return OK; - - 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.get(), F_OK); - if (rv) - { - LOG(("directory no longer exists; skipping")); - mSkip = 1; - } - - return OK; -} - -void -RemoveDir::Finish(int status) -{ - if (mSkip || status != OK) - return; - - 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.get(), F_OK); - if (rv) - { - LOG(("directory no longer exists; skipping")); - return; - } - - - if (status == OK) - { - if (NS_trmdir(mDir.get())) - { - LOG(("non-fatal error removing directory: " LOG_S "/, rv: %d, err: %d", - mRelPath.get(), rv, errno)); - } - } -} - -class AddFile : public Action -{ -public: - AddFile(ArchiveReader& ar) : mAdded(false), mArchiveReader(ar) { } - - virtual int Parse(NS_tchar *line); - virtual int Prepare(); - virtual int Execute(); - virtual void Finish(int status); - -private: - std::unique_ptr<NS_tchar[]> mFile; - std::unique_ptr<NS_tchar[]> mRelPath; - bool mAdded; - ArchiveReader& mArchiveReader; -}; - -int -AddFile::Parse(NS_tchar *line) -{ - // format "<newfile>" - - NS_tchar* validPath = get_valid_path(&line); - if (!validPath) - return PARSE_ERROR; - - mRelPath.reset(new NS_tchar[MAXPATHLEN]); - NS_tstrcpy(mRelPath.get(), validPath); - - mFile.reset(new_absolute_path(validPath)); - if (!mFile) - { - return PARSE_ERROR; - } - - return OK; -} - -int -AddFile::Prepare() -{ - LOG(("PREPARE ADD " LOG_S, mRelPath.get())); - - return OK; -} - -int -AddFile::Execute() -{ - 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.get(), F_OK); - if (rv == 0) - { - rv = backup_create(mFile.get()); - if (rv) - return rv; - } - else - { - rv = ensure_parent_dir(mFile.get()); - if (rv) - return rv; - } - -#ifdef _WIN32 - char sourcefile[MAXPATHLEN]; - 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 = mArchiveReader.ExtractFile(sourcefile, mFile.get()); -#else - rv = mArchiveReader.ExtractFile(mRelPath.get(), mFile.get()); -#endif - if (!rv) - { - mAdded = true; - } - return rv; -} - -void -AddFile::Finish(int status) -{ - 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.get()); - backup_finish(mFile.get(), mRelPath.get(), status); -} - -class PatchFile : public Action -{ -public: - PatchFile(ArchiveReader& ar) : mPatchFile(nullptr), mPatchIndex(-1), buf(nullptr), mArchiveReader(ar) { } - - virtual ~PatchFile(); - - 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: - int LoadSourceFile(FILE* ofile); - - static int sPatchIndex; - - const NS_tchar *mPatchFile; - 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; - ArchiveReader& mArchiveReader; -}; - -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)), (DWORD)0, (DWORD)0, (DWORD)-1, (DWORD)-1); - } -#endif - - // delete the temporary patch file - if (spath[0]) - NS_tremove(spath); - - if (buf) - free(buf); -} - -int -PatchFile::LoadSourceFile(FILE* ofile) -{ - struct stat os; - int rv = fstat(fileno((FILE *)ofile), &os); - if (rv) - { - LOG(("LoadSourceFile: unable to stat destination file: " LOG_S ", " \ - "err: %d", mFileRelPath.get(), errno)); - return READ_ERROR; - } - - if (uint32_t(os.st_size) != header.slen) - { - LOG(("LoadSourceFile: destination file size %d does not match expected size %d", - uint32_t(os.st_size), header.slen)); - return LOADSOURCE_ERROR_WRONG_SIZE; - } - - buf = (unsigned char *) malloc(header.slen); - if (!buf) - return UPDATER_MEM_ERROR; - - size_t r = header.slen; - unsigned char *rb = buf; - while (r) - { - const size_t count = std::min<size_t>(SSIZE_MAX, r); - size_t c = fread(rb, 1, count, ofile); - if (c != count) - { - LOG(("LoadSourceFile: error reading destination file: " LOG_S, - mFileRelPath.get())); - return READ_ERROR; - } - - r -= c; - rb += c; - } - - // Verify that the contents of the source file correspond to what we expect. - - unsigned int crc = crc32(buf, header.slen); - - if (crc != header.scrc32) - { - LOG(("LoadSourceFile: destination file crc %d does not match expected " \ - "crc %d", crc, header.scrc32)); - return CRC_ERROR; - } - - return OK; -} - -int -PatchFile::Parse(NS_tchar *line) -{ - // format "<patchfile>" "<filetopatch>" - - // Get the path to the patch file inside of the mar - mPatchFile = mstrtok(kQuote, &line); - if (!mPatchFile) - return PARSE_ERROR; - - // consume whitespace between args - NS_tchar *q = mstrtok(kQuote, &line); - if (!q) - return PARSE_ERROR; - - NS_tchar* validPath = get_valid_path(&line); - if (!validPath) - return PARSE_ERROR; - mFileRelPath.reset(new NS_tchar[MAXPATHLEN]); - NS_tstrcpy(mFileRelPath.get(), validPath); - - mFile.reset(new_absolute_path(validPath)); - if (!mFile) - { - return PARSE_ERROR; - } - - return OK; -} - -int -PatchFile::Prepare() -{ - LOG(("PREPARE PATCH " LOG_S, mFileRelPath.get())); - - // extract the patch to a temporary file - mPatchIndex = sPatchIndex++; - - int nWrittenBytes = NS_tsnprintf(spath, sizeof(spath)/sizeof(spath[0]), - NS_T("%s/updating/%d.patch"), gWorkingDirPath, mPatchIndex); - (void) nWrittenBytes; - - NS_tremove(spath); - - 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)), (DWORD)0, (DWORD)0, (DWORD)-1, (DWORD)-1)) - { - LOG(("Couldn't lock patch file: %d", GetLastError())); - // TODO: moggi: fix the build problem with LOCK_ERROR_PATCH_FILE - return WRITE_ERROR; //return LOCK_ERROR_PATCH_FILE; - } - char sourcefile[MAXPATHLEN]; - if (!WideCharToMultiByte(CP_UTF8, 0, mPatchFile, -1, sourcefile, MAXPATHLEN, - nullptr, nullptr)) - { - LOG(("error converting wchar to utf8: %d", GetLastError())); - return STRING_CONVERSION_ERROR; - } - - int rv = mArchiveReader.ExtractFileToStream(sourcefile, mPatchStream); -#else - int rv = mArchiveReader.ExtractFileToStream(mPatchFile, mPatchStream); -#endif - - return rv; -} - -int -PatchFile::Execute() -{ - LOG(("EXECUTE PATCH " LOG_S, mFileRelPath.get())); - - fseek(mPatchStream, 0, SEEK_SET); - - int rv = MBS_ReadHeader(mPatchStream, &header); - if (rv) - return rv; - - FILE *origfile = nullptr; -#ifdef _WIN32 - 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.get(), NS_T("rb")); - } -#else - origfile = NS_tfopen(mFile.get(), NS_T("rb")); -#endif - - if (!origfile) - { - LOG(("unable to open destination file: " LOG_S ", err: %d", - mFileRelPath.get(), errno)); - return READ_ERROR; - } - - rv = LoadSourceFile(origfile); - fclose(origfile); - if (rv) - { - LOG(("LoadSourceFile failed")); - return rv; - } - - // 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.get(), &ss); - if (rv) - { - LOG(("failed to read file status info: " LOG_S ", err: %d", - mFileRelPath.get(), errno)); - return READ_ERROR; - } - - rv = backup_create(mFile.get()); - if (rv) - return rv; - -#if defined(HAVE_POSIX_FALLOCATE) - AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode)); - posix_fallocate(fileno((FILE *)ofile), 0, header.dlen); -#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 - // have been tested are: - // 1. _chsize / _chsize_s reduced fragmentation though not completely. - // 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.get(), - GENERIC_WRITE, - 0, - nullptr, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - nullptr); - - if (hfile != INVALID_HANDLE_VALUE) - { - if (SetFilePointer(hfile, header.dlen, - nullptr, FILE_BEGIN) != INVALID_SET_FILE_POINTER && - SetEndOfFile(hfile) != 0) - { - shouldTruncate = false; - } - CloseHandle(hfile); - } - - AutoFile ofile(ensure_open(mFile.get(), shouldTruncate ? NS_T("wb+") : NS_T("rb+"), - ss.st_mode)); -#elif defined(MACOSX) - 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 - rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store); - if (rv == -1) - { - // OK, perhaps we are too fragmented, allocate non-continuous - store.fst_flags = F_ALLOCATEALL; - rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store); - } - - if (rv != -1) - { - ftruncate(fileno((FILE *)ofile), header.dlen); - } -#else - 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", mFileRelPath.get(), - errno)); - return WRITE_ERROR_OPEN_PATCH_FILE; - } - -#ifdef _WIN32 - if (!shouldTruncate) - { - fseek(ofile, 0, SEEK_SET); - } -#endif - - rv = MBS_ApplyPatch(&header, mPatchStream, buf, ofile); - - // Go ahead and do a bit of cleanup now to minimize runtime overhead. - // Make sure mPatchStream gets unlocked on Windows; the system will do that, - // but not until some indeterminate future time, and we want determinism. -#ifdef _WIN32 - UnlockFile((HANDLE)_get_osfhandle(fileno(mPatchStream)), (DWORD)0, (DWORD)0, (DWORD)-1, (DWORD)-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, mFileRelPath.get())); - - backup_finish(mFile.get(), mFileRelPath.get(), status); -} - -class AddIfFile : public AddFile -{ -public: - AddIfFile(ArchiveReader& archiveReader); - - virtual int Parse(NS_tchar *line); - virtual int Prepare(); - virtual int Execute(); - virtual void Finish(int status); - -protected: - std::unique_ptr<NS_tchar[]> mTestFile; -}; - -AddIfFile::AddIfFile(ArchiveReader& archiveReader): - AddFile(archiveReader) -{ -} - -int -AddIfFile::Parse(NS_tchar *line) -{ - // format "<testfile>" "<newfile>" - - mTestFile.reset(new_absolute_path(get_valid_path(&line))); - if (!mTestFile) - return PARSE_ERROR; - - // consume whitespace between args - NS_tchar *q = mstrtok(kQuote, &line); - if (!q) - return PARSE_ERROR; - - return AddFile::Parse(line); -} - -int -AddIfFile::Prepare() -{ - // If the test file does not exist, then skip this action. - if (NS_taccess(mTestFile.get(), F_OK)) - { - mTestFile = nullptr; - return OK; - } - - return AddFile::Prepare(); -} - -int -AddIfFile::Execute() -{ - if (!mTestFile) - return OK; - - return AddFile::Execute(); -} - -void -AddIfFile::Finish(int status) -{ - if (!mTestFile) - return; - - AddFile::Finish(status); -} - -class AddIfNotFile : public AddFile -{ -public: - AddIfNotFile(ArchiveReader& archiveReader); - - virtual int Parse(NS_tchar *line); - virtual int Prepare(); - virtual int Execute(); - virtual void Finish(int status); - -protected: - std::unique_ptr<NS_tchar[]> mTestFile; -}; - -AddIfNotFile::AddIfNotFile(ArchiveReader& archiveReader): - AddFile(archiveReader) -{ -} - -int -AddIfNotFile::Parse(NS_tchar *line) -{ - // format "<testfile>" "<newfile>" - - mTestFile.reset(new_absolute_path(get_valid_path(&line))); - if (!mTestFile) - return PARSE_ERROR; - - // consume whitespace between args - NS_tchar *q = mstrtok(kQuote, &line); - if (!q) - return PARSE_ERROR; - - return AddFile::Parse(line); -} - -int -AddIfNotFile::Prepare() -{ - // If the test file exists, then skip this action. - if (!NS_taccess(mTestFile.get(), F_OK)) - { - mTestFile = NULL; - return OK; - } - - return AddFile::Prepare(); -} - -int -AddIfNotFile::Execute() -{ - if (!mTestFile) - return OK; - - return AddFile::Execute(); -} - -void -AddIfNotFile::Finish(int status) -{ - if (!mTestFile) - return; - - AddFile::Finish(status); -} - -class PatchIfFile : public PatchFile -{ -public: - PatchIfFile(ArchiveReader& archiveReader); - - 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: - std::unique_ptr<NS_tchar[]> mTestFile; -}; - -PatchIfFile::PatchIfFile(ArchiveReader& archiveReader): - PatchFile(archiveReader) -{ -} - -int -PatchIfFile::Parse(NS_tchar *line) -{ - // format "<testfile>" "<patchfile>" "<filetopatch>" - - mTestFile.reset(new_absolute_path(get_valid_path(&line))); - if (!mTestFile) - return PARSE_ERROR; - - // consume whitespace between args - NS_tchar *q = mstrtok(kQuote, &line); - if (!q) - return PARSE_ERROR; - - return PatchFile::Parse(line); -} - -int -PatchIfFile::Prepare() -{ - // If the test file does not exist, then skip this action. - if (NS_taccess(mTestFile.get(), F_OK)) - { - mTestFile = nullptr; - return OK; - } - - return PatchFile::Prepare(); -} - -int -PatchIfFile::Execute() -{ - if (!mTestFile) - return OK; - - return PatchFile::Execute(); -} - -void -PatchIfFile::Finish(int status) -{ - if (!mTestFile) - return; - - PatchFile::Finish(status); -} - -//----------------------------------------------------------------------------- - -#ifdef _WIN32 - -/** - * 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); - - // TODO: moggi: needs adaptation for LibreOffice - // Most likely we don't have the helper method yet. Check if we really need it. - - // 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(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, - NS_tchar **argv, - bool usingService) -{ - putenv(const_cast<char*>("NO_EM_RESTART=")); - putenv(const_cast<char*>("MOZ_LAUNCHED_CHILD=1")); - - // Run from the specified working directory (see bug 312360). This is not - // necessary on Windows CE since the application that launches the updater - // passes the working directory as an --environ: command line argument. - if (NS_tchdir(workingDir) != 0) - { - LOG(("Warning: chdir failed")); - } - -#if defined(USE_EXECV) - (void) argc; - (void) usingService; // avoid warnings - execv(argv[0], argv); -#elif defined(MACOSX) - LaunchChild(argc, (const char**)argv); -#elif defined(_WIN32) - // 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. - if (!usingService) - { - WinLaunchChild(argv[0], argc, argv, nullptr); - } -#else -# warning "Need implementation of LaunchCallbackApp" -#endif -} - -static bool -WriteStatusFile(const char* aStatus) -{ - 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; - - // 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) - { - 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; -} - -static void -WriteStatusFile(int status) -{ - const char *text; - - char buf[32]; - if (status == OK) - { - if (sStagedUpdate) - { - text = "applied\n"; - } - else - { - text = "succeeded\n"; - } - } - else - { - snprintf(buf, sizeof(buf)/sizeof(buf[0]), "failed: %d\n", status); - text = buf; - } - - WriteStatusFile(text); -} - -#ifdef MAINTENANCE_SERVICE -/* - * Read the update.status file and sets isPendingService to true if - * the status is set to pending-service. - * - * @param isPendingService Out parameter for specifying if the status - * is set to pending-service or not. - * @return true if the information was retrieved and it is pending - * or pending-service. - */ -static bool -IsUpdateStatusPendingService() -{ - NS_tchar filename[MAXPATHLEN]; - NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), - NS_T("%s/update.status"), gPatchDirPath); - - AutoFile file(NS_tfopen(filename, NS_T("rb"))); - if (file == nullptr) - return false; - - char buf[32] = { 0 }; - fread(buf, sizeof(buf), 1, file); - - const char kPendingService[] = "pending-service"; - const char kAppliedService[] = "applied-service"; - - return (strncmp(buf, kPendingService, - sizeof(kPendingService) - 1) == 0) || - (strncmp(buf, kAppliedService, - sizeof(kAppliedService) - 1) == 0); -} -#endif - -#ifdef _WIN32 -/* - * Read the update.status file and sets isSuccess to true if - * the status is set to succeeded. - * - * @param isSucceeded Out parameter for specifying if the status - * is set to succeeded or not. - * @return true if the information was retrieved and it is succeeded. - */ -static bool -IsUpdateStatusSucceeded(bool &isSucceeded) -{ - isSucceeded = false; - NS_tchar filename[MAXPATHLEN]; - NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), - NS_T("%s/update.status"), gPatchDirPath); - - AutoFile file(NS_tfopen(filename, NS_T("rb"))); - if (file == nullptr) - return false; - - char buf[32] = { 0 }; - fread(buf, sizeof(buf), 1, file); - - const char kSucceeded[] = "succeeded"; - isSucceeded = strncmp(buf, kSucceeded, - sizeof(kSucceeded) - 1) == 0; - return true; -} -#endif - -/* - * Copy the entire contents of the application installation directory to the - * destination directory for the update process. - * - * @return 0 if successful, an error code otherwise. - */ -static int -CopyInstallDirToDestDir() -{ - // These files should not be copied over to the updated app -#ifdef _WIN32 -#define SKIPLIST_COUNT 4 -#elif defined(MACOSX) -#define SKIPLIST_COUNT 1 -#else -#define SKIPLIST_COUNT 3 -#endif - copy_recursive_skiplist<SKIPLIST_COUNT> skiplist; - - std::unique_ptr<NS_tchar[]> pUserProfile(new NS_tchar[MAXPATHLEN]); - NS_tstrcpy(pUserProfile.get(), gPatchDirPath); - NS_tchar *slash = (NS_tchar *) NS_tstrrchr(pUserProfile.get(), NS_T('/')); - if (slash) - *slash = NS_T('\0'); - - LOG(("ignore user profile directory during copy: " LOG_S, pUserProfile.get())); - - skiplist.append(0, pUserProfile.get()); -#ifndef MACOSX - skiplist.append(1, gInstallDirPath, NS_T("updated")); - skiplist.append(2, gInstallDirPath, NS_T("updates/0")); -#ifdef _WIN32 - skiplist.append(4, gInstallDirPath, NS_T("updated.update_in_progress.lock")); -#endif -#endif - - return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist); -} - -/* - * Replace the application installation directory with the destination - * directory in order to finish a staged update task - * - * @return 0 if successful, an error code otherwise. - */ -static int -ProcessReplaceRequest() -{ - // TODO: moggi: handle the user profile in the installation dir also - // during the replacement request - // The replacement algorithm is like this: - // 1. Move destDir to tmpDir. In case of failure, abort. - // 2. Move newDir to destDir. In case of failure, revert step 1 and abort. - // 3. Delete tmpDir (or defer it to the next reboot). - -#ifdef MACOSX - NS_tchar destDir[MAXPATHLEN]; - NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]), - NS_T("%s/Contents"), gInstallDirPath); -#elif defined(_WIN32) - // Windows preserves the case of the file/directory names. We use the - // GetLongPathName API in order to get the correct case for the directory - // name, so that if the user has used a different case when launching the - // application, the installation directory's name does not change. - NS_tchar destDir[MAXPATHLEN]; - if (!GetLongPathNameW(gInstallDirPath, destDir, - sizeof(destDir)/sizeof(destDir[0]))) - { - return NO_INSTALLDIR_ERROR; - } -#else - NS_tchar* destDir = gInstallDirPath; -#endif - - NS_tchar tmpDir[MAXPATHLEN]; - NS_tsnprintf(tmpDir, sizeof(tmpDir)/sizeof(tmpDir[0]), - NS_T("%s.bak"), destDir); - - // First try to remove the possibly existing temp directory, because if this - // directory exists, we will fail to rename destDir. - // No need to error check here because if this fails, we will fail in the - // next step anyways. - ensure_remove_recursive(tmpDir); - - LOG(("Begin moving destDir (" LOG_S ") to tmpDir (" LOG_S ")", - destDir, tmpDir)); - LogFlush(); - int rv = rename_file(destDir, tmpDir, true); -#ifdef _WIN32 - // On Windows, if Firefox is launched using the shortcut, it will hold a handle - // to its installation directory open, which might not get released in time. - // Therefore we wait a little bit here to see if the handle is released. - // If it's not released, we just fail to perform the replace request. - const int max_retries = 10; - int retries = 0; - while (rv == WRITE_ERROR && (retries++ < max_retries)) - { - LOG(("PerformReplaceRequest: destDir rename attempt %d failed. " \ - "File: " LOG_S ". Last error: %d, err: %d", retries, - destDir, GetLastError(), rv)); - - Sleep(100); - - rv = rename_file(destDir, tmpDir, true); - } -#endif - if (rv) - { - // The status file will have 'pending' written to it so there is no value in - // returning an error specific for this failure. - LOG(("Moving destDir to tmpDir failed, err: %d", rv)); - return rv; - } - - NS_tchar newDir[MAXPATHLEN]; - if (is_userprofile_in_instdir()) - { - LOG(("user profile in instdir")); - NS_tstrcpy(newDir, tmpDir); - NS_tstrcat(newDir, gWorkingDirPath + NS_tstrlen(gInstallDirPath)); - LOG((LOG_S, newDir)); - } - else - { - NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]), - NS_T("%s"), - gWorkingDirPath); - } - - LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")", - newDir, destDir)); - rv = rename_file(newDir, destDir, true); -#ifdef MACOSX - if (rv) - { - LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")", - newDir, destDir)); - copy_recursive_skiplist<0> skiplist; - rv = ensure_copy_recursive(newDir, destDir, skiplist); - } -#endif - if (rv) - { - LOG(("Moving newDir to destDir failed, err: %d", rv)); - LOG(("Now, try to move tmpDir back to destDir")); - ensure_remove_recursive(destDir); - int rv2 = rename_file(tmpDir, destDir, true); - if (rv2) - { - LOG(("Moving tmpDir back to destDir failed, err: %d", rv2)); - } - // The status file will be have 'pending' written to it so there is no value - // in returning an error specific for this failure. - return rv; - } - - if (is_userprofile_in_instdir()) - { - // 1.) calculate path of the user profile in the backup directory - // 2.) move the user profile from the backup to the install directory - NS_tchar backup_user_profile[MAXPATHLEN]; - NS_tchar userprofile[MAXPATHLEN]; - - NS_tstrcpy(userprofile, gPatchDirPath); - NS_tchar* slash = (NS_tchar *) NS_tstrrchr(userprofile, NS_T('/')); - if (slash) - *slash = NS_T('\0'); - NS_tstrcpy(backup_user_profile, tmpDir); - size_t installdir_len = NS_tstrlen(destDir); - - NS_tstrcat(backup_user_profile, userprofile + installdir_len); - LOG(("copy user profile back from " LOG_S " to " LOG_S, backup_user_profile, userprofile)); - int rv2 = rename_file(backup_user_profile, userprofile); - if (rv2) - { - LOG(("failed to copy user profile back")); - } - if (slash) - *slash = NS_T('/'); - } - -#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]; - int nWrittenBytes = NS_tsnprintf(tmpLog, sizeof(tmpLog)/sizeof(tmpLog[0]), - NS_T("%s/updates/last-update.log"), tmpDir); - (void) nWrittenBytes; - 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) - { - LOG(("Removing tmpDir failed, err: %d", rv)); -#ifdef _WIN32 - NS_tchar deleteDir[MAXPATHLEN]; - NS_tsnprintf(deleteDir, sizeof(deleteDir)/sizeof(deleteDir[0]), - NS_T("%s\\%s"), destDir, DELETE_DIR); - // Attempt to remove the tobedeleted directory and then recreate it if it - // was successfully removed. - _wrmdir(deleteDir); - if (NS_taccess(deleteDir, F_OK)) - { - NS_tmkdir(deleteDir, 0755); - } - remove_recursive_on_reboot(tmpDir, deleteDir); -#endif - } - -#ifdef MACOSX - // On macOS, we need to remove the staging directory after its Contents - // directory has been moved. - NS_tchar updatedAppDir[MAXPATHLEN]; - NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]), - NS_T("%s/Updated.app"), gPatchDirPath); - ensure_remove_recursive(updatedAppDir); -#endif - - gSucceeded = true; - - return 0; -} - -#ifdef _WIN32 -static void -WaitForServiceFinishThread(void* /*param*/) -{ - // We wait at most 10 minutes, we already waited 5 seconds previously - // before deciding to show this UI. - WaitForServiceStop(SVC_NAME, 595); - QuitProgressUI(); -} -#endif - -#ifdef VERIFY_MAR_SIGNATURE -/** - * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from update-settings.ini - * - * @param path The path to the ini file that is to be read - * @param results A pointer to the location to store the read strings - * @return OK on success - */ -static int -ReadMARChannelIDs(const NS_tchar *path, MARChannelStringTable *results) -{ - // TODO: moggi: needs adaptation for LibreOffice - // Check where this function gets its parameters from - const unsigned int kNumStrings = 1; - const char *kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0"; - char updater_strings[kNumStrings][MAX_TEXT_LEN]; - - int result = ReadStrings(path, kUpdaterKeys, kNumStrings, - updater_strings, "Settings"); - - strncpy(results->MARChannelID, updater_strings[0], MAX_TEXT_LEN - 1); - results->MARChannelID[MAX_TEXT_LEN - 1] = 0; - - return result; -} -#endif - -static int -GetUpdateFileNames(std::vector<tstring>& fileNames) -{ - NS_tchar fileName[MAXPATHLEN]; - NS_tsnprintf(fileName, MAXPATHLEN, - NS_T("%s/update.mar"), gPatchDirPath); - fileNames.push_back(fileName); - - // add the language packs - NS_tDIR* dir = NS_topendir(gPatchDirPath); - if (!dir) - { - LOG(("Could not open directory " LOG_S, gPatchDirPath)); - return READ_ERROR; - } - - NS_tdirent* entry; - while ((entry = NS_treaddir(dir)) != nullptr) - { - if (NS_tstrcmp(entry->d_name, NS_T(".")) && - NS_tstrcmp(entry->d_name, NS_T("..")) && - NS_tstrcmp(entry->d_name, NS_T("update.mar"))) - { - if (NS_tstrncmp(entry->d_name, NS_T("update"), 6) == 0) - { - NS_tchar *dot = NS_tstrrchr(entry->d_name, NS_T('.')); - if (dot && !NS_tstrcmp(dot, NS_T(".mar"))) - { - NS_tchar updatePath[MAXPATHLEN]; - NS_tsnprintf(updatePath, sizeof(updatePath)/sizeof(updatePath[0]), - NS_T("%s/%s"), gPatchDirPath, entry->d_name); - - LOG (("Found language update file: " LOG_S, updatePath)); - fileNames.push_back(updatePath); - } - } - } - } - return OK; -} - -static int -CheckSignature(ArchiveReader& archiveReader) -{ -#ifdef VERIFY_MAR_SIGNATURE -#ifdef _WIN32 - HKEY baseKey = nullptr; - wchar_t valueName[] = L"Image Path"; - wchar_t rasenh[] = L"rsaenh.dll"; - bool reset = false; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Microsoft Enhanced Cryptographic Provider v1.0", - 0, KEY_READ | KEY_WRITE, - &baseKey) == ERROR_SUCCESS) - { - wchar_t path[MAX_PATH + 1]; - DWORD size = sizeof(path); - DWORD type; - if (RegQueryValueExW(baseKey, valueName, 0, &type, - (LPBYTE)path, &size) == ERROR_SUCCESS) - { - if (type == REG_SZ && wcscmp(path, rasenh) == 0) - { - wchar_t rasenhFullPath[] = L"%SystemRoot%\\System32\\rsaenh.dll"; - if (RegSetValueExW(baseKey, valueName, 0, REG_SZ, - (const BYTE*)rasenhFullPath, - sizeof(rasenhFullPath)) == ERROR_SUCCESS) - { - reset = true; - } - } - } - } -#endif - int rv = archiveReader.VerifySignature(); -#ifdef _WIN32 - if (baseKey) - { - if (reset) - { - RegSetValueExW(baseKey, valueName, 0, REG_SZ, - (const BYTE*)rasenh, - sizeof(rasenh)); - } - RegCloseKey(baseKey); - } -#endif - - - if (rv == OK) - { - if (rv == OK) - { - NS_tchar updateSettingsPath[MAX_TEXT_LEN]; - - // TODO: moggi: needs adaptation for LibreOffice - // These paths need to be adapted for us. - int nWrittenBytes = NS_tsnprintf(updateSettingsPath, - sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), -#ifdef MACOSX - NS_T("%s/Contents/Resources/update-settings.ini"), -#else - NS_T("%s/update-settings.ini"), -#endif - gWorkingDirPath); - (void) nWrittenBytes; - MARChannelStringTable MARStrings; - if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) - { - // If we can't read from update-settings.ini then we shouldn't impose - // a MAR restriction. Some installations won't even include this file. - MARStrings.MARChannelID[0] = '\0'; - } - - rv = archiveReader.VerifyProductInformation(MARStrings.MARChannelID, - LIBO_VERSION_DOTTED); - } - } -#endif - - return rv; -} - -static void -UpdateThreadFunc(void * /*param*/) -{ - // open ZIP archive and process... - int rv = OK; - if (sReplaceRequest) - { - rv = ProcessReplaceRequest(); - } - else - { - std::vector<tstring> fileNames; - GetUpdateFileNames(fileNames); - - for (auto& fileName: fileNames) - { - ArchiveReader archiveReader; - rv = archiveReader.Open(fileName.c_str()); - if (rv != OK) - { - LOG(("Could not open " LOG_S, fileName.c_str())); - break; - } - - rv = CheckSignature(archiveReader); - if (rv != OK) - { - LOG(("Could not verify the signature of " LOG_S, fileName.c_str())); - break; - } - } - - if (rv == OK && sStagedUpdate) - { - rv = CopyInstallDirToDestDir(); - } - - if (rv == OK) - { - for (auto& fileName: fileNames) - { - ArchiveReader archiveReader; - archiveReader.Open(fileName.c_str()); - rv = DoUpdate(archiveReader); - } - NS_tchar updatingDir[MAXPATHLEN]; - int nWrittenBytes = NS_tsnprintf(updatingDir, sizeof(updatingDir)/sizeof(updatingDir[0]), - NS_T("%s/updating"), gWorkingDirPath); - (void) nWrittenBytes; - ensure_remove_recursive(updatingDir); - } - } - - 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 - // launching the callback application. The callback application's - // startup path will see the pending status, and will start the - // updater application again in order to apply the update without - // staging. - 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=")); -#endif - } - else - { - if (rv) - { - LOG(("failed: %d", rv)); - } - else - { -#ifdef MACOSX - // If the update was successful we need to update the timestamp on the - // top-level macOS bundle directory so that macOS's Launch Services - // picks up any major changes when the bundle is updated. - if (!sStagedUpdate && utimes(gInstallDirPath, nullptr) != 0) - { - LOG(("Couldn't set access/modification time on application bundle.")); - } -#endif - - LOG(("succeeded")); - } - WriteStatusFile(rv); - } - - LOG(("calling QuitProgressUI")); - 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 defined(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 USING_SERVICE will not exist. - if (!sUsingService) - { - StartServiceUpdate(gInstallDirPath); - } - } - EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); -#elif defined(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 - // TODO: moggi: needs adaptation for LibreOffice - 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. - // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS - // databases. - if (!NSS_IsInitialized()) - { - if (NSS_NoDB_Init(NULL) != SECSuccess) - { - PRErrorCode error = PR_GetError(); - fprintf(stderr, "Could not initialize NSS: %s (%d)", - PR_ErrorToName(error), (int) error); - _exit(1); - } - } -#endif - -#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 - // argument, the install directory as the second argument, and the directory - // to apply the update to as the third argument. When the updater is launched - // by another process the PID of the parent process should be provided in the - // optional fourth argument and the updater will wait on the parent process to - // exit if the value is non-zero and the process is present. This is necessary - // due to not being able to update files that are in use on Windows. The - // optional fifth argument is the callback's working directory and the - // optional sixth argument is the callback path. The callback is the - // application to launch after updating and it will be launched when these - // arguments are provided whether the update was successful or not. All - // remaining arguments are optional and are passed to the callback when it is - // 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 - // elements, but I don't necessarily believe it. - NS_tstrncpy(gInstallDirPath, argv[2], MAXPATHLEN); - gInstallDirPath[MAXPATHLEN - 1] = NS_T('\0'); - NS_tchar *slash = NS_tstrrchr(gInstallDirPath, NS_SLASH); - if (slash && !slash[1]) - { - *slash = NS_T('\0'); - } - -#ifdef _WIN32 - bool useService = false; - bool testOnlyFallbackKeyExists = false; - bool noServiceFallback = false; - - // We never want the service to be used unless we build with - // the maintenance service. -#ifdef MAINTENANCE_SERVICE - useService = IsUpdateStatusPendingService(); - // Our tests run with a different apply directory for each test. - // We use this registry key on our test slaves to store the - // allowed name/issuers. - testOnlyFallbackKeyExists = DoesFallbackKeyExist(); -#endif - - // Remove everything except close window from the context menu - { - // TODO: moggi: needs adaptation for LibreOffice - HKEY hkApp = nullptr; - RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", - 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr); - RegCloseKey(hkApp); - if (RegCreateKeyExW(HKEY_CURRENT_USER, - L"Software\\Classes\\Applications\\updater.exe", - 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr) == ERROR_SUCCESS) - { - RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0); - RegCloseKey(hkApp); - } - } -#endif - - // If there is a PID specified and it is not '0' then wait for the process to exit. -#ifdef _WIN32 - __int64 pid = 0; -#else - int pid = 0; -#endif - if (argc > 4) - { -#ifdef _WIN32 - pid = _wtoi64(argv[4]); -#else - pid = atoi(argv[4]); -#endif - if (pid == -1) - { - // This is a signal from the parent process that the updater should stage - // the update. - sStagedUpdate = true; - } - else if (NS_tstrstr(argv[4], NS_T("/replace"))) - { - // We're processing a request to replace the application with a staged - // update. - sReplaceRequest = true; - } - } - - // 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 - // elements, but I don't necessarily believe it. - NS_tstrncpy(gWorkingDirPath, argv[3], MAXPATHLEN); - gWorkingDirPath[MAXPATHLEN - 1] = NS_T('\0'); - slash = NS_tstrrchr(gWorkingDirPath, NS_SLASH); - if (slash && !slash[1]) - { - *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 - - 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; - } - - if (sStagedUpdate) - { - LOG(("Performing a staged update")); - } - else if (sReplaceRequest) - { - LOG(("Performing a replace request")); - } - - LOG(("PATCH DIRECTORY " LOG_S, gPatchDirPath)); - LOG(("INSTALLATION DIRECTORY " LOG_S, gInstallDirPath)); - 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. - // Otherwise, wait for the parent process to exit before starting the - // update. - if (parent) - { - DWORD waitTime = PARENT_WAIT; - DWORD result = WaitForSingleObject(parent, waitTime); - CloseHandle(parent); - if (result != WAIT_OBJECT_0) - return 1; - } - } -#else - if (pid > 0) - waitpid(pid, nullptr, 0); -#endif - -#if defined(_WIN32) -#ifdef MAINTENANCE_SERVICE - sUsingService = EnvHasValue("USING_SERVICE"); - putenv(const_cast<char*>("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. - // When fallback is disabled (MOZ_NO_SERVICE_FALLBACK does not exist) then - // we will instead fallback to not using the service and display a UAC prompt. - int lastFallbackError = FALLBACKKEY_UNKNOWN_ERROR; - - // Launch a second instance of the updater with the runas verb on Windows - // when write access is denied to the installation directory. - HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE; - NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')}; - if (!sUsingService && - (argc > callbackIndex || sStagedUpdate || sReplaceRequest)) - { - NS_tchar updateLockFilePath[MAXPATHLEN]; - if (sStagedUpdate) - { - // When staging an update, the lock file is: - // <install_dir>\updated.update_in_progress.lock - NS_tsnprintf(updateLockFilePath, - sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), - NS_T("%s/updated.update_in_progress.lock"), gInstallDirPath); - } - else if (sReplaceRequest) - { - // When processing a replace request, the lock file is: - // <install_dir>\..\moz_update_in_progress.lock - NS_tchar installDir[MAXPATHLEN]; - NS_tstrcpy(installDir, gInstallDirPath); - NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH); - *slash = NS_T('\0'); - NS_tsnprintf(updateLockFilePath, - sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), - NS_T("%s\\moz_update_in_progress.lock"), installDir); - } - else - { - // In the non-staging update case, the lock file is: - // <install_dir>\<app_name>.exe.update_in_progress.lock - NS_tsnprintf(updateLockFilePath, - sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), - NS_T("%s.update_in_progress.lock"), argv[callbackIndex]); - } - - // The update_in_progress.lock file should only exist during an update. In - // case it exists attempt to remove it and exit if that fails to prevent - // simultaneous updates occurring. - if (!_waccess(updateLockFilePath, F_OK) && - NS_tremove(updateLockFilePath) != 0) - { - // Try to fall back to the old way of doing updates if a staged - // update fails. - if (sStagedUpdate || sReplaceRequest) - { - // Note that this could fail, but if it does, there isn't too much we - // can do in order to recover anyways. - WriteStatusFile("pending"); - } - LOG(("Update already in progress! Exiting")); - return 1; - } - - updateLockFileHandle = CreateFileW(updateLockFilePath, - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_ALWAYS, - FILE_FLAG_DELETE_ON_CLOSE, - nullptr); - - NS_tsnprintf(elevatedLockFilePath, - sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]), - NS_T("%s/update_elevated.lock"), gPatchDirPath); - - // Even if a file has no sharing access, you can still get its attributes - bool startedFromUnelevatedUpdater = - GetFileAttributesW(elevatedLockFilePath) != INVALID_FILE_ATTRIBUTES; - - // If we're running from the service, then we were started with the same - // token as the service so the permissions are already dropped. If we're - // running from an elevated updater that was started from an unelevated - // updater, then we drop the permissions here. We do not drop the - // permissions on the originally called updater because we use its token - // to start the callback application. - if (startedFromUnelevatedUpdater) - { - // Disable every privilege we don't need. Processes started using - // CreateProcess will use the same token as this process. - UACHelper::DisablePrivileges(nullptr); - } - - if (updateLockFileHandle == INVALID_HANDLE_VALUE || - (useService && testOnlyFallbackKeyExists && noServiceFallback)) - { - if (!_waccess(elevatedLockFilePath, F_OK) && - NS_tremove(elevatedLockFilePath) != 0) - { - fprintf(stderr, "Unable to create elevated lock file! Exiting\n"); - return 1; - } - - HANDLE elevatedFileHandle; - elevatedFileHandle = CreateFileW(elevatedLockFilePath, - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_ALWAYS, - FILE_FLAG_DELETE_ON_CLOSE, - nullptr); - - if (elevatedFileHandle == INVALID_HANDLE_VALUE) - { - LOG(("Unable to create elevated lock file! Exiting")); - return 1; - } - - wchar_t *cmdLine = MakeCommandLine(argc - 1, argv + 1); - if (!cmdLine) - { - CloseHandle(elevatedFileHandle); - return 1; - } - - // Make sure the path to the updater to use for the update is on local. - // We do this check to make sure that file locking is available for - // race condition security checks. - if (useService) - { - BOOL isLocal = FALSE; - useService = IsLocalFile(argv[0], isLocal) && isLocal; - } - - // If we have unprompted elevation we should NOT use the service - // for the update. Service updates happen with the SYSTEM account - // which has more privs than we need to update with. - // Windows 8 provides a user interface so users can configure this - // behavior and it can be configured in the registry in all Windows - // versions that support UAC. - if (useService) - { - BOOL unpromptedElevation; - if (IsUnpromptedElevation(unpromptedElevation)) - { - useService = !unpromptedElevation; - } - } - - // Make sure the service registry entries for the installation path - // are available. If not don't use the service. - if (useService) - { - WCHAR maintenanceServiceKey[MAX_PATH + 1]; - // TODO: moggi: needs adaptation for LibreOffice - // Most likely the registry part is not correct yet - if (CalculateRegistryPathFromFilePath(gInstallDirPath, - maintenanceServiceKey)) - { - HKEY baseKey = nullptr; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, - maintenanceServiceKey, 0, - KEY_READ | KEY_WOW64_64KEY, - &baseKey) == ERROR_SUCCESS) - { - RegCloseKey(baseKey); - } - else - { -#ifdef TEST_UPDATER - useService = testOnlyFallbackKeyExists; -#endif - if (!useService) - { - lastFallbackError = FALLBACKKEY_NOKEY_ERROR; - } - } - } - else - { - useService = false; - lastFallbackError = FALLBACKKEY_REGPATH_ERROR; - } - } - - // Originally we used to write "pending" to update.status before - // launching the service command. This is no longer needed now - // since the service command is launched from updater.exe. If anything - // fails in between, we can fall back to using the normal update process - // on our own. - - // If we still want to use the service try to launch the service - // command for the update. - if (useService) - { - // If the update couldn't be started, then set useService to false so - // we do the update the old way. - DWORD ret = LaunchServiceSoftwareUpdateCommand(argc, (LPCWSTR *)argv); - useService = (ret == ERROR_SUCCESS); - // If the command was launched then wait for the service to be done. - if (useService) - { - bool showProgressUI = false; - // Never show the progress UI when staging updates. - if (!sStagedUpdate) - { - // We need to call this separately instead of allowing ShowProgressUI - // to initialize the strings because the service will move the - // ini file out of the way when running updater. - showProgressUI = !InitProgressUIStrings(); - } - - // Wait for the service to stop for 5 seconds. If the service - // has still not stopped then show an indeterminate progress bar. - DWORD lastState = WaitForServiceStop(SVC_NAME, 5); - if (lastState != SERVICE_STOPPED) - { - std::thread waitThread(WaitForServiceFinishThread, nullptr); - if (showProgressUI) - { - ShowProgressUI(true, false); - } - waitThread.join(); - } - - lastState = WaitForServiceStop(SVC_NAME, 1); - if (lastState != SERVICE_STOPPED) - { - // If the service doesn't stop after 10 minutes there is - // something seriously wrong. - lastFallbackError = FALLBACKKEY_SERVICE_NO_STOP_ERROR; - useService = false; - } - } - else - { - lastFallbackError = FALLBACKKEY_LAUNCH_ERROR; - } - } - - // If the service can't be used when staging and update, make sure that - // the UAC prompt is not shown! In this case, just set the status to - // pending and the update will be applied during the next startup. - if (!useService && sStagedUpdate) - { - if (updateLockFileHandle != INVALID_HANDLE_VALUE) - { - CloseHandle(updateLockFileHandle); - } - WriteStatusFile("pending"); - return 0; - } - - // If we started the service command, and it finished, check the - // update.status file to make sure it succeeded, and if it did - // we need to manually start the PostUpdate process from the - // current user's session of this unelevated updater.exe the - // current process is running as. - // Note that we don't need to do this if we're just staging the update, - // as the PostUpdate step runs when performing the replacing in that case. - if (useService && !sStagedUpdate) - { - bool updateStatusSucceeded = false; - if (IsUpdateStatusSucceeded(updateStatusSucceeded) && - updateStatusSucceeded) - { - if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) - { - fprintf(stderr, "The post update process which runs as the user" - " for service update could not be launched."); - } - } - } - - // If we didn't want to use the service at all, or if an update was - // already happening, or launching the service command failed, then - // launch the elevated updater.exe as we do without the service. - // We don't launch the elevated updater in the case that we did have - // write access all along because in that case the only reason we're - // using the service is because we are testing. - if (!useService && !noServiceFallback && - updateLockFileHandle == INVALID_HANDLE_VALUE) - { - SHELLEXECUTEINFO sinfo; - memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO)); - sinfo.cbSize = sizeof(SHELLEXECUTEINFO); - sinfo.fMask = SEE_MASK_FLAG_NO_UI | - SEE_MASK_FLAG_DDEWAIT | - SEE_MASK_NOCLOSEPROCESS; - sinfo.hwnd = nullptr; - sinfo.lpFile = argv[0]; - sinfo.lpParameters = cmdLine; - sinfo.lpVerb = L"runas"; - sinfo.nShow = SW_SHOWNORMAL; - - bool result = ShellExecuteEx(&sinfo); - free(cmdLine); - - if (result) - { - WaitForSingleObject(sinfo.hProcess, INFINITE); - CloseHandle(sinfo.hProcess); - } - else - { - WriteStatusFile(ELEVATION_CANCELED); - } - } - - if (argc > callbackIndex) - { - LaunchCallbackApp(argv[5], argc - callbackIndex, - argv + callbackIndex, sUsingService); - } - - CloseHandle(elevatedFileHandle); - - if (!useService && !noServiceFallback && - INVALID_HANDLE_VALUE == updateLockFileHandle) - { - // We didn't use the service and we did run the elevated updater.exe. - // The elevated updater.exe is responsible for writing out the - // update.status file. - return 0; - } - else if (useService) - { - // The service command was launched. The service is responsible for - // writing out the update.status file. - if (updateLockFileHandle != INVALID_HANDLE_VALUE) - { - CloseHandle(updateLockFileHandle); - } - return 0; - } - else - { - // Otherwise the service command was not launched at all. - // We are only reaching this code path because we had write access - // all along to the directory and a fallback key existed, and we - // have fallback disabled (MOZ_NO_SERVICE_FALLBACK env var exists). - // We only currently use this env var from XPCShell tests. - CloseHandle(updateLockFileHandle); - WriteStatusFile(lastFallbackError); - return 0; - } - } - } -#endif - - if (sStagedUpdate) - { - // When staging updates, blow away the old installation directory and create - // it from scratch. - ensure_remove_recursive(gWorkingDirPath); - } - if (!sReplaceRequest) - { - // 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; - } - } - -#ifdef _WIN32 - // For replace requests, we don't need to do any real updates, so this is not - // necessary. - if (!sReplaceRequest) - { - // Allocate enough space for the length of the path an optional additional - // trailing slash and null termination. - NS_tchar *destpath = (NS_tchar *) malloc((NS_tstrlen(gWorkingDirPath) + 2) * sizeof(NS_tchar)); - if (!destpath) - return 1; - - NS_tchar *c = destpath; - NS_tstrcpy(c, gWorkingDirPath); - c += NS_tstrlen(gWorkingDirPath); - if (gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('/') && - gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('\\')) - { - NS_tstrcat(c, NS_T("/")); - c += NS_tstrlen(NS_T("/")); - } - *c = NS_T('\0'); - c++; - - gDestPath = destpath; - } - - NS_tchar applyDirLongPath[MAXPATHLEN]; - if (!GetLongPathNameW(gWorkingDirPath, applyDirLongPath, - sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) - { - LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath)); - LogFinish(); - WriteStatusFile(WRITE_ERROR_APPLY_DIR_PATH); - EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); - if (argc > callbackIndex) - { - LaunchCallbackApp(argv[5], argc - callbackIndex, - argv + callbackIndex, sUsingService); - } - return 1; - } - - HANDLE callbackFile = INVALID_HANDLE_VALUE; - if (argc > callbackIndex) - { - // If the callback executable is specified it must exist for a successful - // update. It is important we null out the whole buffer here because later - // we make the assumption that the callback application is inside the - // apply-to dir. If we don't have a fully null'ed out buffer it can lead - // to stack corruption which causes crashes and other problems. - NS_tchar callbackLongPath[MAXPATHLEN]; - ZeroMemory(callbackLongPath, sizeof(callbackLongPath)); - NS_tchar *targetPath = argv[callbackIndex]; - NS_tchar buffer[MAXPATHLEN * 2] = { NS_T('\0') }; - size_t bufferLeft = MAXPATHLEN * 2; - if (sReplaceRequest) - { - // In case of replace requests, we should look for the callback file in - // the destination directory. - size_t commonPrefixLength = PathCommonPrefixW(argv[callbackIndex], - gInstallDirPath, - nullptr); - NS_tchar *p = buffer; - NS_tstrncpy(p, argv[callbackIndex], commonPrefixLength); - p += commonPrefixLength; - bufferLeft -= commonPrefixLength; - NS_tstrncpy(p, gInstallDirPath + commonPrefixLength, bufferLeft); - - size_t len = NS_tstrlen(gInstallDirPath + commonPrefixLength); - p += len; - bufferLeft -= len; - *p = NS_T('\\'); - ++p; - bufferLeft--; - *p = NS_T('\0'); - NS_tchar installDir[MAXPATHLEN]; - NS_tstrcpy(installDir, gInstallDirPath); - size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex], - installDir, - nullptr); - NS_tstrncpy(p, argv[callbackIndex] + std::max(callbackPrefixLength, - commonPrefixLength), bufferLeft); - targetPath = buffer; - } - if (!GetLongPathNameW(targetPath, callbackLongPath, - sizeof(callbackLongPath)/sizeof(callbackLongPath[0]))) - { - LOG(("NS_main: unable to find callback file: " LOG_S, targetPath)); - LogFinish(); - WriteStatusFile(WRITE_ERROR_CALLBACK_PATH); - EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); - if (argc > callbackIndex) - { - LaunchCallbackApp(argv[5], - argc - callbackIndex, - argv + callbackIndex, - sUsingService); - } - return 1; - } - - // Doing this is only necessary when we're actually applying a patch. - if (!sReplaceRequest) - { - int len = NS_tstrlen(applyDirLongPath); - NS_tchar *s = callbackLongPath; - NS_tchar *d = gCallbackRelPath; - // advance to the apply to directory and advance past the trailing backslash - // if present. - s += len; - if (*s == NS_T('\\')) - ++s; - - // Copy the string and replace backslashes with forward slashes along the - // way. - do - { - if (*s == NS_T('\\')) - *d = NS_T('/'); - else - *d = *s; - ++s; - ++d; - } - while (*s); - *d = NS_T('\0'); - ++d; - - // Make a copy of the callback executable so it can be read when patching. - NS_tsnprintf(gCallbackBackupPath, - sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]), - NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]); - NS_tremove(gCallbackBackupPath); - 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); - } - - EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); - LaunchCallbackApp(argv[callbackIndex], - argc - callbackIndex, - argv + callbackIndex, - sUsingService); - return 1; - } - - // 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); - } - 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 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 /* _WIN32 */ - - // 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(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 /* _WIN32 */ - - -#ifdef MACOSX - // When the update is successful remove the precomplete file in the root of - // the application bundle and move the distribution directory from - // Contents/MacOS to Contents/Resources and if both exist delete the - // directory under Contents/MacOS (see Bug 1068439). - if (gSucceeded && !sStagedUpdate) - { - NS_tchar oldPrecomplete[MAXPATHLEN]; - NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]), - NS_T("%s/precomplete"), gInstallDirPath); - NS_tremove(oldPrecomplete); - - NS_tchar oldDistDir[MAXPATHLEN]; - NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]), - NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath); - int rv = NS_taccess(oldDistDir, F_OK); - if (!rv) - { - NS_tchar newDistDir[MAXPATHLEN]; - NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]), - NS_T("%s/Contents/Resources/distribution"), gInstallDirPath); - rv = NS_taccess(newDistDir, F_OK); - if (!rv) - { - LOG(("New distribution directory already exists... removing old " \ - "distribution directory: " LOG_S, oldDistDir)); - rv = ensure_remove_recursive(oldDistDir); - if (rv) - { - LOG(("Removing old distribution directory failed - err: %d", rv)); - } - } - else - { - LOG(("Moving old distribution directory to new location. src: " LOG_S \ - ", dst:" LOG_S, oldDistDir, newDistDir)); - rv = rename_file(oldDistDir, newDistDir, true); - if (rv) - { - LOG(("Moving old distribution directory to new location failed - " \ - "err: %d", rv)); - } - } - } - } - - 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(); - - int retVal = LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex -#ifdef _WIN32 - , elevatedLockFilePath - , updateLockFileHandle -#elif defined(MACOSX) - , isElevated -#endif - ); - - return retVal ? retVal : (gSucceeded ? 0 : 1); -} - -class ActionList -{ -public: - ActionList() : mFirst(nullptr), mLast(nullptr), mCount(0) { } - ~ActionList(); - - void Append(Action* action); - int Prepare(); - int Execute(); - void Finish(int status); - -private: - Action *mFirst; - Action *mLast; - int mCount; -}; - -ActionList::~ActionList() -{ - Action* a = mFirst; - while (a) - { - Action *b = a; - a = a->mNext; - delete b; - } -} - -void -ActionList::Append(Action *action) -{ - if (mLast) - mLast->mNext = action; - else - mFirst = action; - - mLast = action; - mCount++; -} - -int -ActionList::Prepare() -{ - // If the action list is empty then we should fail in order to signal that - // something has gone wrong. Otherwise we report success when nothing is - // actually done. See bug 327140. - if (mCount == 0) - { - LOG(("empty action list")); - return MAR_ERROR_EMPTY_ACTION_LIST; - } - - Action *a = mFirst; - int i = 0; - while (a) - { - int rv = a->Prepare(); - if (rv) - return rv; - - float percent = float(++i) / float(mCount); - UpdateProgressUI(PROGRESS_PREPARE_SIZE * percent); - - a = a->mNext; - } - - return OK; -} - -int -ActionList::Execute() -{ - int currentProgress = 0, maxProgress = 0; - Action *a = mFirst; - while (a) - { - maxProgress += a->mProgressCost; - a = a->mNext; - } - - a = mFirst; - while (a) - { - int rv = a->Execute(); - if (rv) - { - LOG(("### execution failed")); - return rv; - } - - currentProgress += a->mProgressCost; - float percent = float(currentProgress) / float(maxProgress); - UpdateProgressUI(PROGRESS_PREPARE_SIZE + - PROGRESS_EXECUTE_SIZE * percent); - - a = a->mNext; - } - - return OK; -} - -void -ActionList::Finish(int status) -{ - Action *a = mFirst; - int i = 0; - while (a) - { - a->Finish(status); - - float percent = float(++i) / float(mCount); - UpdateProgressUI(PROGRESS_PREPARE_SIZE + - PROGRESS_EXECUTE_SIZE + - PROGRESS_FINISH_SIZE * percent); - - a = a->mNext; - } - - if (status == OK) - gSucceeded = true; -} - - -#ifdef _WIN32 -int add_dir_entries(const NS_tchar *dirpath, ActionList *list) -{ - int rv = OK; - WIN32_FIND_DATAW finddata; - HANDLE hFindFile; - NS_tchar searchspec[MAXPATHLEN]; - NS_tchar foundpath[MAXPATHLEN]; - - NS_tsnprintf(searchspec, sizeof(searchspec)/sizeof(searchspec[0]), - NS_T("%s*"), dirpath); - std::unique_ptr<const NS_tchar[]> pszSpec(new_absolute_path(searchspec)); - - hFindFile = FindFirstFileW(pszSpec.get(), &finddata); - if (hFindFile != INVALID_HANDLE_VALUE) - { - do - { - // Don't process the current or parent directory. - if (NS_tstrcmp(finddata.cFileName, NS_T(".")) == 0 || - NS_tstrcmp(finddata.cFileName, NS_T("..")) == 0) - continue; - - NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]), - NS_T("%s%s"), dirpath, finddata.cFileName); - if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]), - NS_T("%s/"), foundpath); - // Recurse into the directory. - rv = add_dir_entries(foundpath, list); - if (rv) - { - LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv)); - return rv; - } - } - else - { - // Add the file to be removed to the ActionList. - NS_tchar *quotedpath = get_quoted_path(foundpath); - if (!quotedpath) - return PARSE_ERROR; - - Action *action = new RemoveFile(); - rv = action->Parse(quotedpath); - if (rv) - { - LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d", - quotedpath, rv)); - return rv; - } - free(quotedpath); - - list->Append(action); - } - } - while (FindNextFileW(hFindFile, &finddata) != 0); - - FindClose(hFindFile); - { - // Add the directory to be removed to the ActionList. - NS_tchar *quotedpath = get_quoted_path(dirpath); - if (!quotedpath) - return PARSE_ERROR; - - Action *action = new RemoveDir(); - rv = action->Parse(quotedpath); - if (rv) - LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d", - quotedpath, rv)); - else - list->Append(action); - free(quotedpath); - } - } - - return rv; -} - -#elif defined(__sun) -int add_dir_entries(const NS_tchar *dirpath, ActionList *list) -{ - int rv = OK; - NS_tchar foundpath[MAXPATHLEN]; - struct - { - dirent dent_buffer; - char chars[MAXNAMLEN]; - } ent_buf; - struct dirent* ent; - std::unique_ptr<NS_tchar[]> searchpath(new_absolute_path(dirpath)); - - DIR* dir = opendir(searchpath.get()); - if (!dir) - { - LOG(("add_dir_entries error on opendir: " LOG_S ", err: %d", searchpath.get(), - errno)); - return UNEXPECTED_FILE_OPERATION_ERROR; - } - - while (readdir_r(dir, (dirent *)&ent_buf, &ent) == 0 && ent) - { - if ((strcmp(ent->d_name, ".") == 0) || - (strcmp(ent->d_name, "..") == 0)) - continue; - - NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]), - NS_T("%s%s"), searchpath.get(), ent->d_name); - struct stat64 st_buf; - int test = stat64(foundpath, &st_buf); - if (test) - { - closedir(dir); - return UNEXPECTED_FILE_OPERATION_ERROR; - } - if (S_ISDIR(st_buf.st_mode)) - { - NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]), - NS_T("%s/"), foundpath); - // Recurse into the directory. - rv = add_dir_entries(foundpath, list); - if (rv) - { - LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv)); - closedir(dir); - return rv; - } - } - else - { - // Add the file to be removed to the ActionList. - NS_tchar *quotedpath = get_quoted_path(get_relative_offset(foundpath)); - if (!quotedpath) - { - closedir(dir); - return PARSE_ERROR; - } - - Action *action = new RemoveFile(); - rv = action->Parse(quotedpath); - if (rv) - { - LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d", - quotedpath, rv)); - closedir(dir); - return rv; - } - - list->Append(action); - } - } - closedir(dir); - - // Add the directory to be removed to the ActionList. - NS_tchar *quotedpath = get_quoted_path(get_relative_offset(dirpath)); - if (!quotedpath) - return PARSE_ERROR; - - Action *action = new RemoveDir(); - rv = action->Parse(quotedpath); - if (rv) - { - LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d", - quotedpath, rv)); - } - else - { - list->Append(action); - } - - return rv; -} - -#else - -int add_dir_entries(const NS_tchar *dirpath, ActionList *list) -{ - int rv = OK; - FTS *ftsdir; - FTSENT *ftsdirEntry; - std::unique_ptr<NS_tchar[]> searchpath(new_absolute_path(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.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. - if (!(ftsdir = fts_open(pathargv, - FTS_PHYSICAL | FTS_NOSTAT | FTS_XDEV | FTS_NOCHDIR, - nullptr))) - return UNEXPECTED_FILE_OPERATION_ERROR; - - while ((ftsdirEntry = fts_read(ftsdir)) != nullptr) - { - NS_tchar foundpath[MAXPATHLEN]; - NS_tchar *quotedpath = nullptr; - Action *action = nullptr; - - switch (ftsdirEntry->fts_info) - { - // Filesystem objects that shouldn't be in the application's directories - case FTS_SL: - case FTS_SLNONE: - case FTS_DEFAULT: - LOG(("add_dir_entries: found a non-standard file: " LOG_S, - ftsdirEntry->fts_path)); - /* Fall through */ // and try to remove as a file - - // Files - case FTS_F: - case FTS_NSOK: - // 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(get_relative_offset(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; - - // Directories - case FTS_DP: - rv = OK; - // 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(get_relative_offset(foundpath)); - if (!quotedpath) - { - rv = UPDATER_QUOTED_PATH_MEM_ERROR; - break; - } - - action = new RemoveDir(); - rv = action->Parse(quotedpath); - free(quotedpath); - if (!rv) - list->Append(action); - break; - - // Errors - case FTS_DNR: - case FTS_NS: - // ENOENT is an acceptable error for FTS_DNR and FTS_NS and means that - // we're racing with ourselves. Though strange, the entry will be - // removed anyway. - if (ENOENT == ftsdirEntry->fts_errno) - { - rv = OK; - break; - } - // Fall through - - case FTS_ERR: - rv = UNEXPECTED_FILE_OPERATION_ERROR; - LOG(("add_dir_entries: fts_read() error: " LOG_S ", err: %d", - ftsdirEntry->fts_path, ftsdirEntry->fts_errno)); - break; - - case FTS_DC: - rv = UNEXPECTED_FILE_OPERATION_ERROR; - LOG(("add_dir_entries: fts_read() returned FT_DC: " LOG_S, - ftsdirEntry->fts_path)); - break; - - default: - // FTS_D is ignored and FTS_DP is used instead (post-order). - rv = OK; - break; - } - - if (rv != OK) - break; - } - - fts_close(ftsdir); - - return rv; -} -#endif - -static NS_tchar* -GetManifestContents(const NS_tchar *manifest) -{ - AutoFile mfile(NS_tfopen(manifest, NS_T("rb"))); - if (mfile == nullptr) - { - LOG(("GetManifestContents: error opening manifest file: " LOG_S, manifest)); - return nullptr; - } - - struct stat ms; - int rv = fstat(fileno((FILE *)mfile), &ms); - if (rv) - { - LOG(("GetManifestContents: error stating manifest file: " LOG_S, manifest)); - return nullptr; - } - - char *mbuf = (char *) malloc(ms.st_size + 1); - if (!mbuf) - return nullptr; - - size_t r = ms.st_size; - char *rb = mbuf; - while (r) - { - const size_t count = std::min<size_t>(SSIZE_MAX, r); - size_t c = fread(rb, 1, count, mfile); - if (c != count) - { - LOG(("GetManifestContents: error reading manifest file: " LOG_S, manifest)); - free(mbuf); - return nullptr; - } - - r -= c; - rb += c; - } - mbuf[ms.st_size] = '\0'; - rb = mbuf; - -#ifndef _WIN32 - return rb; -#else - NS_tchar *wrb = (NS_tchar *) malloc((ms.st_size + 1) * sizeof(NS_tchar)); - if (!wrb) - { - free(mbuf); - return nullptr; - } - - if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, rb, -1, wrb, - ms.st_size + 1)) - { - LOG(("GetManifestContents: error converting utf8 to utf16le: %d", GetLastError())); - free(mbuf); - free(wrb); - return nullptr; - } - free(mbuf); - - return wrb; -#endif -} - -int AddPreCompleteActions(ActionList *list) -{ -#ifdef MACOSX - std::unique_ptr<NS_tchar[]> manifestPath(new_absolute_path( - NS_T("Contents/Resources/precomplete"))); -#else - std::unique_ptr<NS_tchar[]> manifestPath(new_absolute_path( - NS_T("precomplete"))); -#endif - - NS_tchar *rb = GetManifestContents(manifestPath.get()); - if (rb == nullptr) - { - LOG(("AddPreCompleteActions: error getting contents of precomplete " \ - "manifest")); - // Applications aren't required to have a precomplete manifest. The mar - // generation scripts enforce the presence of a precomplete manifest. - return OK; - } - - int rv; - NS_tchar *line; - while ((line = mstrtok(kNL, &rb)) != 0) - { - // skip comments - if (*line == NS_T('#')) - continue; - - NS_tchar *token = mstrtok(kWhitespace, &line); - if (!token) - { - LOG(("AddPreCompleteActions: token not found in manifest")); - return PARSE_ERROR; - } - - Action *action = nullptr; - if (NS_tstrcmp(token, NS_T("remove")) == 0) // rm file - { - action = new RemoveFile(); - } - else if (NS_tstrcmp(token, NS_T("remove-cc")) == 0) // no longer supported - { - continue; - } - else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) // rmdir if empty - { - action = new RemoveDir(); - } - else - { - LOG(("AddPreCompleteActions: unknown token: " LOG_S, token)); - return PARSE_ERROR; - } - - if (!action) - return BAD_ACTION_ERROR; - - rv = action->Parse(line); - if (rv) - return rv; - - list->Append(action); - } - - return OK; -} - -int DoUpdate(ArchiveReader& archiveReader) -{ - NS_tchar manifest[MAXPATHLEN]; - int nWrittenBytes = NS_tsnprintf(manifest, sizeof(manifest)/sizeof(manifest[0]), - NS_T("%s/updating/update.manifest"), gWorkingDirPath); - (void) nWrittenBytes; - ensure_parent_dir(manifest); - - // extract the manifest - // TODO: moggi: needs adaptation for LibreOffice - // Why would we need the manifest? Even if we need it why would we need 2? - int rv = archiveReader.ExtractFile("updatev3.manifest", manifest); - if (rv) - { - rv = archiveReader.ExtractFile("updatev2.manifest", manifest); - if (rv) - { - LOG(("DoUpdate: error extracting manifest file")); - return rv; - } - } - - NS_tchar *rb = GetManifestContents(manifest); - NS_tremove(manifest); - if (rb == nullptr) - { - LOG(("DoUpdate: error opening manifest file: " LOG_S, manifest)); - return READ_ERROR; - } - - ActionList list; - NS_tchar *line; - bool isFirstAction = true; - - while ((line = mstrtok(kNL, &rb)) != 0) - { - // skip comments - if (*line == NS_T('#')) - continue; - - NS_tchar *token = mstrtok(kWhitespace, &line); - if (!token) - { - LOG(("DoUpdate: token not found in manifest")); - return PARSE_ERROR; - } - - if (isFirstAction) - { - isFirstAction = false; - // The update manifest isn't required to have a type declaration. The mar - // generation scripts enforce the presence of the type declaration. - if (NS_tstrcmp(token, NS_T("type")) == 0) - { - const NS_tchar *type = mstrtok(kQuote, &line); - LOG(("UPDATE TYPE " LOG_S, type)); - if (NS_tstrcmp(type, NS_T("complete")) == 0) - { - rv = AddPreCompleteActions(&list); - if (rv) - return rv; - } - continue; - } - } - - Action *action = nullptr; - if (NS_tstrcmp(token, NS_T("remove")) == 0) // rm file - { - action = new RemoveFile(); - } - else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) // rmdir if empty - { - action = new RemoveDir(); - } - else if (NS_tstrcmp(token, NS_T("rmrfdir")) == 0) // rmdir recursive - { - const NS_tchar *reldirpath = mstrtok(kQuote, &line); - if (!reldirpath) - return PARSE_ERROR; - - if (reldirpath[NS_tstrlen(reldirpath) - 1] != NS_T('/')) - return PARSE_ERROR; - - rv = add_dir_entries(reldirpath, &list); - if (rv) - return rv; - - continue; - } - else if (NS_tstrcmp(token, NS_T("add")) == 0) - { - action = new AddFile(archiveReader); - } - else if (NS_tstrcmp(token, NS_T("patch")) == 0) - { - action = new PatchFile(archiveReader); - } - else if (NS_tstrcmp(token, NS_T("add-if")) == 0) // Add if exists - { - action = new AddIfFile(archiveReader); - } - else if (NS_tstrcmp(token, NS_T("add-if-not")) == 0) // Add if not exists - { - action = new AddIfNotFile(archiveReader); - } - else if (NS_tstrcmp(token, NS_T("patch-if")) == 0) // Patch if exists - { - action = new PatchIfFile(archiveReader); - } - else - { - LOG(("DoUpdate: unknown token: " LOG_S, token)); - return PARSE_ERROR; - } - - if (!action) - return BAD_ACTION_ERROR; - - rv = action->Parse(line); - if (rv) - return rv; - - list.Append(action); - } - - rv = list.Prepare(); - if (rv) - return rv; - - rv = list.Execute(); - - list.Finish(rv); - return rv; -} diff --git a/onlineupdate/source/update/updater/updater.exe.comctl32.manifest b/onlineupdate/source/update/updater/updater.exe.comctl32.manifest deleted file mode 100644 index 9a6cdb565fe1..000000000000 --- a/onlineupdate/source/update/updater/updater.exe.comctl32.manifest +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> -<assemblyIdentity - version="1.0.0.0" - processorArchitecture="*" - name="Updater" - type="win32" -/> -<description>Updater</description> -<dependency> - <dependentAssembly> - <assemblyIdentity - type="win32" - name="Microsoft.Windows.Common-Controls" - version="6.0.0.0" - processorArchitecture="*" - publicKeyToken="6595b64144ccf1df" - language="*" - /> - </dependentAssembly> -</dependency> -<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"> - <ms_asmv3:security> - <ms_asmv3:requestedPrivileges> - <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" /> - </ms_asmv3:requestedPrivileges> - </ms_asmv3:security> -</ms_asmv3:trustInfo> - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> - <application> - <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> - <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> - <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> - <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> - <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> - </application> - </compatibility> -</assembly> diff --git a/onlineupdate/source/update/updater/updater.exe.manifest b/onlineupdate/source/update/updater/updater.exe.manifest deleted file mode 100644 index cd229c954109..000000000000 --- a/onlineupdate/source/update/updater/updater.exe.manifest +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> -<assemblyIdentity - version="1.0.0.0" - processorArchitecture="*" - name="Updater" - type="win32" -/> -<description>Updater</description> -<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"> - <ms_asmv3:security> - <ms_asmv3:requestedPrivileges> - <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" /> - </ms_asmv3:requestedPrivileges> - </ms_asmv3:security> -</ms_asmv3:trustInfo> - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> - <application> - <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> - <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> - <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> - <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> - <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> - </application> - </compatibility> -</assembly> diff --git a/onlineupdate/source/update/updater/updater.ico b/onlineupdate/source/update/updater/updater.ico Binary files differdeleted file mode 100644 index 7b20ba3ec3ce..000000000000 --- a/onlineupdate/source/update/updater/updater.ico +++ /dev/null diff --git a/onlineupdate/source/update/updater/updater.png b/onlineupdate/source/update/updater/updater.png Binary files differdeleted file mode 100644 index 9d8c6df7789a..000000000000 --- a/onlineupdate/source/update/updater/updater.png +++ /dev/null diff --git a/onlineupdate/source/update/updater/updater.rc b/onlineupdate/source/update/updater/updater.rc deleted file mode 100644 index d77cea2fee90..000000000000 --- a/onlineupdate/source/update/updater/updater.rc +++ /dev/null @@ -1,137 +0,0 @@ -/* 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/. */ - -// Microsoft Visual C++ generated resource script. -// -#ifdef TEST_UPDATER -#include "../resource.h" -#define MANIFEST_PATH "../updater.exe.manifest" -#define COMCTL32_MANIFEST_PATH "../updater.exe.comctl32.manifest" -#define ICON_PATH "../updater.ico" -#else -#include "resource.h" -#define MANIFEST_PATH "updater.exe.manifest" -#define COMCTL32_MANIFEST_PATH "updater.exe.comctl32.manifest" -#define ICON_PATH "updater.ico" -#endif - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winresrc.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -1 RT_MANIFEST MANIFEST_PATH -IDR_COMCTL32_MANIFEST RT_MANIFEST COMCTL32_MANIFEST_PATH - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -IDI_DIALOG ICON ICON_PATH - - -///////////////////////////////////////////////////////////////////////////// -// -// Embedded an identifier to uniquely identify this as a Mozilla updater. -// - -STRINGTABLE -{ - IDS_UPDATER_IDENTITY, "libreoffice-updater.exe-7bab28a0-0599-4f37-9efe-f7f8b71f05e3" -} - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_DIALOG DIALOGEX 0, 0, 253, 41 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,24,239,10 - LTEXT "",IDC_INFO,7,8,239,13,SS_NOPREFIX -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_DIALOG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 246 - TOPMARGIN, 7 - BOTTOMMARGIN, 39 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winresrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/onlineupdate/source/update/updater/updater.svg b/onlineupdate/source/update/updater/updater.svg deleted file mode 100644 index 6a3e88563283..000000000000 --- a/onlineupdate/source/update/updater/updater.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="32" viewBox="0 0 32 32.000001" width="32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><radialGradient id="a" cx="5" cy="13.375" gradientTransform="matrix(2.6502653 .00000002 0 1.1249099 -5.937606 7.116442)" gradientUnits="userSpaceOnUse" r="5" xlink:href="#b"/><linearGradient id="b"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff" stop-opacity=".487603"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="312.625" x2="312.0625" xlink:href="#d" y1="196.541335" y2="191.797335"/><linearGradient id="d"><stop offset="0"/><stop offset="1" stop-opacity="0"/></linearGradient><filter id="e" color-interpolation-filters="sRGB" height="1.588154" width="1.259382" x="-.129691" y="-.294077"><feGaussianBlur stdDeviation=".86460582"/></filter><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="17.92817" x2="17.92817" y1="8.43984" y2="5.29526"><stop offset="0" stop-color="#e9b96e"/><stop offset="1" stop-color="#eeeeec"/></linearGradient><linearGradient id="g" gradientTransform="matrix(.06998908 0 0 .06896555 12.18409 2.80365)" gradientUnits="userSpaceOnUse" x1="174.01562" x2="30" y1="236" y2="64"><stop offset="0" stop-color="#c17d11"/><stop offset="1" stop-color="#e9b96e"/></linearGradient><radialGradient id="h" cx="321.86331" cy="70.499977" gradientTransform="matrix(.6227245 0 0 .09677408 -177.2342 3.75694)" gradientUnits="userSpaceOnUse" r="15.500023"><stop offset="0" stop-color="#faefde"/><stop offset=".68321055" stop-color="#e9b96e"/><stop offset="1" stop-color="#e9b96e" stop-opacity="0"/></radialGradient><radialGradient id="i" cx="321.7785" cy="91.857727" gradientTransform="matrix(2.0837843 0 0 .3006166 -644.48535 -10.03444)" gradientUnits="userSpaceOnUse" r="15.5"><stop offset="0" stop-color="#e9b96e"/><stop offset="1" stop-color="#e9b96e" stop-opacity="0"/></radialGradient><radialGradient id="j" cx="323.89844" cy="70.5" gradientTransform="matrix(.3715153 0 0 .3516126 -97.26516 -14.20919)" gradientUnits="userSpaceOnUse" r="15.5" xlink:href="#b"/><linearGradient id="k" gradientTransform="matrix(.3791614 0 0 .6106884 -99.96394 -32.72591)" gradientUnits="userSpaceOnUse" x1="316.90683" x2="322.41666" xlink:href="#d" y1="69.553268" y2="69.553268"/><linearGradient id="l" gradientTransform="matrix(.970062 -.2428574 0 1 -362.71624 -176.92048)" gradientUnits="userSpaceOnUse" x1="394.59244" x2="389.02057" y1="277.23956" y2="280.54391"><stop offset="0" stop-color="#eeeeec"/><stop offset="1" stop-color="#e9b96e"/></linearGradient><linearGradient id="m" gradientTransform="matrix(.3925197 0 0 .6106884 -104.79786 -32.72591)" gradientUnits="userSpaceOnUse" x1="333.88629" x2="326.32867" xlink:href="#d" y1="69.490768" y2="69.490768"/><linearGradient id="n" gradientTransform="matrix(1.0000001 1.0190348 0 1.0165713 -342.71627 -558.00916)" gradientUnits="userSpaceOnUse" x1="373.8385" x2="375.07596" y1="187.7484" y2="181.79832"><stop offset="0" stop-color="#e9b96e"/><stop offset="1" stop-color="#c17d11"/></linearGradient><linearGradient id="o" gradientUnits="userSpaceOnUse" x1="19.53376" x2="22.28376" xlink:href="#b" y1="14.70452" y2="5.98577"/><linearGradient id="p" gradientUnits="userSpaceOnUse" x1="24.81501" x2="27.63508" xlink:href="#b" y1="5.51702" y2="7.37133"/><linearGradient id="q" gradientTransform="matrix(.970062 -.2428574 0 1 -362.71624 -176.92048)" gradientUnits="userSpaceOnUse" x1="391.0188" x2="389.73026" xlink:href="#b" y1="277.72043" y2="279.4614"/><filter id="r" color-interpolation-filters="sRGB" height="1.86087" width="1.2475" x="-.12375" y="-.430435"><feGaussianBlur stdDeviation=".515625"/></filter><radialGradient id="s" cx="5" cy="13.375" gradientTransform="matrix(2.6502653 .00000002 0 1.1249099 1.062394 13.293218)" gradientUnits="userSpaceOnUse" r="5" xlink:href="#b"/><linearGradient id="t" gradientTransform="matrix(1.2807984 0 0 1.2807976 -376.53809 -266.21095)" gradientUnits="userSpaceOnUse" x1="305.62964" x2="299.38138" y1="222.08656" y2="217.11935"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#babdb6"/></linearGradient><rect fill="url(#c)" filter="url(#e)" height="7.056155" opacity=".753425" rx="1.3125" transform="matrix(1.0441942 0 0 1 -306.59321 -176.92048)" width="16" x="306" y="190.17233"/><rect filter="url(#r)" height="2.875" opacity=".579208" rx="1.25" ry="1.4375" transform="matrix(1.15 0 0 1 -591.83312 5.636224)" width="10" x="515.875" y="16.625"/><rect fill="#d9a452" fill-rule="evenodd" height="8.000001" rx=".09427" ry=".094274" stroke="#8f5902" width="9.015612" x="2.798108" y="16.474611"/><rect fill="#e8c48d" fill-rule="evenodd" height="4.1875" rx=".09427" ry=".094274" transform="scale(-1 1)" width="8.125" x="-11.37622" y="16.912111"/><path d="m3.75122 17.412112v6.125h7.125v-6.125z" fill="none" opacity=".439759" stroke="url(#a)"/><path d="m4.2582637 17.108049 7.3125003-.151651-.170181.91895-6.9783737.173896-.1639456 2.064009 7.0710683-.08839.08839 1.149048-8.1317282-.08839-.088388-4.154253z" fill="#f5efe4" fill-rule="evenodd"/><rect filter="url(#r)" height="2.875" opacity=".579208" rx="1.25" ry="1.4375" transform="matrix(1.15 0 0 1 -584.83312 11.636224)" width="10" x="515.875" y="16.625"/><rect fill="#d9a452" fill-rule="evenodd" height="8.000001" rx=".09427" ry=".094274" stroke="#8f5902" width="9.015612" x="9.798108" y="22.651388"/><rect fill="#e8c48d" fill-rule="evenodd" height="4.1875" rx=".09427" ry=".094274" transform="scale(-1 1)" width="8.125" x="-18.376221" y="23.088888"/><path d="m10.75122 23.588888v6.125h7.125v-6.125z" fill="none" opacity=".439759" stroke="url(#s)"/><path d="m11.258264 23.284825 7.3125-.151651-7.18713.986747-.12537 2.170108 7.071068-.08839.08839 1.149048-8.131727-.08839-.08839-4.154253 1.060661.176777z" fill="#f5efe4" fill-rule="evenodd"/><rect fill="url(#f)" height="14.999985" rx="1.016466" stroke="#8f5902" stroke-dashoffset=".5" stroke-linecap="round" stroke-linejoin="round" width="15" x="13.78376" y="4.579536"/><path d="m18.28175 8.07952h7.90593v1.00676h-7.90593z" fill="#fff" opacity=".2"/><path d="m14.7037 10.07952c-.23265 0-.41994.18455-.41994.41378v7.89657.27586c0 .22924.18729.41379.41994.41379h13.16012c.23265 0 .41994-.18455.41994-.41379v-8.17243c0-.22923-.18729-.41378-.41994-.41378z" fill="url(#g)" fill-rule="evenodd"/><path d="m14.78376 5.57952h13v13.00002h-13z" style="opacity:.342342;fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:.5;stroke:url(#o)"/><path d="m14.34513 9.07952-.0562 2.96875 13.98983.0312-.0562-3h-13.87753z" fill="url(#h)" fill-rule="evenodd" opacity=".5"/><path d="m14.7037 10.07952c-.23265 0-.41994.18454-.41994.41379v7.89655.27587c0 .22925.18729.41379.41994.41379h13.16012c.23265 0 .41994-.18455.41994-.41379v-8.17242c0-.22925-.18729-.41379-.41994-.41379z" fill="url(#i)" fill-rule="evenodd" opacity=".815315"/><path d="m14.28376 10.07952h14v1h-14z" fill="url(#j)" opacity=".747748"/><path d="m18.28175 7.07952h6.18718v1.00676h-6.18718z" fill="#c17d11" opacity=".40991"/><path d="m16.3849 5.07952c-.0485 0-.0757.0294-.11659.11449-.0409.0851-.0772.2227-.10363.3626l-.88092 4.52291h7v-5z" fill="url(#k)" fill-rule="evenodd" opacity=".468468"/><path d="m13.783748 9.4403349v-3.97196c0-.56176.453339-1.1275045 1.01646-1.2684833l4.955804-1.2406977c.563131-.1409811 1.01647.1977743 1.01647.7595343v3.97196c0 .56176-.453339 1.1275046-1.01647 1.2684857l-4.03474.6503971" fill="url(#l)" stroke="#8f5902" stroke-dashoffset=".5" stroke-linecap="round" stroke-linejoin="round"/><path d="m22.28376 5.07952v5h5l-.99706-4.59925c-.0288-.13456-.0614-.26033-.10264-.32442-.04126-.06408-.0783-.07633-.14664-.07633z" fill="url(#m)" fill-rule="evenodd" opacity=".468468"/><path d="m28.78376 10.14202v-4.03125c0-.57245-.46814-1.48866-1.03125-2.0625l-2.9375-3.03125s-.48496-.76809-1.71875-.4375c-.18373-.00045-.3125.15128-.3125.4375v4.03125c0 .57245.46812 1.48866 1.03125 2.0625l3.00562 2.51312" fill="url(#n)" stroke="#8f5902" stroke-dashoffset=".5" stroke-linecap="round" stroke-linejoin="round"/><path d="m13.271484 6.2226562c-5.2651384 1.0467841-9.271484 5.7180798-9.271484 11.2773438 0 6.321666 5.1783326 11.5 11.5 11.5 6.321667 0 11.5-5.178334 11.5-11.5 0-4.428937-2.546314-8.2880167-6.242188-10.2070312v6.3710932c.779838 1.072341 1.242188 2.393081 1.242188 3.835938 0 3.619464-2.880531 6.5-6.5 6.5s-6.5-2.880536-6.5-6.5c0-2.833183 1.768714-5.206891 4.271484-6.107422z" fill="#888a85"/><g fill="none"><g stroke-linecap="round"><path d="m23.75251 1.52093v3.52734c0 .0439.36048.96696.74609 1.37109l2.77344 2.31055.54297.14649v-2.76563c0-.0443-.36385-.98728-.75391-1.38477a.96884687.96884687 0 0 1 -.004-.004l-2.9375-3.03125a.96884687.96884687 0 0 1 -.12305-.15625s.0335.0321-.043-.01c-.0253-.0139-.15681.009-.20117-.004z" opacity=".572072" stroke="url(#p)" stroke-dashoffset=".5" stroke-linejoin="round"/><path d="m23.69001 1.32952c.14068 1.70518-.31678 3.76924.5625 5.03125" opacity=".414414" stroke="#fff"/><path d="m14.819765 5.2499556v3.16797l1.115949.097569 3.794989-.6258648v-3.86914z" opacity=".716216" stroke="url(#q)" stroke-dashoffset=".5"/></g><path d="m24.78174 9.58626h-5v5" stroke="#888a85" stroke-linecap="square" stroke-width="5"/></g><path d="m13.322266 7.2519531c-4.740376 1.0081786-8.322266 5.2153889-8.322266 10.2480469 0 5.781225 4.7187725 10.5 10.5 10.5 5.781228 0 10.5-4.718775 10.5-10.5 0-4.918766-3.420176-9.0588504-8-10.1875v3.119141c2.91831 1.024849 5 3.787879 5 7.068359 0 4.159904-3.340092 7.499999-7.5 7.5-4.159908 0-7.5-3.340096-7.5-7.5 0-3.399893 2.235404-6.239226 5.322266-7.166016z" fill="url(#t)"/><path d="m24.78174 9.58626h-5v5" fill="none" stroke="#fff" stroke-linecap="square" stroke-width="3"/><path d="m17.281748 7.0863v1 6h1v-6h7v-1h-7z" fill="#888a85"/></svg>
\ No newline at end of file diff --git a/onlineupdate/source/update/updater/win_dirent.cxx b/onlineupdate/source/update/updater/win_dirent.cxx deleted file mode 100644 index 2368613ee42b..000000000000 --- a/onlineupdate/source/update/updater/win_dirent.cxx +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifdef _WIN32 -#include "win_dirent.h" -#include <errno.h> -#include <string.h> - -// This file implements the minimum set of dirent APIs used by updater.cpp on -// Windows. If updater.cpp is modified to use more of this API, we need to -// implement those parts here too. - -static dirent gDirEnt; - -DIR::DIR(const WCHAR* path) - : findHandle(INVALID_HANDLE_VALUE) -{ - memset(name, 0, sizeof(name)); - wcsncpy(name, path, sizeof(name)/sizeof(name[0])); - wcsncat(name, L"\\*", sizeof(name)/sizeof(name[0]) - wcslen(name) - 1); -} - -DIR::~DIR() -{ - if (findHandle != INVALID_HANDLE_VALUE) - { - FindClose(findHandle); - } -} - -dirent::dirent() -{ - d_name[0] = L'\0'; -} - -DIR* -opendir(const WCHAR* path) -{ - return new DIR(path); -} - -int -closedir(DIR* dir) -{ - delete dir; - return 0; -} - -dirent* readdir(DIR* dir) -{ - WIN32_FIND_DATAW data; - if (dir->findHandle != INVALID_HANDLE_VALUE) - { - BOOL result = FindNextFileW(dir->findHandle, &data); - if (!result) - { - if (GetLastError() != ERROR_FILE_NOT_FOUND) - { - errno = ENOENT; - } - return 0; - } - } - else - { - // Reading the first directory entry - dir->findHandle = FindFirstFileW(dir->name, &data); - if (dir->findHandle == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - { - errno = ENOENT; - } - else - { - errno = EBADF; - } - return 0; - } - } - memset(gDirEnt.d_name, 0, sizeof(gDirEnt.d_name)); - wcsncpy(gDirEnt.d_name, data.cFileName, - sizeof(gDirEnt.d_name)/sizeof(gDirEnt.d_name[0])); - return &gDirEnt; -} -#endif diff --git a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx deleted file mode 100644 index 17ee57ec400f..000000000000 --- a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx +++ /dev/null @@ -1,429 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVersionComparator.h" - -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#if defined(_WIN32) && !defined(UPDATER_NO_STRING_GLUE_STL) -#include <wchar.h> -#include "Char16.h" -#endif - -#ifdef _WIN32 -// from Mozilla's nsAlgorithm.h -template <class T> inline const T& XPCOM_MIN(const T& aA, const T& aB) { return aB < aA ? aB : aA; } -#endif - -struct VersionPart -{ - int32_t numA; - - const char* strB; // NOT null-terminated, can be a null pointer - uint32_t strBlen; - - int32_t numC; - - char* extraD; // null-terminated -}; - -#ifdef _WIN32 -struct VersionPartW -{ - int32_t numA; - - wchar_t* strB; // NOT null-terminated, can be a null pointer - uint32_t strBlen; - - int32_t numC; - - wchar_t* extraD; // null-terminated -}; -#endif - -/** - * Parse a version part into a number and "extra text". - * - * @returns A pointer to the next versionpart, or null if none. - */ -static char* ParseVP(char* aPart, VersionPart& aResult) -{ - char* dot; - - aResult.numA = 0; - aResult.strB = nullptr; - aResult.strBlen = 0; - aResult.numC = 0; - aResult.extraD = nullptr; - - if (!aPart) - { - return aPart; - } - - dot = strchr(aPart, '.'); - if (dot) - { - *dot = '\0'; - } - - if (aPart[0] == '*' && aPart[1] == '\0') - { - aResult.numA = INT32_MAX; - aResult.strB = ""; - } - else - { - aResult.numA = strtol(aPart, const_cast<char**>(&aResult.strB), 10); - } - - if (!*aResult.strB) - { - aResult.strB = nullptr; - aResult.strBlen = 0; - } - else - { - if (aResult.strB[0] == '+') - { - static const char kPre[] = "pre"; - - ++aResult.numA; - aResult.strB = kPre; - aResult.strBlen = sizeof(kPre) - 1; - } - else - { - const char* numstart = strpbrk(aResult.strB, "0123456789+-"); - if (!numstart) - { - aResult.strBlen = strlen(aResult.strB); - } - else - { - aResult.strBlen = numstart - aResult.strB; - - aResult.numC = strtol(numstart, &aResult.extraD, 10); - if (!*aResult.extraD) - { - aResult.extraD = nullptr; - } - } - } - } - - if (dot) - { - ++dot; - - if (!*dot) - { - dot = nullptr; - } - } - - return dot; -} - -/** - * Parse a version part into a number and "extra text". - * - * @returns A pointer to the next versionpart, or null if none. - */ -#ifdef _WIN32 -static wchar_t* ParseVP(wchar_t* aPart, VersionPartW& aResult) -{ - wchar_t* dot; - - aResult.numA = 0; - aResult.strB = nullptr; - aResult.strBlen = 0; - aResult.numC = 0; - aResult.extraD = nullptr; - - if (!aPart) - { - return aPart; - } - - dot = wcschr(aPart, '.'); - if (dot) - { - *dot = '\0'; - } - - if (aPart[0] == '*' && aPart[1] == '\0') - { - aResult.numA = INT32_MAX; - aResult.strB = L""; - } - else - { - aResult.numA = wcstol(aPart, const_cast<wchar_t**>(&aResult.strB), 10); - } - - if (!*aResult.strB) - { - aResult.strB = nullptr; - aResult.strBlen = 0; - } - else - { - if (aResult.strB[0] == '+') - { - static wchar_t kPre[] = L"pre"; - - ++aResult.numA; - aResult.strB = kPre; - aResult.strBlen = sizeof(kPre) - 1; - } - else - { - const wchar_t* numstart = wcspbrk(aResult.strB, L"0123456789+-"); - if (!numstart) - { - aResult.strBlen = wcslen(aResult.strB); - } - else - { - aResult.strBlen = numstart - aResult.strB; - - aResult.numC = wcstol(numstart, &aResult.extraD, 10); - if (!*aResult.extraD) - { - aResult.extraD = nullptr; - } - } - } - } - - if (dot) - { - ++dot; - - if (!*dot) - { - dot = nullptr; - } - } - - return dot; -} -#endif - -// compare two null-terminated strings, which may be null pointers -static int32_t ns_strcmp(const char* aStr1, const char* aStr2) -{ - // any string is *before* no string - if (!aStr1) - { - return aStr2 != 0; - } - - if (!aStr2) - { - return -1; - } - - return strcmp(aStr1, aStr2); -} - -// compare two length-specified string, which may be null pointers -static int32_t ns_strnncmp(const char* aStr1, uint32_t aLen1, const char* aStr2, uint32_t aLen2) -{ - // any string is *before* no string - if (!aStr1) - { - return aStr2 != 0; - } - - if (!aStr2) - { - return -1; - } - - for (; aLen1 && aLen2; --aLen1, --aLen2, ++aStr1, ++aStr2) - { - if (*aStr1 < *aStr2) - { - return -1; - } - - if (*aStr1 > *aStr2) - { - return 1; - } - } - - if (aLen1 == 0) - { - return aLen2 == 0 ? 0 : -1; - } - - return 1; -} - -// compare two int32_t -static int32_t ns_cmp(int32_t aNum1, int32_t aNum2) -{ - if (aNum1 < aNum2) - { - return -1; - } - - return aNum1 != aNum2; -} - -/** - * Compares two VersionParts - */ -static int32_t CompareVP(VersionPart& aVer1, VersionPart& aVer2) -{ - int32_t r = ns_cmp(aVer1.numA, aVer2.numA); - if (r) - { - return r; - } - - r = ns_strnncmp(aVer1.strB, aVer1.strBlen, aVer2.strB, aVer2.strBlen); - if (r) - { - return r; - } - - r = ns_cmp(aVer1.numC, aVer2.numC); - if (r) - { - return r; - } - - return ns_strcmp(aVer1.extraD, aVer2.extraD); -} - -/** - * Compares two VersionParts - */ -#ifdef _WIN32 -static int32_t CompareVP(VersionPartW& aVer1, VersionPartW& aVer2) -{ - int32_t r = ns_cmp(aVer1.numA, aVer2.numA); - if (r) - { - return r; - } - - r = wcsncmp(aVer1.strB, aVer2.strB, XPCOM_MIN(aVer1.strBlen, aVer2.strBlen)); - if (r) - { - return r; - } - - r = ns_cmp(aVer1.numC, aVer2.numC); - if (r) - { - return r; - } - - if (!aVer1.extraD) - { - return aVer2.extraD != 0; - } - - if (!aVer2.extraD) - { - return -1; - } - - return wcscmp(aVer1.extraD, aVer2.extraD); -} -#endif - -namespace mozilla -{ -#ifdef _WIN32 -int32_t CompareVersions(const wchar_t* aStrA, const wchar_t* aStrB) -{ - wchar_t* A2 = wcsdup(aStrA); - if (!A2) - { - return 1; - } - - wchar_t* B2 = wcsdup(aStrB); - if (!B2) - { - free(A2); - return 1; - } - - int32_t result; - wchar_t* a = A2; - wchar_t* b = B2; - - do - { - VersionPartW va, vb; - - a = ParseVP(a, va); - b = ParseVP(b, vb); - - result = CompareVP(va, vb); - if (result) - { - break; - } - - } while (a || b); - - free(A2); - free(B2); - - return result; -} -#endif - -int32_t CompareVersions(const char* aStrA, const char* aStrB) -{ - char* A2 = strdup(aStrA); - if (!A2) - { - return 1; - } - - char* B2 = strdup(aStrB); - if (!B2) - { - free(A2); - return 1; - } - - int32_t result; - char* a = A2; - char* b = B2; - - do - { - VersionPart va, vb; - - a = ParseVP(a, va); - b = ParseVP(b, vb); - - result = CompareVP(va, vb); - if (result) - { - break; - } - - } while (a || b); - - free(A2); - free(B2); - - return result; -} - -} // namespace mozilla diff --git a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h deleted file mode 100644 index d793e345eb86..000000000000 --- a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h +++ /dev/null @@ -1,174 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsVersionComparator_h__ -#define nsVersionComparator_h__ - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#if defined(_WIN32) && !defined(UPDATER_NO_STRING_GLUE_STL) -#include <wchar.h> -#include <stdint.h> - -#endif - -/** - * In order to compare version numbers in Mozilla, you need to use the - * mozilla::Version class. You can construct an object of this type by passing - * in a string version number to the constructor. Objects of this type can be - * compared using the standard comparison operators. - * - * For example, let's say that you want to make sure that a given version - * number is not older than 15.a2. Here's how you would write a function to - * do that. - * - * bool IsVersionValid(const char* version) { - * return mozilla::Version("15.a2") <= mozilla::Version(version); - * } - * - * Or, since Version's constructor is implicit, you can simplify this code: - * - * bool IsVersionValid(const char* version) { - * return mozilla::Version("15.a2") <= version; - * } - * - * On Windows, if your version strings are wide characters, you should use the - * mozilla::VersionW variant instead. The semantics of that class is the same - * as Version. - */ - -namespace mozilla { - -int32_t CompareVersions(const char* aStrA, const char* aStrB); - -#ifdef _WIN32 -int32_t CompareVersions(const wchar_t* aStrA, const wchar_t* aStrB); -#endif - -struct Version -{ - explicit Version(const char* aVersionString) - { - versionContent = strdup(aVersionString); - } - - const char* ReadContent() const - { - return versionContent; - } - - ~Version() - { - free(versionContent); - } - - bool operator<(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) == -1; - } - bool operator<=(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) < 1; - } - bool operator>(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) == 1; - } - bool operator>=(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) > -1; - } - bool operator==(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) == 0; - } - bool operator!=(const Version& aRhs) const - { - return CompareVersions(versionContent, aRhs.ReadContent()) != 0; - } - bool operator<(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) == -1; - } - bool operator<=(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) < 1; - } - bool operator>(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) == 1; - } - bool operator>=(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) > -1; - } - bool operator==(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) == 0; - } - bool operator!=(const char* aRhs) const - { - return CompareVersions(versionContent, aRhs) != 0; - } - -private: - char* versionContent; -}; - -#ifdef _WIN32 -struct VersionW -{ - explicit VersionW(const wchar_t* aVersionStringW) - { - versionContentW = - reinterpret_cast<wchar_t*>(wcsdup(aVersionStringW)); - } - - const wchar_t* ReadContentW() const - { - return versionContentW; - } - - ~VersionW() - { - free(versionContentW); - } - - bool operator<(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) == -1; - } - bool operator<=(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) < 1; - } - bool operator>(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) == 1; - } - bool operator>=(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) > -1; - } - bool operator==(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) == 0; - } - bool operator!=(const VersionW& aRhs) const - { - return CompareVersions(versionContentW, aRhs.ReadContentW()) != 0; - } - -private: - wchar_t* versionContentW; -}; -#endif - -} // namespace mozilla - -#endif // nsVersionComparator_h__ - |