diff options
author | Nathan Yee <ny.nathan.yee@gmail.com> | 2015-06-26 12:47:03 -0700 |
---|---|---|
committer | Jan Holesovsky <kendy@collabora.com> | 2015-06-29 17:43:31 +0200 |
commit | 8c07510faa32211536a1d3c461b674812b025bdd (patch) | |
tree | 6a39a9a7bb1027da93a926ef15b1a97db2c302d8 /onlineupdate | |
parent | 7316144b8fbc4c4f4412da7afa68186a545847eb (diff) |
online update: Add updater executable build support
Change-Id: I033f114d29cd020b6dba5a74257d3f577dd73ea7
Diffstat (limited to 'onlineupdate')
41 files changed, 4766 insertions, 88 deletions
diff --git a/onlineupdate/Executable_updater.mk b/onlineupdate/Executable_updater.mk new file mode 100644 index 000000000000..149a3a1e2d23 --- /dev/null +++ b/onlineupdate/Executable_updater.mk @@ -0,0 +1,92 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,updater)) + +$(eval $(call gb_Executable_set_include,updater,\ + -I$(SRCDIR)/onlineupdate/source/update/src \ + -I$(SRCDIR)/onlineupdate/source/update/inc \ + -I$(SRCDIR)/onlineupdate/source/update/common \ + -I$(SRCDIR)/onlineupdate/source/update/updater/libbz2/src \ + -I$(SRCDIR)/onlineupdate/source/update/updater/xpcom/glue \ + -lpthread \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_add_libs,updater,\ + -lX11 \ + -lXext \ + -lXrender \ + -lSM \ + -lICE \ +)) + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Executable_set_include,updater,\ + -lgtk \ +)) +$(eval $(call gb_Exectuable_add_libs,updater,\ + -lpthread \ +)) +else ifeq ($(OS),LINUX) +$(eval $(call gb_Executable_set_include,updater,\ + -lgtk \ +)) +$(eval $(call gb_Exectuable_add_libs,updater,\ + -lpthread \ +)) +endif + +$(eval $(call gb_Executable_add_cxxflags,updater,\ + $$(GTK3_CFLAGS) \ +)) + +$(eval $(call gb_Executable_add_libs,updater,\ + $(GTK3_LIBS) \ +)) + +$(eval $(call gb_Executable_use_libraries,updater,\ + libreofficekitgtk \ +)) + +$(eval $(call gb_Executable_use_externals,updater,\ + gtk \ +)) + +$(eval $(call gb_Executable_add_exception_objects,updater,\ + onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator \ + onlineupdate/source/update/updater/archivereader \ + onlineupdate/source/update/updater/bspatch \ + onlineupdate/source/update/updater/loaddlls \ + onlineupdate/source/update/updater/progressui_gtk \ + onlineupdate/source/update/updater/progressui_null \ + onlineupdate/source/update/updater/progressui_win \ + onlineupdate/source/update/updater/updater \ + onlineupdate/source/update/updater/win_dirent \ + onlineupdate/source/update/common/pathhash \ + onlineupdate/source/update/common/readstrings \ + onlineupdate/source/update/common/uachelper \ + onlineupdate/source/update/common/updatehelper \ + onlineupdate/source/update/common/updatelogging \ +)) + +$(eval $(call gb_Executable_add_cobjects,updater,\ + onlineupdate/source/update/src/mar_create \ + onlineupdate/source/update/src/mar_extract \ + onlineupdate/source/update/src/mar_read \ + onlineupdate/source/update/updater/libbz2/src/blocksort \ + onlineupdate/source/update/updater/libbz2/src/bzlib \ + onlineupdate/source/update/updater/libbz2/src/compress \ + onlineupdate/source/update/updater/libbz2/src/crctable \ + onlineupdate/source/update/updater/libbz2/src/decompress \ + onlineupdate/source/update/updater/libbz2/src/huffman \ + onlineupdate/source/update/updater/libbz2/src/randtable \ +)) + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: */ diff --git a/onlineupdate/Module_onlineupdate.mk b/onlineupdate/Module_onlineupdate.mk index deba97a9feb8..fc09440c0ce9 100644 --- a/onlineupdate/Module_onlineupdate.mk +++ b/onlineupdate/Module_onlineupdate.mk @@ -11,7 +11,8 @@ $(eval $(call gb_Module_Module,onlineupdate)) $(eval $(call gb_Module_add_targets,onlineupdate,\ - Executable_mar \ + Executable_mar \ + Executable_updater \ )) # vim: set noet sw=4 ts=4: diff --git a/onlineupdate/source/update/common/pathhash.cpp b/onlineupdate/source/update/common/pathhash.cxx index 540a8fd20903..fea123cda366 100644 --- a/onlineupdate/source/update/common/pathhash.cpp +++ b/onlineupdate/source/update/common/pathhash.cxx @@ -2,6 +2,7 @@ * 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 WNT #include <windows.h> #include <wincrypt.h> #include "pathhash.h" @@ -137,3 +138,4 @@ CalculateRegistryPathFromFilePath(const LPCWSTR filePath, delete[] hash; return TRUE; } +#endif diff --git a/onlineupdate/source/update/common/readstrings.cpp b/onlineupdate/source/update/common/readstrings.cxx index 428c91c0ba69..83580a80bc74 100644 --- a/onlineupdate/source/update/common/readstrings.cpp +++ b/onlineupdate/source/update/common/readstrings.cxx @@ -10,7 +10,7 @@ #include "readstrings.h" #include "errors.h" -#ifdef XP_WIN +#ifdef WNT # define NS_tfopen _wfopen # define OPEN_MODE L"rb" #else diff --git a/onlineupdate/source/update/common/readstrings.h b/onlineupdate/source/update/common/readstrings.h index ccc26e3fe935..99e515daa611 100644 --- a/onlineupdate/source/update/common/readstrings.h +++ b/onlineupdate/source/update/common/readstrings.h @@ -9,7 +9,7 @@ #define MAX_TEXT_LEN 600 -#ifdef XP_WIN +#ifdef WNT # include <windows.h> typedef WCHAR NS_tchar; #else diff --git a/onlineupdate/source/update/common/uachelper.cpp b/onlineupdate/source/update/common/uachelper.cxx index 90ccdb76b4bd..55053f3d7932 100644 --- a/onlineupdate/source/update/common/uachelper.cpp +++ b/onlineupdate/source/update/common/uachelper.cxx @@ -2,6 +2,7 @@ * 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 WNT #include <windows.h> #include <wtsapi32.h> #include "uachelper.h" @@ -220,3 +221,4 @@ UACHelper::CanUserElevate() return canElevate; } +#endif diff --git a/onlineupdate/source/update/common/updatedefines.h b/onlineupdate/source/update/common/updatedefines.h index 0f62dbe2c50b..db4553312384 100644 --- a/onlineupdate/source/update/common/updatedefines.h +++ b/onlineupdate/source/update/common/updatedefines.h @@ -21,7 +21,7 @@ # endif #endif -#if defined(XP_WIN) +#if defined(WNT) # include <windows.h> # include <shlwapi.h> # include <direct.h> @@ -116,7 +116,7 @@ static inline int mywcsprintf(WCHAR* dest, size_t count, const WCHAR* fmt, ...) #endif # include <dirent.h> -#ifdef XP_MACOSX +#ifdef MACOSX # include <sys/time.h> #endif diff --git a/onlineupdate/source/update/common/updatehelper.cpp b/onlineupdate/source/update/common/updatehelper.cxx index 84ab331a6052..579515430115 100644 --- a/onlineupdate/source/update/common/updatehelper.cpp +++ b/onlineupdate/source/update/common/updatehelper.cxx @@ -2,6 +2,7 @@ * 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 WNT #include <windows.h> // Needed for CreateToolhelp32Snapshot @@ -749,3 +750,4 @@ IsUnpromptedElevation(BOOL &isUnpromptedElevation) RegCloseKey(baseKey); return success; } +#endif diff --git a/onlineupdate/source/update/common/updatelogging.cpp b/onlineupdate/source/update/common/updatelogging.cxx index 036c0b175ae6..9ed8f3e8fcea 100644 --- a/onlineupdate/source/update/common/updatelogging.cpp +++ b/onlineupdate/source/update/common/updatelogging.cxx @@ -2,7 +2,7 @@ * 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(XP_WIN) +#if defined(WNT) #include <windows.h> #endif diff --git a/onlineupdate/source/update/common/win_dirent.h b/onlineupdate/source/update/common/win_dirent.h index 28f5317ff3e1..a1c79d6cdc78 100644 --- a/onlineupdate/source/update/common/win_dirent.h +++ b/onlineupdate/source/update/common/win_dirent.h @@ -6,11 +6,7 @@ #ifndef WINDIRENT_H__ #define WINDIRENT_H__ - -#ifndef XP_WIN -#error This library should only be used on Windows -#endif - +#ifdef WNT #include <windows.h> struct DIR { @@ -29,4 +25,5 @@ DIR* opendir(const WCHAR* path); int closedir(DIR* dir); dirent* readdir(DIR* dir); +#endif // WNT #endif // WINDIRENT_H__ diff --git a/onlineupdate/source/update/inc/mozilla/Assertions.h b/onlineupdate/source/update/inc/mozilla/Assertions.h new file mode 100644 index 000000000000..c72e020806cd --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Assertions.h @@ -0,0 +1,503 @@ +/* -*- 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/. */ + +/* Implementations of runtime and static assertion macros for C and C++. */ + +#ifndef mozilla_Assertions_h +#define mozilla_Assertions_h + +#if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus) +#define MOZ_DUMP_ASSERTION_STACK +#endif + +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/Likely.h" +#include "mozilla/MacroArgs.h" +#ifdef MOZ_DUMP_ASSERTION_STACK +#include "nsTraceRefcnt.h" +#endif + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef WIN32 + /* + * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which + * further depends on <windef.h>. We hardcode these few definitions manually + * because those headers clutter the global namespace with a significant + * number of undesired macros and symbols. + */ +# ifdef __cplusplus +extern "C" { +# endif +__declspec(dllimport) int __stdcall +TerminateProcess(void* hProcess, unsigned int uExitCode); +__declspec(dllimport) void* __stdcall GetCurrentProcess(void); +# ifdef __cplusplus +} +# endif +#else +# include <signal.h> +#endif +#ifdef ANDROID +# include <android/log.h> +#endif + +/* + * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C. + * In C++11, static_assert is provided by the compiler to the same effect. + * This can be useful when you make certain assumptions about what must hold for + * optimal, or even correct, behavior. For example, you might assert that the + * size of a struct is a multiple of the target architecture's word size: + * + * struct S { ... }; + * // C + * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0, + * "S should be a multiple of word size for efficiency"); + * // C++11 + * static_assert(sizeof(S) % sizeof(size_t) == 0, + * "S should be a multiple of word size for efficiency"); + * + * This macro can be used in any location where both an extern declaration and a + * typedef could be used. + */ +#ifndef __cplusplus + /* + * Some of the definitions below create an otherwise-unused typedef. This + * triggers compiler warnings with some versions of gcc, so mark the typedefs + * as permissibly-unused to disable the warnings. + */ +# if defined(__GNUC__) +# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +# else +# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ +# endif +# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y +# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) +# if defined(__SUNPRO_CC) + /* + * The Sun Studio C++ compiler is buggy when declaring, inside a function, + * another extern'd function with an array argument whose length contains a + * sizeof, triggering the error message "sizeof expression not accepted as + * size of array parameter". This bug (6688515, not public yet) would hit + * defining moz_static_assert as a function, so we always define an extern + * array for Sun Studio. + * + * We include the line number in the symbol name in a best-effort attempt + * to avoid conflicts (see below). + */ +# define MOZ_STATIC_ASSERT(cond, reason) \ + extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] +# elif defined(__COUNTER__) + /* + * If there was no preferred alternative, use a compiler-agnostic version. + * + * Note that the non-__COUNTER__ version has a bug in C++: it can't be used + * in both |extern "C"| and normal C++ in the same translation unit. (Alas + * |extern "C"| isn't allowed in a function.) The only affected compiler + * we really care about is gcc 4.2. For that compiler and others like it, + * we include the line number in the function name to do the best we can to + * avoid conflicts. These should be rare: a conflict would require use of + * MOZ_STATIC_ASSERT on the same line in separate files in the same + * translation unit, *and* the uses would have to be in code with + * different linkage, *and* the first observed use must be in C++-linkage + * code. + */ +# define MOZ_STATIC_ASSERT(cond, reason) \ + typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +# else +# define MOZ_STATIC_ASSERT(cond, reason) \ + extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +# endif + +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) +#else +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Prints |aStr| as an assertion failure (using aFilename and aLine as the + * location of the assertion) to the standard debug-output channel. + * + * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This + * method is primarily for internal use in this header, and only secondarily + * for use in implementing release-build assertions. + */ +static MOZ_COLD MOZ_ALWAYS_INLINE void +MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine) + MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", + "Assertion failure: %s, at %s:%d\n", + aStr, aFilename, aLine); +#else + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); +#if defined (MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) + nsTraceRefcnt::WalkTheStack(stderr); +#endif + fflush(stderr); +#endif +} + +static MOZ_COLD MOZ_ALWAYS_INLINE void +MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) + MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", + "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); +#else + fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); +#if defined(MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) + nsTraceRefcnt::WalkTheStack(stderr); +#endif + fflush(stderr); +#endif +} + +/** + * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should + * call MOZ_CRASH instead. + */ +#if defined(_MSC_VER) + /* + * On MSVC use the __debugbreak compiler intrinsic, which produces an inline + * (not nested in a system function) breakpoint. This distinctively invokes + * Breakpad without requiring system library symbols on all stack-processing + * machines, as a nested breakpoint would require. + * + * We use TerminateProcess with the exit code aborting would generate + * because we don't want to invoke atexit handlers, destructors, library + * unload handlers, and so on when our process might be in a compromised + * state. + * + * We don't use abort() because it'd cause Windows to annoyingly pop up the + * process error dialog multiple times. See bug 345118 and bug 426163. + * + * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the + * compiler doesn't hassle us to provide a return statement after a + * MOZ_REALLY_CRASH() call. + * + * (Technically these are Windows requirements, not MSVC requirements. But + * practically you need MSVC for debugging, and we only ship builds created + * by MSVC, so doing it this way reduces complexity.) + */ + +__declspec(noreturn) __inline void MOZ_NoReturn() {} + +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + ::__debugbreak(); \ + *((volatile int*) NULL) = __LINE__; \ + ::TerminateProcess(::GetCurrentProcess(), 3); \ + ::MOZ_NoReturn(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + __debugbreak(); \ + *((volatile int*) NULL) = __LINE__; \ + TerminateProcess(GetCurrentProcess(), 3); \ + MOZ_NoReturn(); \ + } while (0) +# endif +#else +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = __LINE__; \ + ::abort(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = __LINE__; \ + abort(); \ + } while (0) +# endif +#endif + +/* + * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a + * Breakpad-compatible way, in both debug and release builds. + * + * MOZ_CRASH is a good solution for "handling" failure cases when you're + * unwilling or unable to handle them more cleanly -- for OOM, for likely memory + * corruption, and so on. It's also a good solution if you need safe behavior + * in release builds as well as debug builds. But if the failure is one that + * should be debugged and fixed, MOZ_ASSERT is generally preferable. + * + * The optional explanation-string, if provided, must be a string literal + * explaining why we're crashing. This argument is intended for use with + * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's + * obvious why we're crashing. + * + * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an + * explanation-string, we print the string to stderr. Otherwise, we don't + * print anything; this is because we want MOZ_CRASH to be 100% safe in release + * builds, and it's hard to print to stderr safely when memory might have been + * corrupted. + */ +#ifndef DEBUG +# define MOZ_CRASH(...) MOZ_REALLY_CRASH() +#else +# define MOZ_CRASH(...) \ + do { \ + MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } while (0) +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* + * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in + * debug builds. If it is, execution continues. Otherwise, an error message + * including the expression and the explanation-string (if provided) is printed, + * an attempt is made to invoke any existing debugger, and execution halts. + * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition + * which can correctly be falsy. + * + * The optional explanation-string, if provided, must be a string literal + * explaining the assertion. It is intended for use with assertions whose + * correctness or rationale is non-obvious, and for assertions where the "real" + * condition being tested is best described prosaically. Don't provide an + * explanation if it's not actually helpful. + * + * // No explanation needed: pointer arguments often must not be NULL. + * MOZ_ASSERT(arg); + * + * // An explanation can be helpful to explain exactly how we know an + * // assertion is valid. + * MOZ_ASSERT(state == WAITING_FOR_RESPONSE, + * "given that <thingA> and <thingB>, we must have..."); + * + * // Or it might disambiguate multiple identical (save for their location) + * // assertions of the same expression. + * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), + * "we already set [[PrimitiveThis]] for this Boolean object"); + * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), + * "we already set [[PrimitiveThis]] for this String object"); + * + * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs + * *only* during debugging, not "in the field". If you want the latter, use + * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well. + * + * MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and + * MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare + * enough to require real user testing to hit, but is not security-sensitive. + * This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT + * is firing, it should promptly be converted to a MOZ_ASSERT while the failure + * is being investigated, rather than letting users suffer. + */ + +/* + * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against + * accidentally passing something unintended in lieu of an assertion condition. + */ + +#ifdef __cplusplus +# include "mozilla/TypeTraits.h" +namespace mozilla { +namespace detail { + +template<typename T> +struct IsFunction +{ + static const bool value = false; +}; + +template<typename R, typename... A> +struct IsFunction<R(A...)> +{ + static const bool value = true; +}; + +template<typename T> +struct AssertionConditionType +{ + typedef typename RemoveReference<T>::Type ValueT; + static_assert(!IsArray<ValueT>::value, + "Expected boolean assertion condition, got an array or a " + "string!"); + static_assert(!IsFunction<ValueT>::value, + "Expected boolean assertion condition, got a function! Did " + "you intend to call that function?"); + static_assert(!IsFloatingPoint<ValueT>::value, + "It's often a bad idea to assert that a floating-point number " + "is nonzero, because such assertions tend to intermittently " + "fail. Shouldn't your code gracefully handle this case instead " + "of asserting? Anyway, if you really want to do that, write an " + "explicit boolean condition, like !!x or x!=0."); + + static const bool isValid = true; +}; + +} // namespace detail +} // namespace mozilla +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ + static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \ + "invalid assertion condition") +#else +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +#endif + +/* First the single-argument form. */ +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!(expr))) { \ + MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } \ + } while (0) +/* Now the two-argument form. */ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!(expr))) { \ + MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } \ + } while (0) + +#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) + +#ifdef DEBUG +# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) +#else +# define MOZ_ASSERT(...) do { } while (0) +#endif /* DEBUG */ + +#ifdef RELEASE_BUILD +# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT +#else +# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT +#endif + +/* + * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is + * true. + * + * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num)); + * + * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is + * designed to catch bugs during debugging, not "in the field". + */ +#ifdef DEBUG +# define MOZ_ASSERT_IF(cond, expr) \ + do { \ + if (cond) { \ + MOZ_ASSERT(expr); \ + } \ + } while (0) +#else +# define MOZ_ASSERT_IF(cond, expr) do { } while (0) +#endif + +/* + * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that + * it is undefined behavior for execution to reach this point. No guarantees + * are made about what will happen if this is reached at runtime. Most code + * should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra + * asserts. + */ +#if defined(__clang__) || defined(__GNUC__) +# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() +#elif defined(_MSC_VER) +# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) +#else +# ifdef __cplusplus +# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() +# else +# define MOZ_ASSUME_UNREACHABLE_MARKER() abort() +# endif +#endif + +/* + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it + * can assume that the macro call cannot be reached during execution. This lets + * the compiler generate better-optimized code under some circumstances, at the + * expense of the program's behavior being undefined if control reaches the + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE. + * + * In Gecko, you probably should not use this macro outside of performance- or + * size-critical code, because it's unsafe. If you don't care about code size + * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH. + * + * SpiderMonkey is a different beast, and there it's acceptable to use + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely. + * + * Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid + * not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE + * call. + * + * Example usage: + * + * enum ValueType { + * VALUE_STRING, + * VALUE_INT, + * VALUE_FLOAT + * }; + * + * int ptrToInt(ValueType type, void* value) { + * { + * // We know for sure that type is either INT or FLOAT, and we want this + * // code to run as quickly as possible. + * switch (type) { + * case VALUE_INT: + * return *(int*) value; + * case VALUE_FLOAT: + * return (int) *(float*) value; + * default: + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType"); + * } + * } + */ + +/* + * Unconditional assert in debug builds for (assumed) unreachable code paths + * that have a safe return without crashing in release builds. + */ +#define MOZ_ASSERT_UNREACHABLE(reason) \ + MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) + +#define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \ + do { \ + MOZ_ASSERT_UNREACHABLE(reason); \ + MOZ_ASSUME_UNREACHABLE_MARKER(); \ + } while (0) + +/* + * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided + * expression, in debug builds and in release builds both. Then, in debug + * builds only, the value of the expression is asserted either true or false + * using MOZ_ASSERT. + */ +#ifdef DEBUG +# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) +# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) +#else +# define MOZ_ALWAYS_TRUE(expr) ((void)(expr)) +# define MOZ_ALWAYS_FALSE(expr) ((void)(expr)) +#endif + +#undef MOZ_DUMP_ASSERTION_STACK + +#endif /* mozilla_Assertions_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Attributes.h b/onlineupdate/source/update/inc/mozilla/Attributes.h new file mode 100644 index 000000000000..b34e7d5af07a --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Attributes.h @@ -0,0 +1,481 @@ +/* -*- 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/. */ + +/* Implementations of various class and method modifier attributes. */ + +#ifndef mozilla_Attributes_h +#define mozilla_Attributes_h + +#include "mozilla/Compiler.h" + +/* + * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the + * method decorated with it must be inlined, even if the compiler thinks + * otherwise. This is only a (much) stronger version of the inline hint: + * compilers are not guaranteed to respect it (although they're much more likely + * to do so). + * + * The MOZ_ALWAYS_INLINE_EVEN_DEBUG macro is yet stronger. It tells the + * compiler to inline even in DEBUG builds. It should be used very rarely. + */ +#if defined(_MSC_VER) +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline +#elif defined(__GNUC__) +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline +#else +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline +#endif + +#if !defined(DEBUG) +# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG +#elif defined(_MSC_VER) && !defined(__cplusplus) +# define MOZ_ALWAYS_INLINE __inline +#else +# define MOZ_ALWAYS_INLINE inline +#endif + +#if defined(_MSC_VER) +/* + * g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality + * without warnings (functionality used by the macros below). These modes are + * detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more + * standardly, by checking whether __cplusplus has a C++11 or greater value. + * Current versions of g++ do not correctly set __cplusplus, so we check both + * for forward compatibility. + * + * Even though some versions of MSVC support explicit conversion operators, we + * don't indicate support for them here, due to + * http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug + */ +# define MOZ_HAVE_NEVER_INLINE __declspec(noinline) +# define MOZ_HAVE_NORETURN __declspec(noreturn) +# ifdef __clang__ + /* clang-cl probably supports constexpr and explicit conversions. */ +# if __has_extension(cxx_constexpr) +# define MOZ_HAVE_CXX11_CONSTEXPR +# endif +# if __has_extension(cxx_explicit_conversions) +# define MOZ_HAVE_EXPLICIT_CONVERSION +# endif +# endif +#elif defined(__clang__) + /* + * Per Clang documentation, "Note that marketing version numbers should not + * be used to check for language features, as different vendors use different + * numbering schemes. Instead, use the feature checking macros." + */ +# ifndef __has_extension +# define __has_extension __has_feature /* compatibility, for older versions of clang */ +# endif +# if __has_extension(cxx_constexpr) +# define MOZ_HAVE_CXX11_CONSTEXPR +# endif +# if __has_extension(cxx_explicit_conversions) +# define MOZ_HAVE_EXPLICIT_CONVERSION +# endif +# if __has_attribute(noinline) +# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +# endif +# if __has_attribute(noreturn) +# define MOZ_HAVE_NORETURN __attribute__((noreturn)) +# endif +#elif defined(__GNUC__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +# define MOZ_HAVE_CXX11_CONSTEXPR +# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) +# define MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES +# endif +# define MOZ_HAVE_EXPLICIT_CONVERSION +# endif +# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +# define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#endif + +/* + * When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN + * to mark some false positives + */ +#ifdef __clang_analyzer__ +# if __has_extension(attribute_analyzer_noreturn) +# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) +# endif +#endif + +/* + * The MOZ_CONSTEXPR specifier declares that a C++11 compiler can evaluate a + * function at compile time. A constexpr function cannot examine any values + * except its arguments and can have no side effects except its return value. + * The MOZ_CONSTEXPR_VAR specifier tells a C++11 compiler that a variable's + * value may be computed at compile time. It should be prefered to just + * marking variables as MOZ_CONSTEXPR because if the compiler does not support + * constexpr it will fall back to making the variable const, and some compilers + * do not accept variables being marked both const and constexpr. + */ +#ifdef MOZ_HAVE_CXX11_CONSTEXPR +# define MOZ_CONSTEXPR constexpr +# define MOZ_CONSTEXPR_VAR constexpr +# ifdef MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES +# define MOZ_CONSTEXPR_TMPL constexpr +# else +# define MOZ_CONSTEXPR_TMPL +# endif +#else +# define MOZ_CONSTEXPR /* no support */ +# define MOZ_CONSTEXPR_VAR const +# define MOZ_CONSTEXPR_TMPL +#endif + +/* + * MOZ_EXPLICIT_CONVERSION is a specifier on a type conversion + * overloaded operator that declares that a C++11 compiler should restrict + * this operator to allow only explicit type conversions, disallowing + * implicit conversions. + * + * Example: + * + * template<typename T> + * class Ptr + * { + * T* mPtr; + * MOZ_EXPLICIT_CONVERSION operator bool() const + * { + * return mPtr != nullptr; + * } + * }; + * + */ +#ifdef MOZ_HAVE_EXPLICIT_CONVERSION +# define MOZ_EXPLICIT_CONVERSION explicit +#else +# define MOZ_EXPLICIT_CONVERSION /* no support */ +#endif + +/* + * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the + * method decorated with it must never be inlined, even if the compiler would + * otherwise choose to inline the method. Compilers aren't absolutely + * guaranteed to support this, but most do. + */ +#if defined(MOZ_HAVE_NEVER_INLINE) +# define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE +#else +# define MOZ_NEVER_INLINE /* no support */ +#endif + +/* + * MOZ_NORETURN, specified at the start of a function declaration, indicates + * that the given function does not return. (The function definition does not + * need to be annotated.) + * + * MOZ_NORETURN void abort(const char* msg); + * + * This modifier permits the compiler to optimize code assuming a call to such a + * function will never return. It also enables the compiler to avoid spurious + * warnings about not initializing variables, or about any other seemingly-dodgy + * operations performed after the function returns. + * + * This modifier does not affect the corresponding function's linking behavior. + */ +#if defined(MOZ_HAVE_NORETURN) +# define MOZ_NORETURN MOZ_HAVE_NORETURN +#else +# define MOZ_NORETURN /* no support */ +#endif + +/** + * MOZ_COLD tells the compiler that a function is "cold", meaning infrequently + * executed. This may lead it to optimize for size more aggressively than speed, + * or to allocate the body of the function in a distant part of the text segment + * to help keep it from taking up unnecessary icache when it isn't in use. + * + * Place this attribute at the very beginning of a function definition. For + * example, write + * + * MOZ_COLD int foo(); + * + * or + * + * MOZ_COLD int foo() { return 42; } + */ +#if defined(__GNUC__) || defined(__clang__) +# define MOZ_COLD __attribute__ ((cold)) +#else +# define MOZ_COLD +#endif + +/** + * MOZ_NONNULL tells the compiler that some of the arguments to a function are + * known to be non-null. The arguments are a list of 1-based argument indexes + * identifying arguments which are known to be non-null. + * + * Place this attribute at the very beginning of a function definition. For + * example, write + * + * MOZ_NONNULL(1, 2) int foo(char *p, char *q); + */ +#if defined(__GNUC__) || defined(__clang__) +# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__))) +#else +# define MOZ_NONNULL(...) +#endif + +/* + * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function + * declaration, indicates that for the purposes of static analysis, this + * function does not return. (The function definition does not need to be + * annotated.) + * + * MOZ_ReportCrash(const char* s, const char* file, int ln) + * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS + * + * Some static analyzers, like scan-build from clang, can use this information + * to eliminate false positives. From the upstream documentation of scan-build: + * "This attribute is useful for annotating assertion handlers that actually + * can return, but for the purpose of using the analyzer we want to pretend + * that such functions do not return." + * + */ +#if defined(MOZ_HAVE_ANALYZER_NORETURN) +# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN +#else +# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ +#endif + +/* + * MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time + * instrumentation shipped with Clang and GCC) to not instrument the annotated + * function. Furthermore, it will prevent the compiler from inlining the + * function because inlining currently breaks the blacklisting mechanism of + * AddressSanitizer. + */ +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define MOZ_HAVE_ASAN_BLACKLIST +# endif +#elif defined(__GNUC__) +# if defined(__SANITIZE_ADDRESS__) +# define MOZ_HAVE_ASAN_BLACKLIST +# endif +#endif + +#if defined(MOZ_HAVE_ASAN_BLACKLIST) +# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) +#else +# define MOZ_ASAN_BLACKLIST /* nothing */ +#endif + +/* + * MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time + * instrumentation shipped with Clang) to not instrument the annotated function. + * Furthermore, it will prevent the compiler from inlining the function because + * inlining currently breaks the blacklisting mechanism of ThreadSanitizer. + */ +#if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) +# else +# define MOZ_TSAN_BLACKLIST /* nothing */ +# endif +#else +# define MOZ_TSAN_BLACKLIST /* nothing */ +#endif + +/** + * MOZ_ALLOCATOR tells the compiler that the function it marks returns either a + * "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the + * block is not pointed to by any other reachable pointer in the program. + * "Pointer-free" means that the block contains no pointers to any valid object + * in the program. It may be initialized with other (non-pointer) values. + * + * Placing this attribute on appropriate functions helps GCC analyze pointer + * aliasing more accurately in their callers. + * + * GCC warns if a caller ignores the value returned by a function marked with + * MOZ_ALLOCATOR: it is hard to imagine cases where dropping the value returned + * by a function that meets the criteria above would be intentional. + * + * Place this attribute after the argument list and 'this' qualifiers of a + * function definition. For example, write + * + * void *my_allocator(size_t) MOZ_ALLOCATOR; + * + * or + * + * void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... } + */ +#if defined(__GNUC__) || defined(__clang__) +# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result)) +#else +# define MOZ_ALLOCATOR +#endif + +/** + * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's + * return value is not used by the caller. + * + * Place this attribute at the very beginning of a function definition. For + * example, write + * + * MOZ_WARN_UNUSED_RESULT int foo(); + * + * or + * + * MOZ_WARN_UNUSED_RESULT int foo() { return 42; } + */ +#if defined(__GNUC__) || defined(__clang__) +# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else +# define MOZ_WARN_UNUSED_RESULT +#endif + +#ifdef __cplusplus + +/* + * The following macros are attributes that support the static analysis plugin + * included with Mozilla, and will be implemented (when such support is enabled) + * as C++11 attributes. Since such attributes are legal pretty much everywhere + * and have subtly different semantics depending on their placement, the + * following is a guide on where to place the attributes. + * + * Attributes that apply to a struct or class precede the name of the class: + * (Note that this is different from the placement of final for classes!) + * + * class MOZ_CLASS_ATTRIBUTE SomeClass {}; + * + * Attributes that apply to functions follow the parentheses and const + * qualifiers but precede final, override and the function body: + * + * void DeclaredFunction() MOZ_FUNCTION_ATTRIBUTE; + * void SomeFunction() MOZ_FUNCTION_ATTRIBUTE {} + * void PureFunction() const MOZ_FUNCTION_ATTRIBUTE = 0; + * void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE override; + * + * Attributes that apply to variables or parameters follow the variable's name: + * + * int variable MOZ_VARIABLE_ATTRIBUTE; + * + * Attributes that apply to types follow the type name: + * + * typedef int MOZ_TYPE_ATTRIBUTE MagicInt; + * int MOZ_TYPE_ATTRIBUTE someVariable; + * int* MOZ_TYPE_ATTRIBUTE magicPtrInt; + * int MOZ_TYPE_ATTRIBUTE* ptrToMagicInt; + * + * Attributes that apply to statements precede the statement: + * + * MOZ_IF_ATTRIBUTE if (x == 0) + * MOZ_DO_ATTRIBUTE do { } while (0); + * + * Attributes that apply to labels precede the label: + * + * MOZ_LABEL_ATTRIBUTE target: + * goto target; + * MOZ_CASE_ATTRIBUTE case 5: + * MOZ_DEFAULT_ATTRIBUTE default: + * + * The static analyses that are performed by the plugin are as follows: + * + * MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate + * subclasses must provide an exact override of this method; if a subclass + * does not override this method, the compiler will emit an error. This + * attribute is not limited to virtual methods, so if it is applied to a + * nonvirtual method and the subclass does not provide an equivalent + * definition, the compiler will emit an error. + * MOZ_STACK_CLASS: Applies to all classes. Any class with this annotation is + * expected to live on the stack, so it is a compile-time error to use it, or + * an array of such objects, as a global or static variable, or as the type of + * a new expression (unless placement new is being used). If a member of + * another class uses this class, or if another class inherits from this + * class, then it is considered to be a stack class as well, although this + * attribute need not be provided in such cases. + * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is + * expected to live on the stack or in static storage, so it is a compile-time + * error to use it, or an array of such objects, as the type of a new + * expression (unless placement new is being used). If a member of another + * class uses this class, or if another class inherits from this class, then + * it is considered to be a non-heap class as well, although this attribute + * need not be provided in such cases. + * MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are + * intended to prevent introducing static initializers. This attribute + * currently makes it a compile-time error to instantiate these classes + * anywhere other than at the global scope, or as a static member of a class. + * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial + * constructor and a trivial destructor. Setting this attribute on a class + * makes it a compile-time error for that class to get a non-trivial + * constructor or destructor for any reason. + * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return + * value is allocated on the heap, and will as a result check such allocations + * during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking. + * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors + * are disallowed by default unless they are marked as MOZ_IMPLICIT. This + * attribute must be used for constructors which intend to provide implicit + * conversions. + * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile + * time error to pass arithmetic expressions on variables to the function. + * MOZ_OWNING_REF: Applies to declarations of pointer types. This attribute + * tells the compiler that the raw pointer is a strong reference, and that + * property is somehow enforced by the code. This can make the compiler + * ignore these pointers when validating the usage of pointers otherwise. + * MOZ_NON_OWNING_REF: Applies to declarations of pointer types. This attribute + * tells the compiler that the raw pointer is a weak reference, and that + * property is somehow enforced by the code. This can make the compiler + * ignore these pointers when validating the usage of pointers otherwise. + * MOZ_UNSAFE_REF: Applies to declarations of pointer types. This attribute + * should be used for non-owning references that can be unsafe, and their + * safety needs to be validated through code inspection. The string argument + * passed to this macro documents the safety conditions. + * MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it + * a compile time error to call AddRef or Release on the return value of a + * function. This is intended to be used with operator->() of our smart + * pointer classes to ensure that the refcount of an object wrapped in a + * smart pointer is not manipulated directly. + */ +#ifdef MOZ_CLANG_PLUGIN +# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +# define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) +# ifdef DEBUG + /* in debug builds, these classes do have non-trivial constructors. */ +# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) +# else +# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \ + MOZ_TRIVIAL_CTOR_DTOR +# endif +# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) +# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg"))) +# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref"))) +# define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref"))) +# define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_strong_ref"))) +# define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) +/* + * It turns out that clang doesn't like void func() __attribute__ {} without a + * warning, so use pragmas to disable the warning. This code won't work on GCC + * anyways, so the warning is safe to ignore. + */ +# define MOZ_HEAP_ALLOCATOR \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("clang diagnostic pop") +#else +# define MOZ_MUST_OVERRIDE /* nothing */ +# define MOZ_STACK_CLASS /* nothing */ +# define MOZ_NONHEAP_CLASS /* nothing */ +# define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ +# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ +# define MOZ_IMPLICIT /* nothing */ +# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ +# define MOZ_HEAP_ALLOCATOR /* nothing */ +# define MOZ_OWNING_REF /* nothing */ +# define MOZ_NON_OWNING_REF /* nothing */ +# define MOZ_UNSAFE_REF(reason) /* nothing */ +# define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */ +#endif /* MOZ_CLANG_PLUGIN */ + +#endif /* __cplusplus */ + +#endif /* mozilla_Attributes_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Compiler.h b/onlineupdate/source/update/inc/mozilla/Compiler.h new file mode 100644 index 000000000000..6d6fcbbb19f5 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Compiler.h @@ -0,0 +1,110 @@ +/* -*- 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/. */ + +/* Various compiler checks. */ + +#ifndef mozilla_Compiler_h +#define mozilla_Compiler_h + +#define MOZ_IS_GCC 0 +#define MOS_IS_MSVC 0 + +#if !defined(__clang__) && defined(__GNUC__) + +# undef MOZ_IS_GCC +# define MOZ_IS_GCC 1 + /* + * This macro should simplify gcc version checking. For example, to check + * for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`. + */ +# define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ + >= ((major) * 10000 + (minor) * 100 + (patchlevel))) +# if !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) +# error "mfbt (and Gecko) require at least gcc 4.7 to build." +# endif + +#elif defined(_MSC_VER) + +# undef MOZ_IS_MSVC +# define MOZ_IS_MSVC 1 + +#endif + +/* + * The situation with standard libraries is a lot worse than with compilers, + * particularly as clang and gcc could end up using one of three or so standard + * libraries, and they may not be up-to-snuff with newer C++11 versions. To + * detect the library, we're going to include cstddef (which is a small header + * which will be transitively included by everybody else at some point) to grab + * the version macros and deduce macros from there. + */ +#ifdef __cplusplus +# include <cstddef> +# ifdef _STLPORT_MAJOR +# define MOZ_USING_STLPORT 1 +# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ + (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) +# elif defined(_LIBCPP_VERSION) + /* + * libc++, unfortunately, doesn't appear to have useful versioning macros. + * Hopefully, the recommendations of N3694 with respect to standard libraries + * will get applied instead and we won't need to worry about version numbers + * here. + */ +# define MOZ_USING_LIBCXX 1 +# elif defined(__GLIBCXX__) +# define MOZ_USING_LIBSTDCXX 1 + /* + * libstdc++ is also annoying and doesn't give us useful versioning macros + * for the library. If we're using gcc, then assume that libstdc++ matches + * the compiler version. If we're using clang, we're going to have to fake + * major/minor combinations by looking for newly-defined config macros. + */ +# if MOZ_IS_GCC +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) +# elif defined(_GLIBCXX_THROW_OR_ABORT) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 8)) +# elif defined(_GLIBCXX_NOEXCEPT) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 7)) +# elif defined(_GLIBCXX_USE_DEPRECATED) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 6)) +# elif defined(_GLIBCXX_PSEUDO_VISIBILITY) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 5)) +# elif defined(_GLIBCXX_BEGIN_EXTERN_C) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 4)) +# elif defined(_GLIBCXX_VISIBILITY_ATTR) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 3)) +# elif defined(_GLIBCXX_VISIBILITY) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 2)) +# else +# error "Your version of libstdc++ is unknown to us and is likely too old." +# endif +# endif + + // Flesh out the defines for everyone else +# ifndef MOZ_USING_STLPORT +# define MOZ_USING_STLPORT 0 +# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 +# endif +# ifndef MOZ_USING_LIBCXX +# define MOZ_USING_LIBCXX 0 +# endif +# ifndef MOZ_USING_LIBSTDCXX +# define MOZ_USING_LIBSTDCXX 0 +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 +# endif +#endif /* __cplusplus */ + +#endif /* mozilla_Compiler_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Likely.h b/onlineupdate/source/update/inc/mozilla/Likely.h new file mode 100644 index 000000000000..4f2160929544 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Likely.h @@ -0,0 +1,23 @@ +/* -*- 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/. */ + +/* + * MOZ_LIKELY and MOZ_UNLIKELY macros to hint to the compiler how a + * boolean predicate should be branch-predicted. + */ + +#ifndef mozilla_Likely_h +#define mozilla_Likely_h + +#if defined(__clang__) || defined(__GNUC__) +# define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) +# define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#else +# define MOZ_LIKELY(x) (!!(x)) +# define MOZ_UNLIKELY(x) (!!(x)) +#endif + +#endif /* mozilla_Likely_h */ diff --git a/onlineupdate/source/update/inc/mozilla/MacroArgs.h b/onlineupdate/source/update/inc/mozilla/MacroArgs.h new file mode 100644 index 000000000000..c8b733821035 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/MacroArgs.h @@ -0,0 +1,105 @@ +/* -*- 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/. */ + +/* + * Implements various macros meant to ease the use of variadic macros. + */ + +#ifndef mozilla_MacroArgs_h +#define mozilla_MacroArgs_h + +/* + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic + * arguments and prefixes it with |aPrefix|. For example: + * + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3 + * + * You must pass in between 1 and 50 (inclusive) variadic arguments, past + * |aPrefix|. It is not legal to do + * + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix) + * + * (that is, pass in 0 variadic arguments). To ensure that a compile-time + * error occurs when these constraints are violated, use the + * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments + * wherever this macro is used. + * + * Passing (__VA_ARGS__, <rest of arguments>) rather than simply calling + * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, <rest of arguments>) very + * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__ + * as a single token in argument lists. For details, see: + * + * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement + * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 + */ +#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \ + MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \ + aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \ + aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \ + aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \ + aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \ + aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \ + aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \ + aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \ + aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \ + aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \ + aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0)) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \ + MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs + +#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \ + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \ + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \ + a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \ + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \ + a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \ + a51, ...) a51 + +/* + * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs + * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are + * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used + * and pass it the same variadic arguments. + * + * This macro employs a few dirty tricks to function. To detect the zero + * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to + * what it should be in the absence of arguments. + * + * Detecting too many arguments is a little trickier. With a valid argument + * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14. + * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many + * arguments, it expands to the first argument over the limit. If this + * exceeding argument is a number, the assertion will fail as there is no + * number than can simultaneously be both > 10 and == 0. If the exceeding + * argument is not a number, a compile-time error should still occur due to + * the operations performed on it. + */ +#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x +#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \ + static_assert( \ + sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \ + (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \ + (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \ + "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */ + +/* + * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N| + * arguments. For example: + * + * MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d + */ +#define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__ +#define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__ + +/* + * MOZ_ARG_N expands to its |N|th argument. + */ +#define MOZ_ARG_1(a1, ...) a1 +#define MOZ_ARG_2(a1, a2, ...) a2 + +#endif /* mozilla_MacroArgs_h */ diff --git a/onlineupdate/source/update/inc/mozilla/TypeTraits.h b/onlineupdate/source/update/inc/mozilla/TypeTraits.h new file mode 100644 index 000000000000..47c7945a6a2d --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/TypeTraits.h @@ -0,0 +1,1116 @@ +/* -*- 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/. */ + +/* Template-based metaprogramming and type-testing facilities. */ + +#ifndef mozilla_TypeTraits_h +#define mozilla_TypeTraits_h + +#include "mozilla/Types.h" + +/* + * These traits are approximate copies of the traits and semantics from C++11's + * <type_traits> header. Don't add traits not in that header! When all + * platforms provide that header, we can convert all users and remove this one. + */ + +#include <wchar.h> + +namespace mozilla { + +/* Forward declarations. */ + +template<typename> struct RemoveCV; + +/* 20.9.3 Helper classes [meta.help] */ + +/** + * Helper class used as a base for various type traits, exposed publicly + * because <type_traits> exposes it as well. + */ +template<typename T, T Value> +struct IntegralConstant +{ + static const T value = Value; + typedef T ValueType; + typedef IntegralConstant<T, Value> Type; +}; + +/** Convenient aliases. */ +typedef IntegralConstant<bool, true> TrueType; +typedef IntegralConstant<bool, false> FalseType; + +/* 20.9.4 Unary type traits [meta.unary] */ + +/* 20.9.4.1 Primary type categories [meta.unary.cat] */ + +namespace detail { + +template<typename T> +struct IsVoidHelper : FalseType {}; + +template<> +struct IsVoidHelper<void> : TrueType {}; + +} // namespace detail + +/** + * IsVoid determines whether a type is void. + * + * mozilla::IsVoid<int>::value is false; + * mozilla::IsVoid<void>::value is true; + * mozilla::IsVoid<void*>::value is false; + * mozilla::IsVoid<volatile void>::value is true. + */ +template<typename T> +struct IsVoid : detail::IsVoidHelper<typename RemoveCV<T>::Type> {}; + +namespace detail { + +template <typename T> +struct IsIntegralHelper : FalseType {}; + +template<> struct IsIntegralHelper<char> : TrueType {}; +template<> struct IsIntegralHelper<signed char> : TrueType {}; +template<> struct IsIntegralHelper<unsigned char> : TrueType {}; +template<> struct IsIntegralHelper<short> : TrueType {}; +template<> struct IsIntegralHelper<unsigned short> : TrueType {}; +template<> struct IsIntegralHelper<int> : TrueType {}; +template<> struct IsIntegralHelper<unsigned int> : TrueType {}; +template<> struct IsIntegralHelper<long> : TrueType {}; +template<> struct IsIntegralHelper<unsigned long> : TrueType {}; +template<> struct IsIntegralHelper<long long> : TrueType {}; +template<> struct IsIntegralHelper<unsigned long long> : TrueType {}; +template<> struct IsIntegralHelper<bool> : TrueType {}; +template<> struct IsIntegralHelper<wchar_t> : TrueType {}; +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +template<> struct IsIntegralHelper<char16_t> : TrueType {}; +#endif + +} /* namespace detail */ + +/** + * IsIntegral determines whether a type is an integral type. + * + * mozilla::IsIntegral<int>::value is true; + * mozilla::IsIntegral<unsigned short>::value is true; + * mozilla::IsIntegral<const long>::value is true; + * mozilla::IsIntegral<int*>::value is false; + * mozilla::IsIntegral<double>::value is false; + * + * Note that the behavior of IsIntegral on char16_t and char32_t is + * unspecified. + */ +template<typename T> +struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type> +{}; + +template<typename T, typename U> +struct IsSame; + +namespace detail { + +template<typename T> +struct IsFloatingPointHelper + : IntegralConstant<bool, + IsSame<T, float>::value || + IsSame<T, double>::value || + IsSame<T, long double>::value> +{}; + +} // namespace detail + +/** + * IsFloatingPoint determines whether a type is a floating point type (float, + * double, long double). + * + * mozilla::IsFloatingPoint<int>::value is false; + * mozilla::IsFloatingPoint<const float>::value is true; + * mozilla::IsFloatingPoint<long double>::value is true; + * mozilla::IsFloatingPoint<double*>::value is false. + */ +template<typename T> +struct IsFloatingPoint + : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type> +{}; + +namespace detail { + +template<typename T> +struct IsArrayHelper : FalseType {}; + +template<typename T, decltype(sizeof(1)) N> +struct IsArrayHelper<T[N]> : TrueType {}; + +template<typename T> +struct IsArrayHelper<T[]> : TrueType {}; + +} // namespace detail + +/** + * IsArray determines whether a type is an array type, of known or unknown + * length. + * + * mozilla::IsArray<int>::value is false; + * mozilla::IsArray<int[]>::value is true; + * mozilla::IsArray<int[5]>::value is true. + */ +template<typename T> +struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type> +{}; + +namespace detail { + +template<typename T> +struct IsPointerHelper : FalseType {}; + +template<typename T> +struct IsPointerHelper<T*> : TrueType {}; + +} // namespace detail + +/** + * IsPointer determines whether a type is a possibly-CV-qualified pointer type + * (but not a pointer-to-member type). + * + * mozilla::IsPointer<struct S*>::value is true; + * mozilla::IsPointer<int*>::value is true; + * mozilla::IsPointer<int**>::value is true; + * mozilla::IsPointer<const int*>::value is true; + * mozilla::IsPointer<int* const>::value is true; + * mozilla::IsPointer<int* volatile>::value is true; + * mozilla::IsPointer<void (*)(void)>::value is true; + * mozilla::IsPointer<int>::value is false; + * mozilla::IsPointer<struct S>::value is false. + * mozilla::IsPointer<int(struct S::*)>::value is false + */ +template<typename T> +struct IsPointer : detail::IsPointerHelper<typename RemoveCV<T>::Type> +{}; + +/** + * IsLvalueReference determines whether a type is an lvalue reference. + * + * mozilla::IsLvalueReference<struct S*>::value is false; + * mozilla::IsLvalueReference<int**>::value is false; + * mozilla::IsLvalueReference<void (*)(void)>::value is false; + * mozilla::IsLvalueReference<int>::value is false; + * mozilla::IsLvalueReference<struct S>::value is false; + * mozilla::IsLvalueReference<struct S*&>::value is true; + * mozilla::IsLvalueReference<struct S&&>::value is false. + */ +template<typename T> +struct IsLvalueReference : FalseType {}; + +template<typename T> +struct IsLvalueReference<T&> : TrueType {}; + +/** + * IsRvalueReference determines whether a type is an rvalue reference. + * + * mozilla::IsRvalueReference<struct S*>::value is false; + * mozilla::IsRvalueReference<int**>::value is false; + * mozilla::IsRvalueReference<void (*)(void)>::value is false; + * mozilla::IsRvalueReference<int>::value is false; + * mozilla::IsRvalueReference<struct S>::value is false; + * mozilla::IsRvalueReference<struct S*&>::value is false; + * mozilla::IsRvalueReference<struct S&&>::value is true. + */ +template<typename T> +struct IsRvalueReference : FalseType {}; + +template<typename T> +struct IsRvalueReference<T&&> : TrueType {}; + +namespace detail { + +// __is_enum is a supported extension across all of our supported compilers. +template<typename T> +struct IsEnumHelper + : IntegralConstant<bool, __is_enum(T)> +{}; + +} // namespace detail + +/** + * IsEnum determines whether a type is an enum type. + * + * mozilla::IsEnum<enum S>::value is true; + * mozilla::IsEnum<enum S*>::value is false; + * mozilla::IsEnum<int>::value is false; + */ +template<typename T> +struct IsEnum + : detail::IsEnumHelper<typename RemoveCV<T>::Type> +{}; + +namespace detail { + +// __is_class is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template<typename T> +struct IsClassHelper + : IntegralConstant<bool, __is_class(T)> +{}; + +} // namespace detail + +/** + * IsClass determines whether a type is a class type (but not a union). + * + * struct S {}; + * union U {}; + * mozilla::IsClass<int>::value is false; + * mozilla::IsClass<const S>::value is true; + * mozilla::IsClass<U>::value is false; + */ +template<typename T> +struct IsClass + : detail::IsClassHelper<typename RemoveCV<T>::Type> +{}; + +/* 20.9.4.2 Composite type traits [meta.unary.comp] */ + +/** + * IsReference determines whether a type is an lvalue or rvalue reference. + * + * mozilla::IsReference<struct S*>::value is false; + * mozilla::IsReference<int**>::value is false; + * mozilla::IsReference<int&>::value is true; + * mozilla::IsReference<void (*)(void)>::value is false; + * mozilla::IsReference<const int&>::value is true; + * mozilla::IsReference<int>::value is false; + * mozilla::IsReference<struct S>::value is false; + * mozilla::IsReference<struct S&>::value is true; + * mozilla::IsReference<struct S*&>::value is true; + * mozilla::IsReference<struct S&&>::value is true. + */ +template<typename T> +struct IsReference + : IntegralConstant<bool, + IsLvalueReference<T>::value || IsRvalueReference<T>::value> +{}; + +/** + * IsArithmetic determines whether a type is arithmetic. A type is arithmetic + * iff it is an integral type or a floating point type. + * + * mozilla::IsArithmetic<int>::value is true; + * mozilla::IsArithmetic<double>::value is true; + * mozilla::IsArithmetic<long double*>::value is false. + */ +template<typename T> +struct IsArithmetic + : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value> +{}; + +/* 20.9.4.3 Type properties [meta.unary.prop] */ + +/** + * IsConst determines whether a type is const or not. + * + * mozilla::IsConst<int>::value is false; + * mozilla::IsConst<void* const>::value is true; + * mozilla::IsConst<const char*>::value is false. + */ +template<typename T> +struct IsConst : FalseType {}; + +template<typename T> +struct IsConst<const T> : TrueType {}; + +/** + * IsVolatile determines whether a type is volatile or not. + * + * mozilla::IsVolatile<int>::value is false; + * mozilla::IsVolatile<void* volatile>::value is true; + * mozilla::IsVolatile<volatile char*>::value is false. + */ +template<typename T> +struct IsVolatile : FalseType {}; + +template<typename T> +struct IsVolatile<volatile T> : TrueType {}; + +/** + * Traits class for identifying POD types. Until C++11 there's no automatic + * way to detect PODs, so for the moment this is done manually. Users may + * define specializations of this class that inherit from mozilla::TrueType and + * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or + * false>, or conveniently from mozilla::IsPod for composite types) as needed to + * ensure correct IsPod behavior. + */ +template<typename T> +struct IsPod : public FalseType {}; + +template<> struct IsPod<char> : TrueType {}; +template<> struct IsPod<signed char> : TrueType {}; +template<> struct IsPod<unsigned char> : TrueType {}; +template<> struct IsPod<short> : TrueType {}; +template<> struct IsPod<unsigned short> : TrueType {}; +template<> struct IsPod<int> : TrueType {}; +template<> struct IsPod<unsigned int> : TrueType {}; +template<> struct IsPod<long> : TrueType {}; +template<> struct IsPod<unsigned long> : TrueType {}; +template<> struct IsPod<long long> : TrueType {}; +template<> struct IsPod<unsigned long long> : TrueType {}; +template<> struct IsPod<bool> : TrueType {}; +template<> struct IsPod<float> : TrueType {}; +template<> struct IsPod<double> : TrueType {}; +template<> struct IsPod<wchar_t> : TrueType {}; +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +template<> struct IsPod<char16_t> : TrueType {}; +#endif +template<typename T> struct IsPod<T*> : TrueType {}; + +namespace detail { + +// __is_empty is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template<typename T> +struct IsEmptyHelper + : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)> +{}; + +} // namespace detail + +/** + * IsEmpty determines whether a type is a class (but not a union) that is empty. + * + * A class is empty iff it and all its base classes have no non-static data + * members (except bit-fields of length 0) and no virtual member functions, and + * no base class is empty or a virtual base class. + * + * Intuitively, empty classes don't have any data that has to be stored in + * instances of those classes. (The size of the class must still be non-zero, + * because distinct array elements of any type must have different addresses. + * However, if the Empty Base Optimization is implemented by the compiler [most + * compilers implement it, and in certain cases C++11 requires it], the size of + * a class inheriting from an empty |Base| class need not be inflated by + * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or + * vtable pointers that must be stored in each instance for proper behavior. + * + * static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty"); + * union U1 { int x; }; + * static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty"); + * struct E1 {}; + * struct E2 { int : 0 }; + * struct E3 : E1 {}; + * struct E4 : E2 {}; + * static_assert(mozilla::IsEmpty<E1>::value && + * mozilla::IsEmpty<E2>::value && + * mozilla::IsEmpty<E3>::value && + * mozilla::IsEmpty<E4>::value, + * "all empty"); + * union U2 { E1 e1; }; + * static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty"); + * struct NE1 { int x; }; + * struct NE2 : virtual E1 {}; + * struct NE3 : E2 { virtual ~NE3() {} }; + * struct NE4 { virtual void f() {} }; + * static_assert(!mozilla::IsEmpty<NE1>::value && + * !mozilla::IsEmpty<NE2>::value && + * !mozilla::IsEmpty<NE3>::value && + * !mozilla::IsEmpty<NE4>::value, + * "all empty"); + */ +template<typename T> +struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type> +{}; + + +namespace detail { + +template<typename T, + bool = IsFloatingPoint<T>::value, + bool = IsIntegral<T>::value, + typename NoCV = typename RemoveCV<T>::Type> +struct IsSignedHelper; + +// Floating point is signed. +template<typename T, typename NoCV> +struct IsSignedHelper<T, true, false, NoCV> : TrueType {}; + +// Integral is conditionally signed. +template<typename T, typename NoCV> +struct IsSignedHelper<T, false, true, NoCV> + : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))> +{}; + +// Non-floating point, non-integral is not signed. +template<typename T, typename NoCV> +struct IsSignedHelper<T, false, false, NoCV> : FalseType {}; + +} // namespace detail + +/** + * IsSigned determines whether a type is a signed arithmetic type. |char| is + * considered a signed type if it has the same representation as |signed char|. + * + * mozilla::IsSigned<int>::value is true; + * mozilla::IsSigned<const unsigned int>::value is false; + * mozilla::IsSigned<unsigned char>::value is false; + * mozilla::IsSigned<float>::value is true. + */ +template<typename T> +struct IsSigned : detail::IsSignedHelper<T> {}; + +namespace detail { + +template<typename T, + bool = IsFloatingPoint<T>::value, + bool = IsIntegral<T>::value, + typename NoCV = typename RemoveCV<T>::Type> +struct IsUnsignedHelper; + +// Floating point is not unsigned. +template<typename T, typename NoCV> +struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {}; + +// Integral is conditionally unsigned. +template<typename T, typename NoCV> +struct IsUnsignedHelper<T, false, true, NoCV> + : IntegralConstant<bool, + (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))> +{}; + +// Non-floating point, non-integral is not unsigned. +template<typename T, typename NoCV> +struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {}; + +} // namespace detail + +/** + * IsUnsigned determines whether a type is an unsigned arithmetic type. + * + * mozilla::IsUnsigned<int>::value is false; + * mozilla::IsUnsigned<const unsigned int>::value is true; + * mozilla::IsUnsigned<unsigned char>::value is true; + * mozilla::IsUnsigned<float>::value is false. + */ +template<typename T> +struct IsUnsigned : detail::IsUnsignedHelper<T> {}; + +/* 20.9.5 Type property queries [meta.unary.prop.query] */ + +/* 20.9.6 Relationships between types [meta.rel] */ + +/** + * IsSame tests whether two types are the same type. + * + * mozilla::IsSame<int, int>::value is true; + * mozilla::IsSame<int*, int*>::value is true; + * mozilla::IsSame<int, unsigned int>::value is false; + * mozilla::IsSame<void, void>::value is true; + * mozilla::IsSame<const int, int>::value is false; + * mozilla::IsSame<struct S, struct S>::value is true. + */ +template<typename T, typename U> +struct IsSame : FalseType {}; + +template<typename T> +struct IsSame<T, T> : TrueType {}; + +namespace detail { + +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) + +template<class Base, class Derived> +struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {}; + +#else + +// The trickery used to implement IsBaseOf here makes it possible to use it for +// the cases of private and multiple inheritance. This code was inspired by the +// sample code here: +// +// http://stackoverflow.com/questions/2910979/how-is-base-of-works +template<class Base, class Derived> +struct BaseOfHelper +{ +public: + operator Base*() const; + operator Derived*(); +}; + +template<class Base, class Derived> +struct BaseOfTester +{ +private: + template<class T> + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char); +}; + +template<class Base, class Derived> +struct BaseOfTester<Base, const Derived> +{ +private: + template<class T> + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char); +}; + +template<class Base, class Derived> +struct BaseOfTester<Base&, Derived&> : FalseType {}; + +template<class Type> +struct BaseOfTester<Type, Type> : TrueType {}; + +template<class Type> +struct BaseOfTester<Type, const Type> : TrueType {}; + +#endif + +} /* namespace detail */ + +/* + * IsBaseOf allows to know whether a given class is derived from another. + * + * Consider the following class definitions: + * + * class A {}; + * class B : public A {}; + * class C {}; + * + * mozilla::IsBaseOf<A, B>::value is true; + * mozilla::IsBaseOf<A, C>::value is false; + */ +template<class Base, class Derived> +struct IsBaseOf + : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value> +{}; + +namespace detail { + +template<typename From, typename To> +struct ConvertibleTester +{ +private: + static From create(); + + template<typename From1, typename To1> + static char test(To to); + + template<typename From1, typename To1> + static int test(...); + +public: + static const bool value = + sizeof(test<From, To>(create())) == sizeof(char); +}; + +} // namespace detail + +/** + * IsConvertible determines whether a value of type From will implicitly convert + * to a value of type To. For example: + * + * struct A {}; + * struct B : public A {}; + * struct C {}; + * + * mozilla::IsConvertible<A, A>::value is true; + * mozilla::IsConvertible<A*, A*>::value is true; + * mozilla::IsConvertible<B, A>::value is true; + * mozilla::IsConvertible<B*, A*>::value is true; + * mozilla::IsConvertible<C, A>::value is false; + * mozilla::IsConvertible<A, C>::value is false; + * mozilla::IsConvertible<A*, C*>::value is false; + * mozilla::IsConvertible<C*, A*>::value is false. + * + * For obscure reasons, you can't use IsConvertible when the types being tested + * are related through private inheritance, and you'll get a compile error if + * you try. Just don't do it! + * + * Note - we need special handling for void, which ConvertibleTester doesn't + * handle. The void handling here doesn't handle const/volatile void correctly, + * which could be easily fixed if the need arises. + */ +template<typename From, typename To> +struct IsConvertible + : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value> +{}; + +template<typename B> +struct IsConvertible<void, B> + : IntegralConstant<bool, IsVoid<B>::value> +{}; + +template<typename A> +struct IsConvertible<A, void> + : IntegralConstant<bool, IsVoid<A>::value> +{}; + +template<> +struct IsConvertible<void, void> + : TrueType +{}; + +/* 20.9.7 Transformations between types [meta.trans] */ + +/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */ + +/** + * RemoveConst removes top-level const qualifications on a type. + * + * mozilla::RemoveConst<int>::Type is int; + * mozilla::RemoveConst<const int>::Type is int; + * mozilla::RemoveConst<const int*>::Type is const int*; + * mozilla::RemoveConst<int* const>::Type is int*. + */ +template<typename T> +struct RemoveConst +{ + typedef T Type; +}; + +template<typename T> +struct RemoveConst<const T> +{ + typedef T Type; +}; + +/** + * RemoveVolatile removes top-level volatile qualifications on a type. + * + * mozilla::RemoveVolatile<int>::Type is int; + * mozilla::RemoveVolatile<volatile int>::Type is int; + * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*; + * mozilla::RemoveVolatile<int* volatile>::Type is int*. + */ +template<typename T> +struct RemoveVolatile +{ + typedef T Type; +}; + +template<typename T> +struct RemoveVolatile<volatile T> +{ + typedef T Type; +}; + +/** + * RemoveCV removes top-level const and volatile qualifications on a type. + * + * mozilla::RemoveCV<int>::Type is int; + * mozilla::RemoveCV<const int>::Type is int; + * mozilla::RemoveCV<volatile int>::Type is int; + * mozilla::RemoveCV<int* const volatile>::Type is int*. + */ +template<typename T> +struct RemoveCV +{ + typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type; +}; + +/* 20.9.7.2 Reference modifications [meta.trans.ref] */ + +/** + * Converts reference types to the underlying types. + * + * mozilla::RemoveReference<T>::Type is T; + * mozilla::RemoveReference<T&>::Type is T; + * mozilla::RemoveReference<T&&>::Type is T; + */ + +template<typename T> +struct RemoveReference +{ + typedef T Type; +}; + +template<typename T> +struct RemoveReference<T&> +{ + typedef T Type; +}; + +template<typename T> +struct RemoveReference<T&&> +{ + typedef T Type; +}; + +template<bool Condition, typename A, typename B> +struct Conditional; + +namespace detail { + +enum Voidness { TIsVoid, TIsNotVoid }; + +template<typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid> +struct AddLvalueReferenceHelper; + +template<typename T> +struct AddLvalueReferenceHelper<T, TIsVoid> +{ + typedef void Type; +}; + +template<typename T> +struct AddLvalueReferenceHelper<T, TIsNotVoid> +{ + typedef T& Type; +}; + +} // namespace detail + +/** + * AddLvalueReference adds an lvalue & reference to T if one isn't already + * present. (Note: adding an lvalue reference to an rvalue && reference in + * essence replaces the && with a &&, per C+11 reference collapsing rules. For + * example, int&& would become int&.) + * + * The final computed type will only *not* be an lvalue reference if T is void. + * + * mozilla::AddLvalueReference<int>::Type is int&; + * mozilla::AddLvalueRference<volatile int&>::Type is volatile int&; + * mozilla::AddLvalueReference<void*>::Type is void*&; + * mozilla::AddLvalueReference<void>::Type is void; + * mozilla::AddLvalueReference<struct S&&>::Type is struct S&. + */ +template<typename T> +struct AddLvalueReference + : detail::AddLvalueReferenceHelper<T> +{}; + +namespace detail { + +template<typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid> +struct AddRvalueReferenceHelper; + +template<typename T> +struct AddRvalueReferenceHelper<T, TIsVoid> +{ + typedef void Type; +}; + +template<typename T> +struct AddRvalueReferenceHelper<T, TIsNotVoid> +{ + typedef T&& Type; +}; + +} // namespace detail + +/** + * AddRvalueReference adds an rvalue && reference to T if one isn't already + * present. (Note: adding an rvalue reference to an lvalue & reference in + * essence keeps the &, per C+11 reference collapsing rules. For example, + * int& would remain int&.) + * + * The final computed type will only *not* be a reference if T is void. + * + * mozilla::AddRvalueReference<int>::Type is int&&; + * mozilla::AddRvalueRference<volatile int&>::Type is volatile int&; + * mozilla::AddRvalueRference<const int&&>::Type is const int&&; + * mozilla::AddRvalueReference<void*>::Type is void*&&; + * mozilla::AddRvalueReference<void>::Type is void; + * mozilla::AddRvalueReference<struct S&>::Type is struct S&. + */ +template<typename T> +struct AddRvalueReference + : detail::AddRvalueReferenceHelper<T> +{}; + +/* 20.2.4 Function template declval [declval] */ + +/** + * DeclVal simplifies the definition of expressions which occur as unevaluated + * operands. It converts T to a reference type, making it possible to use in + * decltype expressions even if T does not have a default constructor, e.g.: + * decltype(DeclVal<TWithNoDefaultConstructor>().foo()) + */ +template<typename T> +typename AddRvalueReference<T>::Type DeclVal(); + +/* 20.9.7.3 Sign modifications [meta.trans.sign] */ + +template<bool B, typename T = void> +struct EnableIf; + +namespace detail { + +template<bool MakeConst, typename T> +struct WithC : Conditional<MakeConst, const T, T> +{}; + +template<bool MakeVolatile, typename T> +struct WithV : Conditional<MakeVolatile, volatile T, T> +{}; + + +template<bool MakeConst, bool MakeVolatile, typename T> +struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type> +{}; + +template<typename T> +struct CorrespondingSigned; + +template<> +struct CorrespondingSigned<char> { typedef signed char Type; }; +template<> +struct CorrespondingSigned<unsigned char> { typedef signed char Type; }; +template<> +struct CorrespondingSigned<unsigned short> { typedef short Type; }; +template<> +struct CorrespondingSigned<unsigned int> { typedef int Type; }; +template<> +struct CorrespondingSigned<unsigned long> { typedef long Type; }; +template<> +struct CorrespondingSigned<unsigned long long> { typedef long long Type; }; + +template<typename T, + typename CVRemoved = typename RemoveCV<T>::Type, + bool IsSignedIntegerType = IsSigned<CVRemoved>::value && + !IsSame<char, CVRemoved>::value> +struct MakeSigned; + +template<typename T, typename CVRemoved> +struct MakeSigned<T, CVRemoved, true> +{ + typedef T Type; +}; + +template<typename T, typename CVRemoved> +struct MakeSigned<T, CVRemoved, false> + : WithCV<IsConst<T>::value, IsVolatile<T>::value, + typename CorrespondingSigned<CVRemoved>::Type> +{}; + +} // namespace detail + +/** + * MakeSigned produces the corresponding signed integer type for a given + * integral type T, with the const/volatile qualifiers of T. T must be a + * possibly-const/volatile-qualified integral type that isn't bool. + * + * If T is already a signed integer type (not including char!), then T is + * produced. + * + * Otherwise, if T is an unsigned integer type, the signed variety of T, with + * T's const/volatile qualifiers, is produced. + * + * Otherwise, the integral type of the same size as T, with the lowest rank, + * with T's const/volatile qualifiers, is produced. (This basically only acts + * to produce signed char when T = char.) + * + * mozilla::MakeSigned<unsigned long>::Type is signed long; + * mozilla::MakeSigned<volatile int>::Type is volatile int; + * mozilla::MakeSigned<const unsigned short>::Type is const signed short; + * mozilla::MakeSigned<const char>::Type is const signed char; + * mozilla::MakeSigned<bool> is an error; + * mozilla::MakeSigned<void*> is an error. + */ +template<typename T> +struct MakeSigned + : EnableIf<IsIntegral<T>::value && + !IsSame<bool, typename RemoveCV<T>::Type>::value, + typename detail::MakeSigned<T> + >::Type +{}; + +namespace detail { + +template<typename T> +struct CorrespondingUnsigned; + +template<> +struct CorrespondingUnsigned<char> { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned<short> { typedef unsigned short Type; }; +template<> +struct CorrespondingUnsigned<int> { typedef unsigned int Type; }; +template<> +struct CorrespondingUnsigned<long> { typedef unsigned long Type; }; +template<> +struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; }; + + +template<typename T, + typename CVRemoved = typename RemoveCV<T>::Type, + bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value && + !IsSame<char, CVRemoved>::value> +struct MakeUnsigned; + +template<typename T, typename CVRemoved> +struct MakeUnsigned<T, CVRemoved, true> +{ + typedef T Type; +}; + +template<typename T, typename CVRemoved> +struct MakeUnsigned<T, CVRemoved, false> + : WithCV<IsConst<T>::value, IsVolatile<T>::value, + typename CorrespondingUnsigned<CVRemoved>::Type> +{}; + +} // namespace detail + +/** + * MakeUnsigned produces the corresponding unsigned integer type for a given + * integral type T, with the const/volatile qualifiers of T. T must be a + * possibly-const/volatile-qualified integral type that isn't bool. + * + * If T is already an unsigned integer type (not including char!), then T is + * produced. + * + * Otherwise, if T is an signed integer type, the unsigned variety of T, with + * T's const/volatile qualifiers, is produced. + * + * Otherwise, the unsigned integral type of the same size as T, with the lowest + * rank, with T's const/volatile qualifiers, is produced. (This basically only + * acts to produce unsigned char when T = char.) + * + * mozilla::MakeUnsigned<signed long>::Type is unsigned long; + * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int; + * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short; + * mozilla::MakeUnsigned<const char>::Type is const unsigned char; + * mozilla::MakeUnsigned<bool> is an error; + * mozilla::MakeUnsigned<void*> is an error. + */ +template<typename T> +struct MakeUnsigned + : EnableIf<IsIntegral<T>::value && + !IsSame<bool, typename RemoveCV<T>::Type>::value, + typename detail::MakeUnsigned<T> + >::Type +{}; + +/* 20.9.7.4 Array modifications [meta.trans.arr] */ + +/** + * RemoveExtent produces either the type of the elements of the array T, or T + * itself. + * + * mozilla::RemoveExtent<int>::Type is int; + * mozilla::RemoveExtent<const int[]>::Type is const int; + * mozilla::RemoveExtent<volatile int[5]>::Type is volatile int; + * mozilla::RemoveExtent<long[][17]>::Type is long[17]. + */ +template<typename T> +struct RemoveExtent +{ + typedef T Type; +}; + +template<typename T> +struct RemoveExtent<T[]> +{ + typedef T Type; +}; + +template<typename T, decltype(sizeof(1)) N> +struct RemoveExtent<T[N]> +{ + typedef T Type; +}; + +/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ + +namespace detail { + +template<typename T, typename CVRemoved> +struct RemovePointerHelper +{ + typedef T Type; +}; + +template<typename T, typename Pointee> +struct RemovePointerHelper<T, Pointee*> +{ + typedef Pointee Type; +}; + +} // namespac detail + +/** + * Produces the pointed-to type if a pointer is provided, else returns the input + * type. Note that this does not dereference pointer-to-member pointers. + * + * struct S { bool m; void f(); }; + * mozilla::RemovePointer<int>::Type is int; + * mozilla::RemovePointer<int*>::Type is int; + * mozilla::RemovePointer<int* const>::Type is int; + * mozilla::RemovePointer<int* volatile>::Type is int; + * mozilla::RemovePointer<const long*>::Type is const long; + * mozilla::RemovePointer<void* const>::Type is void; + * mozilla::RemovePointer<void (S::*)()>::Type is void (S::*)(); + * mozilla::RemovePointer<void (*)()>::Type is void(); + * mozilla::RemovePointer<bool S::*>::Type is bool S::*. + */ +template<typename T> +struct RemovePointer + : detail::RemovePointerHelper<T, typename RemoveCV<T>::Type> +{}; + +/* 20.9.7.6 Other transformations [meta.trans.other] */ + +/** + * EnableIf is a struct containing a typedef of T if and only if B is true. + * + * mozilla::EnableIf<true, int>::Type is int; + * mozilla::EnableIf<false, int>::Type is a compile-time error. + * + * Use this template to implement SFINAE-style (Substitution Failure Is not An + * Error) requirements. For example, you might use it to impose a restriction + * on a template parameter: + * + * template<typename T> + * class PodVector // vector optimized to store POD (memcpy-able) types + * { + * EnableIf<IsPod<T>::value, T>::Type* vector; + * size_t length; + * ... + * }; + */ +template<bool B, typename T> +struct EnableIf +{}; + +template<typename T> +struct EnableIf<true, T> +{ + typedef T Type; +}; + +/** + * Conditional selects a class between two, depending on a given boolean value. + * + * mozilla::Conditional<true, A, B>::Type is A; + * mozilla::Conditional<false, A, B>::Type is B; + */ +template<bool Condition, typename A, typename B> +struct Conditional +{ + typedef A Type; +}; + +template<class A, class B> +struct Conditional<false, A, B> +{ + typedef B Type; +}; + +} /* namespace mozilla */ + +#endif /* mozilla_TypeTraits_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Types.h b/onlineupdate/source/update/inc/mozilla/Types.h new file mode 100644 index 000000000000..a5d936389d99 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Types.h @@ -0,0 +1,134 @@ +/* -*- 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/. */ + +/* mfbt foundational types and macros. */ + +#ifndef mozilla_Types_h +#define mozilla_Types_h + +/* + * This header must be valid C and C++, includable by code embedding either + * SpiderMonkey or Gecko. + */ + +/* Expose all <stdint.h> types and size_t. */ +#include <stddef.h> +#include <stdint.h> + +/* Implement compiler and linker macros needed for APIs. */ + +/* + * MOZ_EXPORT is used to declare and define a symbol or type which is externally + * visible to users of the current library. It encapsulates various decorations + * needed to properly export the method's symbol. + * + * api.h: + * extern MOZ_EXPORT int MeaningOfLife(void); + * extern MOZ_EXPORT int LuggageCombination; + * + * api.c: + * int MeaningOfLife(void) { return 42; } + * int LuggageCombination = 12345; + * + * If you are merely sharing a method across files, just use plain |extern|. + * These macros are designed for use by library interfaces -- not for normal + * methods or data used cross-file. + */ +#if defined(WIN32) +# define MOZ_EXPORT __declspec(dllexport) +#else /* Unix */ +# ifdef HAVE_VISIBILITY_ATTRIBUTE +# define MOZ_EXPORT __attribute__((visibility("default"))) +# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define MOZ_EXPORT __global +# else +# define MOZ_EXPORT /* nothing */ +# endif +#endif + + +/* + * Whereas implementers use MOZ_EXPORT to declare and define library symbols, + * users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to access them. Most often the + * implementer of the library will expose an API macro which expands to either + * the export or import version of the macro, depending upon the compilation + * mode. + */ +#ifdef _WIN32 +# if defined(__MWERKS__) +# define MOZ_IMPORT_API /* nothing */ +# else +# define MOZ_IMPORT_API __declspec(dllimport) +# endif +#else +# define MOZ_IMPORT_API MOZ_EXPORT +#endif + +#if defined(_WIN32) && !defined(__MWERKS__) +# define MOZ_IMPORT_DATA __declspec(dllimport) +#else +# define MOZ_IMPORT_DATA MOZ_EXPORT +#endif + +/* + * Consistent with the above comment, the MFBT_API and MFBT_DATA macros expose + * export mfbt declarations when building mfbt, and they expose import mfbt + * declarations when using mfbt. + */ +#if defined(IMPL_MFBT) +# define MFBT_API MOZ_EXPORT +# define MFBT_DATA MOZ_EXPORT +#else + /* + * On linux mozglue is linked in the program and we link libxul.so with + * -z,defs. Normally that causes the linker to reject undefined references in + * libxul.so, but as a loophole it allows undefined references to weak + * symbols. We add the weak attribute to the import version of the MFBT API + * macros to exploit this. + */ +# if defined(MOZ_GLUE_IN_PROGRAM) && !defined(MOZILLA_XPCOMRT_API) +# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API +# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA +# else +# define MFBT_API MOZ_IMPORT_API +# define MFBT_DATA MOZ_IMPORT_DATA +# endif +#endif + +/* + * C symbols in C++ code must be declared immediately within |extern "C"| + * blocks. However, in C code, they need not be declared specially. This + * difference is abstracted behind the MOZ_BEGIN_EXTERN_C and MOZ_END_EXTERN_C + * macros, so that the user need not know whether he is being used in C or C++ + * code. + * + * MOZ_BEGIN_EXTERN_C + * + * extern MOZ_EXPORT int MostRandomNumber(void); + * ...other declarations... + * + * MOZ_END_EXTERN_C + * + * This said, it is preferable to just use |extern "C"| in C++ header files for + * its greater clarity. + */ +#ifdef __cplusplus +# define MOZ_BEGIN_EXTERN_C extern "C" { +# define MOZ_END_EXTERN_C } +#else +# define MOZ_BEGIN_EXTERN_C +# define MOZ_END_EXTERN_C +#endif + +/* + * GCC's typeof is available when decltype is not. + */ +#if defined(__GNUC__) && defined(__cplusplus) && \ + !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L +# define decltype __typeof__ +#endif + +#endif /* mozilla_Types_h */ diff --git a/onlineupdate/source/update/inc/mozilla/nsTraceRefcnt.h b/onlineupdate/source/update/inc/mozilla/nsTraceRefcnt.h new file mode 100644 index 000000000000..c5b1de7e806a --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/nsTraceRefcnt.h @@ -0,0 +1,67 @@ +/* -*- 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 nsTraceRefcnt_h___ +#define nsTraceRefcnt_h___ + +#include <stdio.h> // for FILE +#include "nscore.h" + +class nsTraceRefcnt +{ +public: + static void Shutdown(); + + enum StatisticsType { + ALL_STATS, + NEW_STATS + }; + + static nsresult DumpStatistics(StatisticsType aType = ALL_STATS, + FILE* aOut = 0); + + static void ResetStatistics(); + + static void DemangleSymbol(const char* aSymbol, char* aBuffer, int aBufLen); + + static void WalkTheStack(FILE* aStream); + + /** + * This is a variant of |WalkTheStack| that uses |CodeAddressService| to cache + * the results of |NS_DescribeCodeAddress|. If |WalkTheStackCached| is being + * called frequently, it will be a few orders of magnitude faster than + * |WalkTheStack|. However, the cache uses a lot of memory, which can cause + * OOM crashes. Therefore, this should only be used for things like refcount + * logging which walk the stack extremely frequently. + */ + static void WalkTheStackCached(FILE* aStream); + + /** + * Tell nsTraceRefcnt whether refcounting, allocation, and destruction + * activity is legal. This is used to trigger assertions for any such + * activity that occurs because of static constructors or destructors. + */ + static void SetActivityIsLegal(bool aLegal); +}; + +#define NS_TRACE_REFCNT_CONTRACTID "@mozilla.org/xpcom/trace-refcnt;1" +#define NS_TRACE_REFCNT_CID \ +{ /* e3e7511e-a395-4924-94b1-d527861cded4 */ \ + 0xe3e7511e, \ + 0xa395, \ + 0x4924, \ + {0x94, 0xb1, 0xd5, 0x27, 0x86, 0x1c, 0xde, 0xd4} \ +} \ + +//////////////////////////////////////////////////////////////////////////////// +// And now for that utility that you've all been asking for... + +extern "C" void +NS_MeanAndStdDev(double aNumberOfValues, + double aSumOfValues, double aSumOfSquaredValues, + double* aMeanResult, double* aStdDevResult); + +//////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/onlineupdate/source/update/src/Makefile.in b/onlineupdate/source/update/src/Makefile.in new file mode 100644 index 000000000000..1da582e5be03 --- /dev/null +++ b/onlineupdate/source/update/src/Makefile.in @@ -0,0 +1,13 @@ +# 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/. + +# This makefile just builds support for reading archives. + +include $(topsrcdir)/config/rules.mk + +# The intermediate (.ii/.s) files for host and target can have the same name... +# disable parallel builds +.NOTPARALLEL: diff --git a/onlineupdate/source/update/src/mar.h b/onlineupdate/source/update/src/mar.h new file mode 100644 index 000000000000..0e9dc1f137bd --- /dev/null +++ b/onlineupdate/source/update/src/mar.h @@ -0,0 +1,198 @@ +/* -*- 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 MAR_H__ +#define MAR_H__ + +#include "mozilla/Assertions.h" +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* We have a MAX_SIGNATURES limit so that an invalid MAR will never + * waste too much of either updater's or signmar's time. + * It is also used at various places internally and will affect memory usage. + * If you want to increase this value above 9 then you need to adjust parsing + * code in tool/mar.c. +*/ +#define MAX_SIGNATURES 8 +#ifdef __cplusplus +static_assert(MAX_SIGNATURES <= 9, "too many signatures"); +#else +MOZ_STATIC_ASSERT(MAX_SIGNATURES <= 9, "too many signatures"); +#endif + +struct ProductInformationBlock { + const char *MARChannelID; + const char *productVersion; +}; + +/** + * The MAR item data structure. + */ +typedef struct MarItem_ { + struct MarItem_ *next; /* private field */ + uint32_t offset; /* offset into archive */ + uint32_t length; /* length of data in bytes */ + uint32_t flags; /* contains file mode bits */ + char name[1]; /* file path */ +} MarItem; + +#define TABLESIZE 256 + +struct MarFile_ { + FILE *fp; + MarItem *item_table[TABLESIZE]; +}; + +typedef struct MarFile_ MarFile; + +/** + * Signature of callback function passed to mar_enum_items. + * @param mar The MAR file being visited. + * @param item The MAR item being visited. + * @param data The data parameter passed by the caller of mar_enum_items. + * @return A non-zero value to stop enumerating. + */ +typedef int (* MarItemCallback)(MarFile *mar, const MarItem *item, void *data); + +/** + * Open a MAR file for reading. + * @param path Specifies the path to the MAR file to open. This path must + * be compatible with fopen. + * @return NULL if an error occurs. + */ +MarFile *mar_open(const char *path); + +#ifdef XP_WIN +MarFile *mar_wopen(const wchar_t *path); +#endif + +/** + * Close a MAR file that was opened using mar_open. + * @param mar The MarFile object to close. + */ +void mar_close(MarFile *mar); + +/** + * Find an item in the MAR file by name. + * @param mar The MarFile object to query. + * @param item The name of the item to query. + * @return A const reference to a MAR item or NULL if not found. + */ +const MarItem *mar_find_item(MarFile *mar, const char *item); + +/** + * Enumerate all MAR items via callback function. + * @param mar The MAR file to enumerate. + * @param callback The function to call for each MAR item. + * @param data A caller specified value that is passed along to the + * callback function. + * @return 0 if the enumeration ran to completion. Otherwise, any + * non-zero return value from the callback is returned. + */ +int mar_enum_items(MarFile *mar, MarItemCallback callback, void *data); + +/** + * Read from MAR item at given offset up to bufsize bytes. + * @param mar The MAR file to read. + * @param item The MAR item to read. + * @param offset The byte offset relative to the start of the item. + * @param buf A pointer to a buffer to copy the data into. + * @param bufsize The length of the buffer to copy the data into. + * @return The number of bytes written or a negative value if an + * error occurs. + */ +int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, + int bufsize); + +/** + * Create a MAR file from a set of files. + * @param dest The path to the file to create. This path must be + * compatible with fopen. + * @param numfiles The number of files to store in the archive. + * @param files The list of null-terminated file paths. Each file + * path must be compatible with fopen. + * @param infoBlock The information to store in the product information block. + * @return A non-zero value if an error occurs. + */ +int mar_create(const char *dest, + int numfiles, + char **files, + struct ProductInformationBlock *infoBlock); + +/** + * Extract a MAR file to the current working directory. + * @param path The path to the MAR file to extract. This path must be + * compatible with fopen. + * @return A non-zero value if an error occurs. + */ +int mar_extract(const char *path); + +#define MAR_MAX_CERT_SIZE (16*1024) // Way larger than necessary + +/* Read the entire file (not a MAR file) into a newly-allocated buffer. + * This function does not write to stderr. Instead, the caller should + * write whatever error messages it sees fit. The caller must free the returned + * buffer using free(). + * + * @param filePath The path to the file that should be read. + * @param maxSize The maximum valid file size. + * @param data On success, *data will point to a newly-allocated buffer + * with the file's contents in it. + * @param size On success, *size will be the size of the created buffer. + * + * @return 0 on success, -1 on error + */ +int mar_read_entire_file(const char * filePath, + uint32_t maxSize, + /*out*/ const uint8_t * *data, + /*out*/ uint32_t *size); + +/** + * Verifies a MAR file by verifying each signature with the corresponding + * certificate. That is, the first signature will be verified using the first + * certificate given, the second signature will be verified using the second + * certificate given, etc. The signature count must exactly match the number of + * certificates given, and all signature verifications must succeed. + * We do not check that the certificate was issued by any trusted authority. + * We assume it to be self-signed. We do not check whether the certificate + * is valid for this usage. + * + * @param mar The already opened MAR file. + * @param certData Pointer to the first element in an array of certificate + * file data. + * @param certDataSizes Pointer to the first element in an array for size of + * the cert data. + * @param certCount The number of elements in certData and certDataSizes + * @return 0 on success + * a negative number if there was an error + * a positive number if the signature does not verify + */ +int mar_verify_signatures(MarFile *mar, + const uint8_t * const *certData, + const uint32_t *certDataSizes, + uint32_t certCount); + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +mar_read_product_info_block(MarFile *mar, + struct ProductInformationBlock *infoBlock); + +#ifdef __cplusplus +} +#endif + +#endif /* MAR_H__ */ diff --git a/onlineupdate/source/update/src/mar_cmdline.h b/onlineupdate/source/update/src/mar_cmdline.h new file mode 100644 index 000000000000..ef6867f06fc3 --- /dev/null +++ b/onlineupdate/source/update/src/mar_cmdline.h @@ -0,0 +1,110 @@ +/* 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 MAR_CMDLINE_H__ +#define MAR_CMDLINE_H__ + +/* We use NSPR here just to import the definition of uint32_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ProductInformationBlock; + +/** + * Determines MAR file information. + * + * @param path The path of the MAR file to check. + * @param hasSignatureBlock Optional out parameter specifying if the MAR + * file has a signature block or not. + * @param numSignatures Optional out parameter for storing the number + * of signatures in the MAR file. + * @param hasAdditionalBlocks Optional out parameter specifying if the MAR + * file has additional blocks or not. + * @param offsetAdditionalBlocks Optional out parameter for the offset to the + * first additional block. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @param numAdditionalBlocks Optional out parameter for the number of + * additional blocks. Value is only valid if + * has_additional_blocks is not equal to 0. + * @return 0 on success and non-zero on failure. + */ +int get_mar_file_info(const char *path, + int *hasSignatureBlock, + uint32_t *numSignatures, + int *hasAdditionalBlocks, + uint32_t *offsetAdditionalBlocks, + uint32_t *numAdditionalBlocks); + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +read_product_info_block(char *path, + struct ProductInformationBlock *infoBlock); + +/** + * Refreshes the product information block with the new information. + * The input MAR must not be signed or the function call will fail. + * + * @param path The path to the MAR file whose product info block + * should be refreshed. + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +refresh_product_info_block(const char *path, + struct ProductInformationBlock *infoBlock); + +/** + * Writes out a copy of the MAR at src but with the signature block stripped. + * + * @param src The path of the source MAR file + * @param dest The path of the MAR file to write out that + has no signature block + * @return 0 on success + * -1 on error +*/ +int +strip_signature_block(const char *src, const char * dest); + +/** + * Extracts a signature from a MAR file, base64 encodes it, and writes it out + * + * @param src The path of the source MAR file + * @param sigIndex The index of the signature to extract + * @param dest The path of file to write the signature to + * @return 0 on success + * -1 on error +*/ +int +extract_signature(const char *src, uint32_t sigIndex, const char * dest); + +/** + * Imports a base64 encoded signature into a MAR file + * + * @param src The path of the source MAR file + * @param sigIndex The index of the signature to import + * @param base64SigFile A file which contains the signature to import + * @param dest The path of the destination MAR file with replaced signature + * @return 0 on success + * -1 on error +*/ +int +import_signature(const char *src, + uint32_t sigIndex, + const char * base64SigFile, + const char *dest); + +#ifdef __cplusplus +} +#endif + +#endif /* MAR_CMDLINE_H__ */ diff --git a/onlineupdate/source/update/src/mar_create.c b/onlineupdate/source/update/src/mar_create.c new file mode 100644 index 000000000000..c2ce10126cbd --- /dev/null +++ b/onlineupdate/source/update/src/mar_create.c @@ -0,0 +1,399 @@ +/* -*- 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include "mar_private.h" +#include "mar_cmdline.h" +#include "mar.h" + +#ifdef XP_WIN +#include <winsock2.h> +#else +#include <netinet/in.h> +#include <unistd.h> +#endif + +struct MarItemStack { + void *head; + uint32_t size_used; + uint32_t size_allocated; + uint32_t last_offset; +}; + +/** + * Push a new item onto the stack of items. The stack is a single block + * of memory. + */ +static int mar_push(struct MarItemStack *stack, uint32_t length, uint32_t flags, + const char *name) { + int namelen; + uint32_t n_offset, n_length, n_flags; + uint32_t size; + char *data; + + namelen = strlen(name); + size = MAR_ITEM_SIZE(namelen); + + if (stack->size_allocated - stack->size_used < size) { + /* increase size of stack */ + size_t size_needed = ROUND_UP(stack->size_used + size, BLOCKSIZE); + stack->head = realloc(stack->head, size_needed); + if (!stack->head) + return -1; + stack->size_allocated = size_needed; + } + + data = (((char *) stack->head) + stack->size_used); + + n_offset = htonl(stack->last_offset); + n_length = htonl(length); + n_flags = htonl(flags); + + memcpy(data, &n_offset, sizeof(n_offset)); + data += sizeof(n_offset); + + memcpy(data, &n_length, sizeof(n_length)); + data += sizeof(n_length); + + memcpy(data, &n_flags, sizeof(n_flags)); + data += sizeof(n_flags); + + memcpy(data, name, namelen + 1); + + stack->size_used += size; + stack->last_offset += length; + return 0; +} + +static int mar_concat_file(FILE *fp, const char *path) { + FILE *in; + char buf[BLOCKSIZE]; + size_t len; + int rv = 0; + + in = fopen(path, "rb"); + if (!in) { + fprintf(stderr, "ERROR: could not open file in mar_concat_file()\n"); + perror(path); + return -1; + } + + while ((len = fread(buf, 1, BLOCKSIZE, in)) > 0) { + if (fwrite(buf, len, 1, fp) != 1) { + rv = -1; + break; + } + } + + fclose(in); + return rv; +} + +/** + * Writes out the product information block to the specified file. + * + * @param fp The opened MAR file being created. + * @param stack A pointer to the MAR item stack being used to create + * the MAR + * @param infoBlock The product info block to store in the file. + * @return 0 on success. +*/ +static int +mar_concat_product_info_block(FILE *fp, + struct MarItemStack *stack, + struct ProductInformationBlock *infoBlock) +{ + char buf[PIB_MAX_MAR_CHANNEL_ID_SIZE + PIB_MAX_PRODUCT_VERSION_SIZE]; + uint32_t additionalBlockID = 1, infoBlockSize, unused; + if (!fp || !infoBlock || + !infoBlock->MARChannelID || + !infoBlock->productVersion) { + return -1; + } + + /* The MAR channel name must be < 64 bytes per the spec */ + if (strlen(infoBlock->MARChannelID) > PIB_MAX_MAR_CHANNEL_ID_SIZE) { + return -1; + } + + /* The product version must be < 32 bytes per the spec */ + if (strlen(infoBlock->productVersion) > PIB_MAX_PRODUCT_VERSION_SIZE) { + return -1; + } + + /* Although we don't need the product information block size to include the + maximum MAR channel name and product version, we allocate the maximum + amount to make it easier to modify the MAR file for repurposing MAR files + to different MAR channels. + 2 is for the NULL terminators. */ + infoBlockSize = sizeof(infoBlockSize) + + sizeof(additionalBlockID) + + PIB_MAX_MAR_CHANNEL_ID_SIZE + + PIB_MAX_PRODUCT_VERSION_SIZE + 2; + if (stack) { + stack->last_offset += infoBlockSize; + } + + /* Write out the product info block size */ + infoBlockSize = htonl(infoBlockSize); + if (fwrite(&infoBlockSize, + sizeof(infoBlockSize), 1, fp) != 1) { + return -1; + } + infoBlockSize = ntohl(infoBlockSize); + + /* Write out the product info block ID */ + additionalBlockID = htonl(additionalBlockID); + if (fwrite(&additionalBlockID, + sizeof(additionalBlockID), 1, fp) != 1) { + return -1; + } + additionalBlockID = ntohl(additionalBlockID); + + /* Write out the channel name and NULL terminator */ + if (fwrite(infoBlock->MARChannelID, + strlen(infoBlock->MARChannelID) + 1, 1, fp) != 1) { + return -1; + } + + /* Write out the product version string and NULL terminator */ + if (fwrite(infoBlock->productVersion, + strlen(infoBlock->productVersion) + 1, 1, fp) != 1) { + return -1; + } + + /* Write out the rest of the block that is unused */ + unused = infoBlockSize - (sizeof(infoBlockSize) + + sizeof(additionalBlockID) + + strlen(infoBlock->MARChannelID) + + strlen(infoBlock->productVersion) + 2); + memset(buf, 0, sizeof(buf)); + if (fwrite(buf, unused, 1, fp) != 1) { + return -1; + } + return 0; +} + +/** + * Refreshes the product information block with the new information. + * The input MAR must not be signed or the function call will fail. + * + * @param path The path to the MAR file whose product info block + * should be refreshed. + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +refresh_product_info_block(const char *path, + struct ProductInformationBlock *infoBlock) +{ + FILE *fp ; + int rv; + uint32_t numSignatures, additionalBlockSize, additionalBlockID, + offsetAdditionalBlocks, numAdditionalBlocks, i; + int additionalBlocks, hasSignatureBlock; + int64_t oldPos; + + rv = get_mar_file_info(path, + &hasSignatureBlock, + &numSignatures, + &additionalBlocks, + &offsetAdditionalBlocks, + &numAdditionalBlocks); + if (rv) { + fprintf(stderr, "ERROR: Could not obtain MAR information.\n"); + return -1; + } + + if (hasSignatureBlock && numSignatures) { + fprintf(stderr, "ERROR: Cannot refresh a signed MAR\n"); + return -1; + } + + fp = fopen(path, "r+b"); + if (!fp) { + fprintf(stderr, "ERROR: could not open target file: %s\n", path); + return -1; + } + + if (fseeko(fp, offsetAdditionalBlocks, SEEK_SET)) { + fprintf(stderr, "ERROR: could not seek to additional blocks\n"); + fclose(fp); + return -1; + } + + for (i = 0; i < numAdditionalBlocks; ++i) { + /* Get the position of the start of this block */ + oldPos = ftello(fp); + + /* Read the additional block size */ + if (fread(&additionalBlockSize, + sizeof(additionalBlockSize), + 1, fp) != 1) { + fclose(fp); + return -1; + } + additionalBlockSize = ntohl(additionalBlockSize); + + /* Read the additional block ID */ + if (fread(&additionalBlockID, + sizeof(additionalBlockID), + 1, fp) != 1) { + fclose(fp); + return -1; + } + additionalBlockID = ntohl(additionalBlockID); + + if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) { + if (fseeko(fp, oldPos, SEEK_SET)) { + fprintf(stderr, "Could not seek back to Product Information Block\n"); + fclose(fp); + return -1; + } + + if (mar_concat_product_info_block(fp, NULL, infoBlock)) { + fprintf(stderr, "Could not concat Product Information Block\n"); + fclose(fp); + return -1; + } + + fclose(fp); + return 0; + } else { + /* This is not the additional block you're looking for. Move along. */ + if (fseek(fp, additionalBlockSize, SEEK_CUR)) { + fprintf(stderr, "ERROR: Could not seek past current block.\n"); + fclose(fp); + return -1; + } + } + } + + /* If we had a product info block we would have already returned */ + fclose(fp); + fprintf(stderr, "ERROR: Could not refresh because block does not exist\n"); + return -1; +} + +/** + * Create a MAR file from a set of files. + * @param dest The path to the file to create. This path must be + * compatible with fopen. + * @param numfiles The number of files to store in the archive. + * @param files The list of null-terminated file paths. Each file + * path must be compatible with fopen. + * @param infoBlock The information to store in the product information block. + * @return A non-zero value if an error occurs. + */ +int mar_create(const char *dest, int + num_files, char **files, + struct ProductInformationBlock *infoBlock) { + struct MarItemStack stack; + uint32_t offset_to_index = 0, size_of_index, + numSignatures, numAdditionalSections; + uint64_t sizeOfEntireMAR = 0; + struct stat st; + FILE *fp; + int i, rv = -1; + + memset(&stack, 0, sizeof(stack)); + + fp = fopen(dest, "wb"); + if (!fp) { + fprintf(stderr, "ERROR: could not create target file: %s\n", dest); + return -1; + } + + if (fwrite(MAR_ID, MAR_ID_SIZE, 1, fp) != 1) + goto failure; + if (fwrite(&offset_to_index, sizeof(uint32_t), 1, fp) != 1) + goto failure; + + stack.last_offset = MAR_ID_SIZE + + sizeof(offset_to_index) + + sizeof(numSignatures) + + sizeof(numAdditionalSections) + + sizeof(sizeOfEntireMAR); + + /* We will circle back on this at the end of the MAR creation to fill it */ + if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fp) != 1) { + goto failure; + } + + /* Write out the number of signatures, for now only at most 1 is supported */ + numSignatures = 0; + if (fwrite(&numSignatures, sizeof(numSignatures), 1, fp) != 1) { + goto failure; + } + + /* Write out the number of additional sections, for now just 1 + for the product info block */ + numAdditionalSections = htonl(1); + if (fwrite(&numAdditionalSections, + sizeof(numAdditionalSections), 1, fp) != 1) { + goto failure; + } + numAdditionalSections = ntohl(numAdditionalSections); + + if (mar_concat_product_info_block(fp, &stack, infoBlock)) { + goto failure; + } + + for (i = 0; i < num_files; ++i) { + if (stat(files[i], &st)) { + fprintf(stderr, "ERROR: file not found: %s\n", files[i]); + goto failure; + } + + if (mar_push(&stack, st.st_size, st.st_mode & 0777, files[i])) + goto failure; + + /* concatenate input file to archive */ + if (mar_concat_file(fp, files[i])) + goto failure; + } + + /* write out the index (prefixed with length of index) */ + size_of_index = htonl(stack.size_used); + if (fwrite(&size_of_index, sizeof(size_of_index), 1, fp) != 1) + goto failure; + if (fwrite(stack.head, stack.size_used, 1, fp) != 1) + goto failure; + + /* To protect against invalid MAR files, we assumes that the MAR file + size is less than or equal to MAX_SIZE_OF_MAR_FILE. */ + if (ftell(fp) > MAX_SIZE_OF_MAR_FILE) { + goto failure; + } + + /* write out offset to index file in network byte order */ + offset_to_index = htonl(stack.last_offset); + if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) + goto failure; + if (fwrite(&offset_to_index, sizeof(offset_to_index), 1, fp) != 1) + goto failure; + offset_to_index = ntohl(stack.last_offset); + + sizeOfEntireMAR = ((uint64_t)stack.last_offset) + + stack.size_used + + sizeof(size_of_index); + sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR); + if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fp) != 1) + goto failure; + sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR); + + rv = 0; +failure: + if (stack.head) + free(stack.head); + fclose(fp); + if (rv) + remove(dest); + return rv; +} diff --git a/onlineupdate/source/update/src/mar_extract.c b/onlineupdate/source/update/src/mar_extract.c new file mode 100644 index 000000000000..ec1cd6c53446 --- /dev/null +++ b/onlineupdate/source/update/src/mar_extract.c @@ -0,0 +1,83 @@ +/* -*- 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include "mar_private.h" +#include "mar.h" + +#ifdef XP_WIN +#include <io.h> +#include <direct.h> +#endif + +/* Ensure that the directory containing this file exists */ +static int mar_ensure_parent_dir(const char *path) +{ + char *slash = strrchr(path, '/'); + if (slash) + { + *slash = '\0'; + mar_ensure_parent_dir(path); +#ifdef XP_WIN + _mkdir(path); +#else + mkdir(path, 0755); +#endif + *slash = '/'; + } + return 0; +} + +static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) { + FILE *fp; + char buf[BLOCKSIZE]; + int fd, len, offset = 0; + + if (mar_ensure_parent_dir(item->name)) + return -1; + +#ifdef XP_WIN + fd = _open(item->name, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, item->flags); +#else + fd = creat(item->name, item->flags); +#endif + if (fd == -1) { + fprintf(stderr, "ERROR: could not create file in mar_test_callback()\n"); + perror(item->name); + return -1; + } + + fp = fdopen(fd, "wb"); + if (!fp) + return -1; + + while ((len = mar_read(mar, item, offset, buf, sizeof(buf))) > 0) { + if (fwrite(buf, len, 1, fp) != 1) + break; + offset += len; + } + + fclose(fp); + return len == 0 ? 0 : -1; +} + +int mar_extract(const char *path) { + MarFile *mar; + int rv; + + mar = mar_open(path); + if (!mar) + return -1; + + rv = mar_enum_items(mar, mar_test_callback, NULL); + + mar_close(mar); + return rv; +} diff --git a/onlineupdate/source/update/src/mar_private.h b/onlineupdate/source/update/src/mar_private.h new file mode 100644 index 000000000000..8a7fb45ccd82 --- /dev/null +++ b/onlineupdate/source/update/src/mar_private.h @@ -0,0 +1,79 @@ +/* -*- 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 MAR_PRIVATE_H__ +#define MAR_PRIVATE_H__ + +#include "limits.h" +#include "mozilla/Assertions.h" +#include <stdint.h> + +#define BLOCKSIZE 4096 +#define ROUND_UP(n, incr) (((n) / (incr) + 1) * (incr)) + +#define MAR_ID "MAR1" +#define MAR_ID_SIZE 4 + +/* The signature block comes directly after the header block + which is 16 bytes */ +#define SIGNATURE_BLOCK_OFFSET 16 + +/* Make sure the file is less than 500MB. We do this to protect against + invalid MAR files. */ +#define MAX_SIZE_OF_MAR_FILE ((int64_t)524288000) + +/* Existing code makes assumptions that the file size is + smaller than LONG_MAX. */ +MOZ_STATIC_ASSERT(MAX_SIZE_OF_MAR_FILE < ((int64_t)LONG_MAX), + "max mar file size is too big"); + +/* We store at most the size up to the signature block + 4 + bytes per BLOCKSIZE bytes */ +MOZ_STATIC_ASSERT(sizeof(BLOCKSIZE) < \ + (SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t)), + "BLOCKSIZE is too big"); + +/* The maximum size of any signature supported by current and future + implementations of the signmar program. */ +#define MAX_SIGNATURE_LENGTH 2048 + +/* Each additional block has a unique ID. + The product information block has an ID of 1. */ +#define PRODUCT_INFO_BLOCK_ID 1 + +#define MAR_ITEM_SIZE(namelen) (3*sizeof(uint32_t) + (namelen) + 1) + +/* Product Information Block (PIB) constants */ +#define PIB_MAX_MAR_CHANNEL_ID_SIZE 63 +#define PIB_MAX_PRODUCT_VERSION_SIZE 31 + +/* The mar program is compiled as a host bin so we don't have access to NSPR at + runtime. For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64 + instead of the NSPR equivalents. */ +#ifdef XP_WIN +#include <winsock2.h> +#define ftello _ftelli64 +#define fseeko _fseeki64 +#else +#define _FILE_OFFSET_BITS 64 +#include <netinet/in.h> +#include <unistd.h> +#endif + +#include <stdio.h> + +#define HOST_TO_NETWORK64(x) ( \ + ((((uint64_t) x) & 0xFF) << 56) | \ + ((((uint64_t) x) >> 8) & 0xFF) << 48) | \ + (((((uint64_t) x) >> 16) & 0xFF) << 40) | \ + (((((uint64_t) x) >> 24) & 0xFF) << 32) | \ + (((((uint64_t) x) >> 32) & 0xFF) << 24) | \ + (((((uint64_t) x) >> 40) & 0xFF) << 16) | \ + (((((uint64_t) x) >> 48) & 0xFF) << 8) | \ + (((uint64_t) x) >> 56) +#define NETWORK_TO_HOST64 HOST_TO_NETWORK64 + +#endif /* MAR_PRIVATE_H__ */ diff --git a/onlineupdate/source/update/src/mar_read.c b/onlineupdate/source/update/src/mar_read.c new file mode 100644 index 000000000000..7be225385403 --- /dev/null +++ b/onlineupdate/source/update/src/mar_read.c @@ -0,0 +1,570 @@ +/* -*- 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 <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include "mar_private.h" +#include "mar.h" + +#ifdef XP_WIN +#include <winsock2.h> +#else +#include <netinet/in.h> +#endif + + +/* this is the same hash algorithm used by nsZipArchive.cpp */ +static uint32_t mar_hash_name(const char *name) { + uint32_t val = 0; + unsigned char* c; + + for (c = (unsigned char *) name; *c; ++c) + val = val*37 + *c; + + return val % TABLESIZE; +} + +static int mar_insert_item(MarFile *mar, const char *name, int namelen, + uint32_t offset, uint32_t length, uint32_t flags) { + MarItem *item, *root; + uint32_t hash; + + item = (MarItem *) malloc(sizeof(MarItem) + namelen); + if (!item) + return -1; + item->next = NULL; + item->offset = offset; + item->length = length; + item->flags = flags; + memcpy(item->name, name, namelen + 1); + + hash = mar_hash_name(name); + + root = mar->item_table[hash]; + if (!root) { + mar->item_table[hash] = item; + } else { + /* append item */ + while (root->next) + root = root->next; + root->next = item; + } + return 0; +} + +static int mar_consume_index(MarFile *mar, char **buf, const char *buf_end) { + /* + * Each item has the following structure: + * uint32_t offset (network byte order) + * uint32_t length (network byte order) + * uint32_t flags (network byte order) + * char name[N] (where N >= 1) + * char null_byte; + */ + uint32_t offset; + uint32_t length; + uint32_t flags; + const char *name; + int namelen; + + if ((buf_end - *buf) < (int)(3*sizeof(uint32_t) + 2)) + return -1; + + memcpy(&offset, *buf, sizeof(offset)); + *buf += sizeof(offset); + + memcpy(&length, *buf, sizeof(length)); + *buf += sizeof(length); + + memcpy(&flags, *buf, sizeof(flags)); + *buf += sizeof(flags); + + offset = ntohl(offset); + length = ntohl(length); + flags = ntohl(flags); + + name = *buf; + /* find namelen; must take care not to read beyond buf_end */ + while (**buf) { + if (*buf == buf_end) + return -1; + ++(*buf); + } + namelen = (*buf - name); + /* consume null byte */ + if (*buf == buf_end) + return -1; + ++(*buf); + + return mar_insert_item(mar, name, namelen, offset, length, flags); +} + +static int mar_read_index(MarFile *mar) { + char id[MAR_ID_SIZE], *buf, *bufptr, *bufend; + uint32_t offset_to_index, size_of_index; + + /* verify MAR ID */ + if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1) + return -1; + if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) + return -1; + + if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1) + return -1; + offset_to_index = ntohl(offset_to_index); + + if (fseek(mar->fp, offset_to_index, SEEK_SET)) + return -1; + if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1) + return -1; + size_of_index = ntohl(size_of_index); + + buf = (char *) malloc(size_of_index); + if (!buf) + return -1; + if (fread(buf, size_of_index, 1, mar->fp) != 1) { + free(buf); + return -1; + } + + bufptr = buf; + bufend = buf + size_of_index; + while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0); + + free(buf); + return (bufptr == bufend) ? 0 : -1; +} + +/** + * Internal shared code for mar_open and mar_wopen. + * On failure, will fclose(fp). + */ +static MarFile *mar_fpopen(FILE *fp) +{ + MarFile *mar; + + mar = (MarFile *) malloc(sizeof(*mar)); + if (!mar) { + fclose(fp); + return NULL; + } + + mar->fp = fp; + memset(mar->item_table, 0, sizeof(mar->item_table)); + if (mar_read_index(mar)) { + mar_close(mar); + return NULL; + } + + return mar; +} + +MarFile *mar_open(const char *path) { + FILE *fp; + + fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in mar_open()\n"); + perror(path); + return NULL; + } + + return mar_fpopen(fp); +} + +#ifdef XP_WIN +MarFile *mar_wopen(const wchar_t *path) { + FILE *fp; + + _wfopen_s(&fp, path, L"rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in mar_wopen()\n"); + _wperror(path); + return NULL; + } + + return mar_fpopen(fp); +} +#endif + +void mar_close(MarFile *mar) { + MarItem *item; + int i; + + fclose(mar->fp); + + for (i = 0; i < TABLESIZE; ++i) { + item = mar->item_table[i]; + while (item) { + MarItem *temp = item; + item = item->next; + free(temp); + } + } + + free(mar); +} + +/** + * Determines the MAR file information. + * + * @param fp An opened MAR file in read mode. + * @param hasSignatureBlock Optional out parameter specifying if the MAR + * file has a signature block or not. + * @param numSignatures Optional out parameter for storing the number + * of signatures in the MAR file. + * @param hasAdditionalBlocks Optional out parameter specifying if the MAR + * file has additional blocks or not. + * @param offsetAdditionalBlocks Optional out parameter for the offset to the + * first additional block. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @param numAdditionalBlocks Optional out parameter for the number of + * additional blocks. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @return 0 on success and non-zero on failure. + */ +int get_mar_file_info_fp(FILE *fp, + int *hasSignatureBlock, + uint32_t *numSignatures, + int *hasAdditionalBlocks, + uint32_t *offsetAdditionalBlocks, + uint32_t *numAdditionalBlocks) +{ + uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i; + + /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */ + if (!hasSignatureBlock && !hasAdditionalBlocks) { + return -1; + } + + + /* Skip to the start of the offset index */ + if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) { + return -1; + } + + /* Read the offset to the index. */ + if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) { + return -1; + } + offsetToIndex = ntohl(offsetToIndex); + + if (numSignatures) { + /* Skip past the MAR file size field */ + if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) { + return -1; + } + + /* Read the number of signatures field */ + if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) { + return -1; + } + *numSignatures = ntohl(*numSignatures); + } + + /* Skip to the first index entry past the index size field + We do it in 2 calls because offsetToIndex + sizeof(uint32_t) + could oerflow in theory. */ + if (fseek(fp, offsetToIndex, SEEK_SET)) { + return -1; + } + + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { + return -1; + } + + /* Read the first offset to content field. */ + if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) { + return -1; + } + offsetToContent = ntohl(offsetToContent); + + /* Check if we have a new or old MAR file */ + if (hasSignatureBlock) { + if (offsetToContent == MAR_ID_SIZE + sizeof(uint32_t)) { + *hasSignatureBlock = 0; + } else { + *hasSignatureBlock = 1; + } + } + + /* If the caller doesn't care about the product info block + value, then just return */ + if (!hasAdditionalBlocks) { + return 0; + } + + /* Skip to the start of the signature block */ + if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) { + return -1; + } + + /* Get the number of signatures */ + if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) { + return -1; + } + signatureCount = ntohl(signatureCount); + + /* Check that we have less than the max amount of signatures so we don't + waste too much of either updater's or signmar's time. */ + if (signatureCount > MAX_SIGNATURES) { + return -1; + } + + /* Skip past the whole signature block */ + for (i = 0; i < signatureCount; i++) { + /* Skip past the signature algorithm ID */ + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { + return -1; + } + + /* Read the signature length and skip past the signature */ + if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) { + return -1; + } + signatureLen = ntohl(signatureLen); + if (fseek(fp, signatureLen, SEEK_CUR)) { + return -1; + } + } + + if (ftell(fp) == offsetToContent) { + *hasAdditionalBlocks = 0; + } else { + if (numAdditionalBlocks) { + /* We have an additional block, so read in the number of additional blocks + and set the offset. */ + *hasAdditionalBlocks = 1; + if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) { + return -1; + } + *numAdditionalBlocks = ntohl(*numAdditionalBlocks); + if (offsetAdditionalBlocks) { + *offsetAdditionalBlocks = ftell(fp); + } + } else if (offsetAdditionalBlocks) { + /* numAdditionalBlocks is not specified but offsetAdditionalBlocks + is, so fill it! */ + *offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t); + } + } + + return 0; +} + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +read_product_info_block(char *path, + struct ProductInformationBlock *infoBlock) +{ + int rv; + MarFile mar; + mar.fp = fopen(path, "rb"); + if (!mar.fp) { + fprintf(stderr, "ERROR: could not open file in read_product_info_block()\n"); + perror(path); + return -1; + } + rv = mar_read_product_info_block(&mar, infoBlock); + fclose(mar.fp); + return rv; +} + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +mar_read_product_info_block(MarFile *mar, + struct ProductInformationBlock *infoBlock) +{ + uint32_t i, offsetAdditionalBlocks, numAdditionalBlocks, + additionalBlockSize, additionalBlockID; + int hasAdditionalBlocks; + + /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and + product version < 32 bytes + 3 NULL terminator bytes. */ + char buf[97] = { '\0' }; + int ret = get_mar_file_info_fp(mar->fp, NULL, NULL, + &hasAdditionalBlocks, + &offsetAdditionalBlocks, + &numAdditionalBlocks); + for (i = 0; i < numAdditionalBlocks; ++i) { + /* Read the additional block size */ + if (fread(&additionalBlockSize, + sizeof(additionalBlockSize), + 1, mar->fp) != 1) { + return -1; + } + additionalBlockSize = ntohl(additionalBlockSize) - + sizeof(additionalBlockSize) - + sizeof(additionalBlockID); + + /* Read the additional block ID */ + if (fread(&additionalBlockID, + sizeof(additionalBlockID), + 1, mar->fp) != 1) { + return -1; + } + additionalBlockID = ntohl(additionalBlockID); + + if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) { + const char *location; + int len; + + /* This block must be at most 104 bytes. + MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL + terminator bytes. We only check for 96 though because we remove 8 + bytes above from the additionalBlockSize: We subtract + sizeof(additionalBlockSize) and sizeof(additionalBlockID) */ + if (additionalBlockSize > 96) { + return -1; + } + + if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) { + return -1; + } + + /* Extract the MAR channel name from the buffer. For now we + point to the stack allocated buffer but we strdup this + if we are within bounds of each field's max length. */ + location = buf; + len = strlen(location); + infoBlock->MARChannelID = location; + location += len + 1; + if (len >= 64) { + infoBlock->MARChannelID = NULL; + return -1; + } + + /* Extract the version from the buffer */ + len = strlen(location); + infoBlock->productVersion = location; + location += len + 1; + if (len >= 32) { + infoBlock->MARChannelID = NULL; + infoBlock->productVersion = NULL; + return -1; + } + infoBlock->MARChannelID = + strdup(infoBlock->MARChannelID); + infoBlock->productVersion = + strdup(infoBlock->productVersion); + return 0; + } else { + /* This is not the additional block you're looking for. Move along. */ + if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) { + return -1; + } + } + } + + /* If we had a product info block we would have already returned */ + return -1; +} + +const MarItem *mar_find_item(MarFile *mar, const char *name) { + uint32_t hash; + const MarItem *item; + + hash = mar_hash_name(name); + + item = mar->item_table[hash]; + while (item && strcmp(item->name, name) != 0) + item = item->next; + + return item; +} + +int mar_enum_items(MarFile *mar, MarItemCallback callback, void *closure) { + MarItem *item; + int i; + + for (i = 0; i < TABLESIZE; ++i) { + item = mar->item_table[i]; + while (item) { + int rv = callback(mar, item, closure); + if (rv) + return rv; + item = item->next; + } + } + + return 0; +} + +int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, + int bufsize) { + int nr; + + if (offset == (int) item->length) + return 0; + if (offset > (int) item->length) + return -1; + + nr = item->length - offset; + if (nr > bufsize) + nr = bufsize; + + if (fseek(mar->fp, item->offset + offset, SEEK_SET)) + return -1; + + return fread(buf, 1, nr, mar->fp); +} + +/** + * Determines the MAR file information. + * + * @param path The path of the MAR file to check. + * @param hasSignatureBlock Optional out parameter specifying if the MAR + * file has a signature block or not. + * @param numSignatures Optional out parameter for storing the number + * of signatures in the MAR file. + * @param hasAdditionalBlocks Optional out parameter specifying if the MAR + * file has additional blocks or not. + * @param offsetAdditionalBlocks Optional out parameter for the offset to the + * first additional block. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @param numAdditionalBlocks Optional out parameter for the number of + * additional blocks. Value is only valid if + * has_additional_blocks is not equal to 0. + * @return 0 on success and non-zero on failure. + */ +int get_mar_file_info(const char *path, + int *hasSignatureBlock, + uint32_t *numSignatures, + int *hasAdditionalBlocks, + uint32_t *offsetAdditionalBlocks, + uint32_t *numAdditionalBlocks) +{ + int rv; + FILE *fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in get_mar_file_info()\n"); + perror(path); + return -1; + } + + rv = get_mar_file_info_fp(fp, hasSignatureBlock, + numSignatures, hasAdditionalBlocks, + offsetAdditionalBlocks, numAdditionalBlocks); + + fclose(fp); + return rv; +} diff --git a/onlineupdate/source/update/src/moz.build b/onlineupdate/source/update/src/moz.build new file mode 100644 index 000000000000..2d25e0849af1 --- /dev/null +++ b/onlineupdate/source/update/src/moz.build @@ -0,0 +1,30 @@ +# -*- 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/. + +EXPORTS += [ + 'mar.h', + 'mar_cmdline.h', +] + +HOST_SOURCES += [ + 'mar_create.c', + 'mar_extract.c', + 'mar_read.c', +] +HostLibrary('hostmar') + +Library('mar') + +UNIFIED_SOURCES += [ + 'mar_create.c', + 'mar_extract.c', + 'mar_read.c', +] + +FORCE_STATIC_LIB = True + +if CONFIG['OS_ARCH'] == 'WINNT': + USE_STATIC_LIBS = True diff --git a/onlineupdate/source/update/updater/archivereader.cpp b/onlineupdate/source/update/updater/archivereader.cxx index 6aa1f49fde9d..0bdb99220334 100644 --- a/onlineupdate/source/update/updater/archivereader.cpp +++ b/onlineupdate/source/update/updater/archivereader.cxx @@ -10,7 +10,7 @@ #include "bzlib.h" #include "archivereader.h" #include "errors.h" -#ifdef XP_WIN +#ifdef WNT #include "nsAlgorithm.h" // Needed by nsVersionComparator.cpp #include "updatehelper.h" #endif @@ -27,12 +27,12 @@ #endif #define UPDATER_NO_STRING_GLUE_STL -#include "nsVersionComparator.cpp" +#include "nsVersionComparator.h" #undef UPDATER_NO_STRING_GLUE_STL -#if defined(XP_UNIX) +#if defined(UNIX) # include <sys/types.h> -#elif defined(XP_WIN) +#elif defined(WNT) # include <io.h> #endif @@ -203,7 +203,7 @@ ArchiveReader::Open(const NS_tchar *path) } } -#ifdef XP_WIN +#ifdef WNT mArchive = mar_wopen(path); #else mArchive = mar_open(path); @@ -240,7 +240,7 @@ ArchiveReader::ExtractFile(const char *name, const NS_tchar *dest) if (!item) return READ_ERROR; -#ifdef XP_WIN +#ifdef WNT FILE* fp = _wfopen(dest, L"wb+"); #else int fd = creat(dest, item->flags); diff --git a/onlineupdate/source/update/updater/archivereader.h b/onlineupdate/source/update/updater/archivereader.h index 6dccd8983eb5..5fa9523eba40 100644 --- a/onlineupdate/source/update/updater/archivereader.h +++ b/onlineupdate/source/update/updater/archivereader.h @@ -10,7 +10,7 @@ #include <stdio.h> #include "mar.h" -#ifdef XP_WIN +#ifdef WNT typedef WCHAR NS_tchar; #else typedef char NS_tchar; diff --git a/onlineupdate/source/update/updater/automounter_gonk.cpp b/onlineupdate/source/update/updater/automounter_gonk.cxx index 3dff2a1337a1..3dff2a1337a1 100644 --- a/onlineupdate/source/update/updater/automounter_gonk.cpp +++ b/onlineupdate/source/update/updater/automounter_gonk.cxx diff --git a/onlineupdate/source/update/updater/bspatch.cpp b/onlineupdate/source/update/updater/bspatch.cxx index e4b5706ef2de..8f8e0420000a 100644 --- a/onlineupdate/source/update/updater/bspatch.cpp +++ b/onlineupdate/source/update/updater/bspatch.cxx @@ -39,13 +39,13 @@ #include <string.h> #include <limits.h> -#if defined(XP_WIN) +#if defined(WNT) # include <io.h> #else # include <unistd.h> #endif -#ifdef XP_WIN +#ifdef WNT # include <winsock2.h> #else # include <arpa/inet.h> diff --git a/onlineupdate/source/update/updater/loaddlls.cpp b/onlineupdate/source/update/updater/loaddlls.cxx index b4291a5df6bf..b910723953f8 100644 --- a/onlineupdate/source/update/updater/loaddlls.cpp +++ b/onlineupdate/source/update/updater/loaddlls.cxx @@ -3,6 +3,8 @@ * 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 WNT #include <windows.h> // Delayed load libraries are loaded when the first symbol is used. @@ -101,3 +103,4 @@ struct AutoLoadSystemDependencies } } } loadDLLs; +#endif diff --git a/onlineupdate/source/update/updater/progressui_gonk.cpp b/onlineupdate/source/update/updater/progressui-unused/progressui_gonk.cxx index f77d0af6338a..f77d0af6338a 100644 --- a/onlineupdate/source/update/updater/progressui_gonk.cpp +++ b/onlineupdate/source/update/updater/progressui-unused/progressui_gonk.cxx diff --git a/onlineupdate/source/update/updater/progressui_osx.mm b/onlineupdate/source/update/updater/progressui-unused/progressui_osx.mm index 8e3ce01eb836..8e3ce01eb836 100644 --- a/onlineupdate/source/update/updater/progressui_osx.mm +++ b/onlineupdate/source/update/updater/progressui-unused/progressui_osx.mm diff --git a/onlineupdate/source/update/updater/progressui.h b/onlineupdate/source/update/updater/progressui.h index 6dc20e06bcc7..55d0d9ebf0c3 100644 --- a/onlineupdate/source/update/updater/progressui.h +++ b/onlineupdate/source/update/updater/progressui.h @@ -9,7 +9,7 @@ #include "updatedefines.h" -#if defined(XP_WIN) +#if defined(WNT) typedef WCHAR NS_tchar; #define NS_main wmain #else @@ -20,7 +20,7 @@ // Called to perform any initialization of the widget toolkit int InitProgressUI(int *argc, NS_tchar ***argv); -#if defined(XP_WIN) +#if defined(WNT) // Called on the main thread at startup int ShowProgressUI(bool indeterminate = false, bool initUIStrings = true); int InitProgressUIStrings(); diff --git a/onlineupdate/source/update/updater/progressui_gtk.cpp b/onlineupdate/source/update/updater/progressui_gtk.cxx index f3c537047f25..362b3ba5ba19 100644 --- a/onlineupdate/source/update/updater/progressui_gtk.cpp +++ b/onlineupdate/source/update/updater/progressui_gtk.cxx @@ -4,6 +4,7 @@ * 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> @@ -129,3 +130,4 @@ UpdateProgressUI(float progress) { sProgressVal = progress; // 32-bit writes are atomic } +#endif // defined(UNIX) || defined(MACOSX) diff --git a/onlineupdate/source/update/updater/progressui_null.cpp b/onlineupdate/source/update/updater/progressui_null.cxx index cb3ac6369593..7c3019e0f010 100644 --- a/onlineupdate/source/update/updater/progressui_null.cpp +++ b/onlineupdate/source/update/updater/progressui_null.cxx @@ -4,6 +4,7 @@ * 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(WNT) #include "progressui.h" int InitProgressUI(int *argc, char ***argv) @@ -23,3 +24,4 @@ void QuitProgressUI() void UpdateProgressUI(float progress) { } +#endif // !defined(MACOSX) && !defined(UNIX) && !defined(WNT) diff --git a/onlineupdate/source/update/updater/progressui_win.cpp b/onlineupdate/source/update/updater/progressui_win.cxx index 66232902a4e8..d0b268edaa26 100644 --- a/onlineupdate/source/update/updater/progressui_win.cpp +++ b/onlineupdate/source/update/updater/progressui_win.cxx @@ -4,6 +4,7 @@ * 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 WNT #include <stdio.h> #include <windows.h> #include <commctrl.h> @@ -317,3 +318,4 @@ UpdateProgressUI(float progress) { sProgress = progress; // 32-bit writes are atomic } +#endif // WNT diff --git a/onlineupdate/source/update/updater/updater.cpp b/onlineupdate/source/update/updater/updater.cxx index 62237ade7bd1..8de9cc1e0898 100644 --- a/onlineupdate/source/update/updater/updater.cpp +++ b/onlineupdate/source/update/updater/updater.cxx @@ -66,7 +66,7 @@ // Amount of time in ms to wait for the parent process to close #define PARENT_WAIT 5000 -#if defined(XP_MACOSX) +#if defined(MACOSX) // These functions are defined in launchchild_osx.mm void LaunchChild(int argc, char **argv); void LaunchMacPostProcess(const char* aAppBundle); @@ -86,7 +86,7 @@ void LaunchMacPostProcess(const char* aAppBundle); // We want to use execv to invoke the callback executable on platforms where // we were launched using execv. See nsUpdateDriver.cpp. -#if defined(XP_UNIX) && !defined(XP_MACOSX) +#if defined(UNIX) && !defined(MACOSX) #define USE_EXECV #endif @@ -115,12 +115,12 @@ static bool sUseHardLinks = true; # define MAYBE_USE_HARD_LINKS 0 #endif -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(WNT) && !defined(MACOSX) #include "nss.h" #include "prerror.h" #endif -#ifdef XP_WIN +#ifdef WNT #include "updatehelper.h" // Closes the handle if valid and if the updater is elevated returns with the @@ -216,7 +216,7 @@ struct MARChannelStringTable { typedef void (* ThreadFunc)(void *param); -#ifdef XP_WIN +#ifdef WNT #include <process.h> class Thread @@ -252,7 +252,7 @@ private: void *mThreadParam; }; -#elif defined(XP_UNIX) +#elif defined(UNIX) #include <pthread.h> class Thread @@ -270,7 +270,6 @@ public: private: pthread_t thr; }; - #else #error "Unsupported platform" #endif @@ -287,7 +286,7 @@ static bool sReplaceRequest = false; static bool sUsingService = false; static bool sIsOSUpdate = false; -#ifdef XP_WIN +#ifdef WNT // The current working directory specified in the command line. static NS_tchar* gDestPath; static NS_tchar gCallbackRelPath[MAXPATHLEN]; @@ -352,7 +351,7 @@ EnvHasValue(const char *name) return (val && *val); } -#ifdef XP_WIN +#ifdef WNT /** * Coverts a relative update path to a full path for Windows. * @@ -406,7 +405,7 @@ get_valid_path(NS_tchar **line, bool isdir = false) return nullptr; } -#ifdef XP_WIN +#ifdef WNT // 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)); @@ -461,7 +460,7 @@ get_quoted_path(const NS_tchar *path) static void ensure_write_permissions(const NS_tchar *path) { -#ifdef XP_WIN +#ifdef WNT (void) _wchmod(path, _S_IREAD | _S_IWRITE); #else struct stat fs; @@ -605,7 +604,7 @@ static int ensure_parent_dir(const NS_tchar *path) return rv; } -#ifdef XP_UNIX +#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 @@ -648,7 +647,7 @@ create_hard_link(const NS_tchar *srcFilename, const NS_tchar *destFilename) // Copy the file named path onto a new file named dest. static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) { -#ifdef XP_WIN +#ifdef WNT // Fast path for Windows bool result = CopyFileW(path, dest, false); if (!result) { @@ -666,7 +665,7 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) return READ_ERROR; } -#ifdef XP_UNIX +#ifdef UNIX if (S_ISLNK(ss.st_mode)) { return ensure_copy_symlink(path, dest); } @@ -766,7 +765,7 @@ static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest, return READ_ERROR; } -#ifdef XP_UNIX +#ifdef UNIX if (S_ISLNK(sInfo.st_mode)) { return ensure_copy_symlink(path, dest); } @@ -859,7 +858,7 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath, return OK; } -#ifdef XP_WIN +#ifdef WNT // 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 @@ -967,7 +966,7 @@ static int backup_discard(const NS_tchar *path) } int rv = ensure_remove(backup); -#if defined(XP_WIN) +#if defined(WNT) if (rv && !sStagedUpdate && !sReplaceRequest) { LOG(("backup_discard: unable to remove: " LOG_S, backup)); NS_tchar path[MAXPATHLEN]; @@ -1311,7 +1310,7 @@ AddFile::Execute() return rv; } -#ifdef XP_WIN +#ifdef WNT char sourcefile[MAXPATHLEN]; if (!WideCharToMultiByte(CP_UTF8, 0, mFile, -1, sourcefile, MAXPATHLEN, nullptr, nullptr)) { @@ -1465,7 +1464,7 @@ PatchFile::Prepare() if (!fp) return WRITE_ERROR; -#ifdef XP_WIN +#ifdef WNT char sourcefile[MAXPATHLEN]; if (!WideCharToMultiByte(CP_UTF8, 0, mPatchFile, -1, sourcefile, MAXPATHLEN, nullptr, nullptr)) { @@ -1495,7 +1494,7 @@ PatchFile::Execute() return rv; FILE *origfile = nullptr; -#ifdef XP_WIN +#ifdef WNT if (NS_tstrcmp(mFile, 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. @@ -1537,7 +1536,7 @@ PatchFile::Execute() #if defined(HAVE_POSIX_FALLOCATE) AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode)); posix_fallocate(fileno((FILE *)ofile), 0, header.dlen); -#elif defined(XP_WIN) +#elif defined(WNT) 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 @@ -1565,7 +1564,7 @@ PatchFile::Execute() AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"), ss.st_mode)); -#elif defined(XP_MACOSX) +#elif defined(MACOSX) AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode)); // Modified code from FileUtils.cpp fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen}; @@ -1589,7 +1588,7 @@ PatchFile::Execute() return WRITE_ERROR_OPEN_PATCH_FILE; } -#ifdef XP_WIN +#ifdef WNT if (!shouldTruncate) { fseek(ofile, 0, SEEK_SET); } @@ -1802,7 +1801,7 @@ PatchIfFile::Finish(int status) //----------------------------------------------------------------------------- -#ifdef XP_WIN +#ifdef WNT #include "nsWindowsRestart.cpp" #include "nsWindowsHelpers.h" #include "uachelper.h" @@ -1827,9 +1826,9 @@ LaunchCallbackApp(const NS_tchar *workingDir, #if defined(USE_EXECV) execv(argv[0], argv); -#elif defined(XP_MACOSX) +#elif defined(MACOSX) LaunchChild(argc, argv); -#elif defined(XP_WIN) +#elif defined(WNT) // Do not allow the callback to run when running an update through the // service as session 0. The unelevated updater.exe will do the launching. if (!usingService) { @@ -1915,7 +1914,7 @@ IsUpdateStatusPendingService() } #endif -#ifdef XP_WIN +#ifdef WNT /* * Read the update.status file and sets isSuccess to true if * the status is set to succeeded. @@ -1956,18 +1955,18 @@ static int CopyInstallDirToDestDir() { // These files should not be copied over to the updated app -#ifdef XP_WIN +#ifdef WNT #define SKIPLIST_COUNT 3 -#elif XP_MACOSX +#elif MACOSX #define SKIPLIST_COUNT 0 #else #define SKIPLIST_COUNT 2 #endif copy_recursive_skiplist<SKIPLIST_COUNT> skiplist; -#ifndef XP_MACOSX +#ifndef MACOSX skiplist.append(0, gInstallDirPath, NS_T("updated")); skiplist.append(1, gInstallDirPath, NS_T("updates/0")); -#ifdef XP_WIN +#ifdef WNT skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock")); #endif #endif @@ -1989,11 +1988,11 @@ ProcessReplaceRequest() // 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 XP_MACOSX +#ifdef MACOSX NS_tchar destDir[MAXPATHLEN]; NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]), NS_T("%s/Contents"), gInstallDirPath); -#elif XP_WIN +#elif WNT // 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 @@ -2013,7 +2012,7 @@ ProcessReplaceRequest() NS_tchar newDir[MAXPATHLEN]; NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]), -#ifdef XP_MACOSX +#ifdef MACOSX NS_T("%s/Contents"), gWorkingDirPath); #else @@ -2030,7 +2029,7 @@ ProcessReplaceRequest() LOG(("Begin moving destDir (" LOG_S ") to tmpDir (" LOG_S ")", destDir, tmpDir)); int rv = rename_file(destDir, tmpDir, true); -#ifdef XP_WIN +#ifdef WNT // 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. @@ -2057,7 +2056,7 @@ ProcessReplaceRequest() LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")", newDir, destDir)); rv = rename_file(newDir, destDir, true); -#ifdef XP_MACOSX +#ifdef MACOSX if (rv) { LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")", newDir, destDir)); @@ -2082,7 +2081,7 @@ ProcessReplaceRequest() rv = ensure_remove_recursive(tmpDir, true); if (rv) { LOG(("Removing tmpDir failed, err: %d", rv)); -#ifdef XP_WIN +#ifdef WNT NS_tchar deleteDir[MAXPATHLEN]; NS_tsnprintf(deleteDir, sizeof(deleteDir)/sizeof(deleteDir[0]), NS_T("%s\\%s"), destDir, DELETE_DIR); @@ -2096,7 +2095,7 @@ ProcessReplaceRequest() #endif } -#ifdef XP_MACOSX +#ifdef MACOSX // On OS X, we we need to remove the staging directory after its Contents // directory has been moved. NS_tchar updatedAppDir[MAXPATHLEN]; @@ -2110,7 +2109,7 @@ ProcessReplaceRequest() return 0; } -#ifdef XP_WIN +#ifdef WNT static void WaitForServiceFinishThread(void *param) { @@ -2206,7 +2205,7 @@ UpdateThreadFunc(void *param) #ifdef MOZ_VERIFY_MAR_SIGNATURE if (rv == OK) { -#ifdef XP_WIN +#ifdef WNT HKEY baseKey = nullptr; wchar_t valueName[] = L"Image Path"; wchar_t rasenh[] = L"rsaenh.dll"; @@ -2232,7 +2231,7 @@ UpdateThreadFunc(void *param) } #endif rv = gArchiveReader.VerifySignature(); -#ifdef XP_WIN +#ifdef WNT if (baseKey) { if (reset) { RegSetValueExW(baseKey, valueName, 0, REG_SZ, @@ -2249,7 +2248,7 @@ UpdateThreadFunc(void *param) NS_tchar updateSettingsPath[MAX_TEXT_LEN]; NS_tsnprintf(updateSettingsPath, sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), -#ifdef XP_MACOSX +#ifdef MACOSX NS_T("%s/Contents/Resources/update-settings.ini"), #else NS_T("%s/update-settings.ini"), @@ -2311,7 +2310,7 @@ UpdateThreadFunc(void *param) if (rv) { LOG(("failed: %d", rv)); } else { -#ifdef XP_MACOSX +#ifdef MACOSX // If the update was successful we need to update the timestamp on the // top-level Mac OS X bundle directory so that Mac OS X's Launch Services // picks up any major changes when the bundle is updated. @@ -2349,7 +2348,7 @@ int NS_main(int argc, NS_tchar **argv) } #endif -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(WNT) && !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 @@ -2396,7 +2395,7 @@ int NS_main(int argc, NS_tchar **argv) *slash = NS_T('\0'); } -#ifdef XP_WIN +#ifdef WNT bool useService = false; bool testOnlyFallbackKeyExists = false; bool noServiceFallback = EnvHasValue("MOZ_NO_SERVICE_FALLBACK"); @@ -2432,13 +2431,13 @@ int NS_main(int argc, NS_tchar **argv) #endif // If there is a PID specified and it is not '0' then wait for the process to exit. -#ifdef XP_WIN +#ifdef WNT __int64 pid = 0; #else int pid = 0; #endif if (argc > 4) { -#ifdef XP_WIN +#ifdef WNT pid = _wtoi64(argv[4]); #else pid = atoi(argv[4]); @@ -2473,10 +2472,10 @@ int NS_main(int argc, NS_tchar **argv) if (sReplaceRequest) { // If we're attempting to replace the application, try to append to the // log generated when staging the staged update. -#ifdef XP_WIN +#ifdef WNT NS_tchar* logDir = gPatchDirPath; #else -#ifdef XP_MACOSX +#ifdef MACOSX NS_tchar* logDir = gPatchDirPath; #else NS_tchar logDir[MAXPATHLEN]; @@ -2536,7 +2535,7 @@ int NS_main(int argc, NS_tchar **argv) } #endif -#ifdef XP_WIN +#ifdef WNT if (pid > 0) { HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid); // May return nullptr if the parent process has already gone away. @@ -2556,7 +2555,7 @@ int NS_main(int argc, NS_tchar **argv) #endif if (sReplaceRequest) { -#ifdef XP_WIN +#ifdef WNT // On Windows, the current working directory of the process should be changed // so that it's not locked. NS_tchar sysDir[MAX_PATH + 1] = { L'\0' }; @@ -2571,7 +2570,7 @@ int NS_main(int argc, NS_tchar **argv) // argument prior to callbackIndex is the working directory. const int callbackIndex = 6; -#if defined(XP_WIN) +#if defined(WNT) sUsingService = EnvHasValue("MOZ_USING_SERVICE"); putenv(const_cast<char*>("MOZ_USING_SERVICE=")); // lastFallbackError keeps track of the last error for the service not being @@ -2914,7 +2913,7 @@ int NS_main(int argc, NS_tchar **argv) } } -#ifdef XP_WIN +#ifdef WNT // For replace requests, we don't need to do any real updates, so this is not // necessary. if (!sReplaceRequest) { @@ -3102,7 +3101,7 @@ int NS_main(int argc, NS_tchar **argv) NS_tmkdir(DELETE_DIR, 0755); } } -#endif /* XP_WIN */ +#endif /* WNT */ // Run update process on a background thread. ShowProgressUI may return // before QuitProgressUI has been called, so wait for UpdateThreadFunc to @@ -3115,7 +3114,7 @@ int NS_main(int argc, NS_tchar **argv) } t.Join(); -#ifdef XP_WIN +#ifdef WNT if (argc > callbackIndex && !sReplaceRequest) { if (callbackFile != INVALID_HANDLE_VALUE) { CloseHandle(callbackFile); @@ -3144,13 +3143,13 @@ int NS_main(int argc, NS_tchar **argv) "directory: " LOG_S, DELETE_DIR)); } } -#endif /* XP_WIN */ +#endif /* WNT */ #if defined(MOZ_WIDGET_GONK) } // end the extra level of scope for the GonkAutoMounter #endif -#ifdef XP_MACOSX +#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 @@ -3188,12 +3187,12 @@ int NS_main(int argc, NS_tchar **argv) } } } -#endif /* XP_MACOSX */ +#endif /* MACOSX */ LogFinish(); if (argc > callbackIndex) { -#if defined(XP_WIN) +#if defined(WNT) if (gSucceeded) { // The service update will only be executed if it is already installed. // For first time installs of the service, the install will happen from @@ -3211,12 +3210,12 @@ int NS_main(int argc, NS_tchar **argv) } } EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); -#endif /* XP_WIN */ -#ifdef XP_MACOSX +#endif /* WNT */ +#ifdef MACOSX if (gSucceeded) { LaunchMacPostProcess(gInstallDirPath); } -#endif /* XP_MACOSX */ +#endif /* MACOSX */ LaunchCallbackApp(argv[5], argc - callbackIndex, argv + callbackIndex, @@ -3342,7 +3341,7 @@ ActionList::Finish(int status) } -#ifdef XP_WIN +#ifdef WNT int add_dir_entries(const NS_tchar *dirpath, ActionList *list) { int rv = OK; @@ -3649,7 +3648,7 @@ GetManifestContents(const NS_tchar *manifest) mbuf[ms.st_size] = '\0'; rb = mbuf; -#ifndef XP_WIN +#ifndef WNT return rb; #else NS_tchar *wrb = (NS_tchar *) malloc((ms.st_size + 1) * sizeof(NS_tchar)); @@ -3675,7 +3674,7 @@ int AddPreCompleteActions(ActionList *list) return OK; } -#ifdef XP_MACOSX +#ifdef MACOSX NS_tchar *rb = GetManifestContents(NS_T("Contents/Resources/precomplete")); #else NS_tchar *rb = GetManifestContents(NS_T("precomplete")); diff --git a/onlineupdate/source/update/updater/win_dirent.cpp b/onlineupdate/source/update/updater/win_dirent.cxx index b0807ba5e193..7df6c26f2bbe 100644 --- a/onlineupdate/source/update/updater/win_dirent.cpp +++ b/onlineupdate/source/update/updater/win_dirent.cxx @@ -4,6 +4,7 @@ * 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 WNT #include "win_dirent.h" #include <errno.h> #include <string.h> @@ -75,4 +76,4 @@ dirent* readdir(DIR* dir) 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 new file mode 100644 index 000000000000..1193f867efa7 --- /dev/null +++ b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx @@ -0,0 +1,379 @@ +/* -*- 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(WNT) && !defined(UPDATER_NO_STRING_GLUE_STL) +#include <wchar.h> +#include "nsStringGlue.h" +#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 WNT +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 WNT +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 WNT +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 WNT +int32_t +CompareVersions(const char16_t* aStrA, const char16_t* aStrB) +{ + wchar_t* A2 = wcsdup(char16ptr_t(aStrA)); + if (!A2) { + return 1; + } + + wchar_t* B2 = wcsdup(char16ptr_t(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 new file mode 100644 index 000000000000..431d181ef722 --- /dev/null +++ b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h @@ -0,0 +1,173 @@ +/* -*- 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(WNT) && !defined(UPDATER_NO_STRING_GLUE_STL) +#include <wchar.h> +#include "nsStringGlue.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 WNT +int32_t CompareVersions(const char16_t* aStrA, const char16_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 WNT +struct VersionW +{ + VersionW(const char16_t* aVersionStringW) + { + versionContentW = + reinterpret_cast<char16_t*>(wcsdup(char16ptr_t(aVersionStringW))); + } + + const char16_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: + char16_t* versionContentW; +}; +#endif + +} // namespace mozilla + +#endif // nsVersionComparator_h__ + |