summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/installer
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r--chrome/installer/mini_installer/SConscript302
-rw-r--r--chrome/installer/mini_installer/chrome.release40
-rw-r--r--chrome/installer/mini_installer/mini_installer.cc392
-rw-r--r--chrome/installer/mini_installer/mini_installer.exe.manifest11
-rw-r--r--chrome/installer/mini_installer/mini_installer.h68
-rw-r--r--chrome/installer/mini_installer/mini_installer.icobin0 -> 318 bytes
-rw-r--r--chrome/installer/mini_installer/mini_installer.rc76
-rw-r--r--chrome/installer/mini_installer/mini_installer.vcproj125
-rw-r--r--chrome/installer/mini_installer/mini_installer.vsprops31
-rw-r--r--chrome/installer/mini_installer/mini_installer_debug.vsprops13
-rw-r--r--chrome/installer/mini_installer/mini_installer_exe_version.rc.version40
-rw-r--r--chrome/installer/mini_installer/mini_installer_release.vsprops13
-rw-r--r--chrome/installer/mini_installer/mini_installer_resource.h18
-rw-r--r--chrome/installer/mini_installer/pe_resource.cc73
-rw-r--r--chrome/installer/mini_installer/pe_resource.h66
-rw-r--r--chrome/installer/setup/SConscript153
-rw-r--r--chrome/installer/setup/install.cc269
-rw-r--r--chrome/installer/setup/main.cc389
-rw-r--r--chrome/installer/setup/setup.cc290
-rw-r--r--chrome/installer/setup/setup.exe.manifest11
-rw-r--r--chrome/installer/setup/setup.h104
-rw-r--r--chrome/installer/setup/setup.icobin0 -> 766 bytes
-rw-r--r--chrome/installer/setup/setup.rc82
-rw-r--r--chrome/installer/setup/setup.vcproj130
-rw-r--r--chrome/installer/setup/setup.vsprops30
-rw-r--r--chrome/installer/setup/setup_constants.cc49
-rw-r--r--chrome/installer/setup/setup_constants.h53
-rw-r--r--chrome/installer/setup/setup_debug.vsprops8
-rw-r--r--chrome/installer/setup/setup_exe_version.rc.version40
-rw-r--r--chrome/installer/setup/setup_release.vsprops8
-rw-r--r--chrome/installer/setup/setup_resource.h17
-rw-r--r--chrome/installer/setup/uninstall.cc303
-rw-r--r--chrome/installer/setup/uninstall.h56
-rw-r--r--chrome/installer/util/SConscript106
-rw-r--r--chrome/installer/util/copy_tree_work_item.cc169
-rw-r--r--chrome/installer/util/copy_tree_work_item.h105
-rw-r--r--chrome/installer/util/copy_tree_work_item_unittest.cc620
-rw-r--r--chrome/installer/util/create_dir_work_item.cc94
-rw-r--r--chrome/installer/util/create_dir_work_item.h70
-rw-r--r--chrome/installer/util/create_dir_work_item_unittest.cc169
-rw-r--r--chrome/installer/util/create_reg_key_work_item.cc131
-rw-r--r--chrome/installer/util/create_reg_key_work_item.h74
-rw-r--r--chrome/installer/util/create_reg_key_work_item_unittest.cc212
-rw-r--r--chrome/installer/util/delete_tree_work_item.cc97
-rw-r--r--chrome/installer/util/delete_tree_work_item.h74
-rw-r--r--chrome/installer/util/delete_tree_work_item_unittest.cc243
-rw-r--r--chrome/installer/util/google_update_constants.cc43
-rw-r--r--chrome/installer/util/google_update_constants.h52
-rw-r--r--chrome/installer/util/helper.cc147
-rw-r--r--chrome/installer/util/helper.h72
-rw-r--r--chrome/installer/util/helper_unittest.cc231
-rw-r--r--chrome/installer/util/install_util.cc120
-rw-r--r--chrome/installer/util/install_util.h89
-rw-r--r--chrome/installer/util/install_util_unittest.cc97
-rw-r--r--chrome/installer/util/installer_unittests.vcproj194
-rw-r--r--chrome/installer/util/l10n_string_util.cc148
-rw-r--r--chrome/installer/util/l10n_string_util.h52
-rw-r--r--chrome/installer/util/logging_installer.cc92
-rw-r--r--chrome/installer/util/logging_installer.h52
-rw-r--r--chrome/installer/util/lzma_util.cc210
-rw-r--r--chrome/installer/util/lzma_util.h62
-rw-r--r--chrome/installer/util/prebuild/create_string_rc.bat10
-rw-r--r--chrome/installer/util/prebuild/create_string_rc.py180
-rw-r--r--chrome/installer/util/prebuild/util_prebuild.vcproj150
-rw-r--r--chrome/installer/util/prebuild/util_prebuild.vsprops11
-rw-r--r--chrome/installer/util/run_all_unittests.cc34
-rw-r--r--chrome/installer/util/set_reg_value_work_item.cc176
-rw-r--r--chrome/installer/util/set_reg_value_work_item.h101
-rw-r--r--chrome/installer/util/set_reg_value_work_item_unittest.cc263
-rw-r--r--chrome/installer/util/shell_util.cc376
-rw-r--r--chrome/installer/util/shell_util.h145
-rw-r--r--chrome/installer/util/using_util.vsprops11
-rw-r--r--chrome/installer/util/util.vcproj180
-rw-r--r--chrome/installer/util/util_constants.cc82
-rw-r--r--chrome/installer/util/util_constants.h88
-rw-r--r--chrome/installer/util/version.cc71
-rw-r--r--chrome/installer/util/version.h71
-rw-r--r--chrome/installer/util/work_item.cc85
-rw-r--r--chrome/installer/util/work_item.h124
-rw-r--r--chrome/installer/util/work_item_list.cc142
-rw-r--r--chrome/installer/util/work_item_list.h116
-rw-r--r--chrome/installer/util/work_item_list_unittest.cc192
82 files changed, 9693 insertions, 0 deletions
diff --git a/chrome/installer/mini_installer/SConscript b/chrome/installer/mini_installer/SConscript
new file mode 100644
index 0000000..37cc692
--- /dev/null
+++ b/chrome/installer/mini_installer/SConscript
@@ -0,0 +1,302 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env', 'env_res', 'env_test')
+
+
+env = env.Clone()
+env_res = env_res.Clone()
+env_test = env_test.Clone()
+
+
+env_res.Append(
+ CPPPATH = [
+ "$TARGET_ROOT",
+ ".",
+ "#/..",
+ ],
+ RCFLAGS = [
+ ["/l", "0x409"],
+ ],
+)
+
+resources = env_res.RES('mini_installer.rc')
+
+
+env.Prepend(
+ CPPPATH = [
+ '$GTEST_DIR/include',
+ '$GTEST_DIR',
+ '#/..',
+ ],
+ CPPDEFINES = [
+ 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
+ 'WIN32_LEAN_AND_MEAN',
+ ],
+ CCFLAGS = [
+ '/TP',
+
+ '/Wp64',
+
+ '/wd4503',
+ '/wd4819',
+
+ '/GS-', # because we link with /NODEFAULTLIB
+ ],
+ LINKFLAGS = [
+ '/INCREMENTAL',
+ '/NODEFAULTLIB',
+ '/DEBUG',
+ '/SUBSYSTEM:WINDOWS',
+ '/OPT:NOWIN98',
+ '/ENTRY:"MainEntryPoint"',
+ '/MACHINE:X86',
+ '/FIXED:No',
+
+ '/SAFESEH:NO',
+ '/NXCOMPAT',
+ '/DYNAMICBASE:NO',
+
+ '/PDB:${TARGETS[1]}',
+ '/MAP:${TARGETS[2]}',
+ ],
+)
+
+env['CCFLAGS'].remove('/RTC1')
+
+env.Append(
+ LIBS = [
+ 'shlwapi.lib',
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+ ],
+)
+
+components = [
+ "$VISUAL_STUDIO/VC/crt/src/intel/mt_lib/memset.obj",
+ "$VISUAL_STUDIO/VC/crt/src/intel/mt_lib/P4_memset.obj",
+ "$TARGET_ROOT/chrome_dll.lib",
+]
+
+input_files = [
+ "mini_installer.cc",
+ "pe_resource.cc",
+]
+
+exe = env.Program(['mini_installer',
+ 'mini_installer.pdb',
+ 'mini_installer.map'],
+ components + resources + input_files)
+i = env.Install('$TARGET_ROOT', exe)
+env.Alias('chrome', i)
+
+
+env.AppendENVPath('PATH', r'C:\WINDOWS\system32')
+
+packed = env.Command('$TARGET_ROOT/packed_files.txt',
+ ['$CHROME_DIR/tools/build/win/create_installer_archive.py',
+ '$CHROME_DIR/installer/mini_installer/chrome.release'],
+ ('$PYTHON ${SOURCES[0]}'
+ ' --output_dir=${TARGET.dir}'
+ ' --input_file=${SOURCES[1]}'))
+env.Depends(packed, '$TARGET_ROOT/setup.exe')
+
+
+env_version = env.Clone(
+ VERSION_BAT = File('#/../chrome/tools/build/win/version.bat'),
+ CHROMEDIR = Dir('#/../chrome'),
+ PWD = Dir('.'),
+)
+
+env_version.Command('mini_installer_exe_version.rc',
+ ['mini_installer_exe_version.rc.version',
+ '$CHROMEDIR/VERSION',
+ '$CHROMEDIR/BRANDING'],
+ "$VERSION_BAT $SOURCE $CHROMEDIR $PWD $TARGET")
+
+
+#/Od
+#/I
+#"C:\src\trunk-vs\chrome\..\testing\gtest\include"
+#/I
+#"C:\src\trunk-vs\chrome\..\testing\gtest"
+#/I
+#"C:\src\trunk-vs\chrome\.."
+#/I
+#"C:\src\trunk-vs\chrome\third_party\wtl\include"
+#/I
+#"C:\src\trunk-vs\chrome\..\third_party\platformsdk_vista_6_0\files\Include"
+#/I
+#"C:\src\trunk-vs\chrome\..\third_party\platformsdk_vista_6_0\files\VC\INCLUDE"
+#/I
+#"C:\Program
+#Files\Microsoft
+#Visual
+#Studio
+#8\\VC\atlmfc\include"
+#/D
+#"UNIT_TEST"
+#/D
+#"_DEBUG"
+#/D
+#"_WIN32_WINNT=0x0600"
+#/D
+#"WINVER=0x0600"
+#/D
+#"WIN32"
+#/D
+#"_WINDOWS"
+#/D
+#"_HAS_EXCEPTIONS=0"
+#/D
+#"NOMINMAX"
+#/D
+#"_CRT_RAND_S"
+#/D
+#"CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"
+#/D
+#"WIN32_LEAN_AND_MEAN"
+#/D
+#"_UNICODE"
+#/D
+#"UNICODE"
+#/FD
+#/RTC1
+#/MTd
+#/Gy
+#/GR-
+#/Fo"C:\src\trunk-vs\chrome\Debug\obj\installer_unittests\\"
+#/Fd"C:\src\trunk-vs\chrome\Debug\obj\installer_unittests\vc80.pdb"
+#/W3
+#/WX
+#/c
+#/Wp64
+#/Zi
+#/TP
+#/wd4503
+#/wd4819
+
+env_test.Prepend(
+ CPPDEFINES = [
+ 'UNIT_TEST',
+ 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
+ 'WIN32_LEAN_AND_MEAN',
+ ],
+ CPPPATH = [
+ '$GTEST_DIR/include',
+ '$GTEST_DIR',
+ '#/..',
+ ],
+ LINKFLAGS = [
+ '/INCREMENTAL',
+ '/DEBUG',
+
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+
+ '/MACHINE:X86',
+ '/FIXED:No',
+
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+ ],
+ LIBS = [
+ 'shlwapi.lib',
+ 'rpcrt4.lib',
+ 'oleacc.lib',
+ 'comsupp.lib',
+
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+
+ 'DelayImp.lib',
+ ],
+)
+
+input_files = [
+ '../setup/setup_constants$OBJSUFFIX',
+ '../util/copy_tree_work_item_unittest.cc',
+ '../util/create_dir_work_item_unittest.cc',
+ '../util/create_reg_key_work_item_unittest.cc',
+ '../util/delete_tree_work_item_unittest.cc',
+ '../util/helper_unittest.cc',
+ '../util/install_util_unittest.cc',
+ '../util/run_all_unittests.cc',
+ '../util/set_reg_value_work_item_unittest.cc',
+ '../util/work_item_list_unittest.cc',
+]
+
+libs = [
+ '../util/util.lib',
+ '$TESTING_DIR/gtest.lib',
+ '$ICU38_DIR/icuuc.lib',
+ '$CHROME_DIR/common/common.lib',
+ '$BASE_DIR/base.lib',
+]
+
+exe = env_test.Program(['installer_unittests',
+ 'installer_unittests.pdb'],
+ input_files + libs)
+i = env_test.Install('$TARGET_ROOT', exe)
+
+env.Alias('chrome', i)
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release
new file mode 100644
index 0000000..e9fc438
--- /dev/null
+++ b/chrome/installer/mini_installer/chrome.release
@@ -0,0 +1,40 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+[FILES]
+chrome.exe: %(ChromeDir)s\
+wow_helper.exe: %(ChromeDir)s\
+Dictionaries\en-US.bdic: %(ChromeDir)s\Dictionaries
+rlz.dll: %(VersionDir)s\
+chrome.dll: %(VersionDir)s\
+icudt38.dll: %(VersionDir)s\
+Themes\default.dll: %(VersionDir)s\Themes
+locales\*.dll: %(VersionDir)s\Locales
+Resources\Inspector\*.*: %(VersionDir)s\Resources\Inspector
+Resources\Inspector\Images\*.*: %(VersionDir)s\Resources\Inspector\Images
diff --git a/chrome/installer/mini_installer/mini_installer.cc b/chrome/installer/mini_installer/mini_installer.cc
new file mode 100644
index 0000000..7c1650e
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.cc
@@ -0,0 +1,392 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// mini_installer.exe is the first exe that is run when chrome is being
+// installed or upgraded. It is designed to be extremely small (~5KB with no
+// extra resources linked) and it has two main jobs:
+// 1) unpack the resources (possibly decompressing some)
+// 2) run the real installer (setup.exe) with appropiate flags.
+//
+// In order to be really small we don't link against the CRT and we define the
+// following compiler/linker flags:
+// EnableIntrinsicFunctions="true" compiler: /Oi
+// BasicRuntimeChecks="0"
+// BufferSecurityCheck="false" compiler: /GS-
+// EntryPointSymbol="MainEntryPoint" linker: /ENTRY
+// IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB
+// OptimizeForWindows98="1" liker: /OPT:NOWIN98
+// linker: /SAFESEH:NO
+// Also some built-in code that the compiler relies on is not defined so we
+// are forced to manually link against it. It comes in the form of two
+// object files that exist in $(VCInstallDir)\crt\src which are memset.obj and
+// P4_memset.obj. These two object files rely on the existence of a static
+// variable named __sse2_available which indicates the presence of intel sse2
+// extensions. We define it to false which causes a slower but safe code for
+// memcpy and memset intrinsics.
+
+// having the linker merge the sections is saving us ~500 bytes.
+#pragma comment(linker, "/MERGE:.rdata=.text")
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <stdlib.h>
+
+#include "chrome/installer/mini_installer/mini_installer.h"
+#include "chrome/installer/mini_installer/pe_resource.h"
+
+// Required linker symbol. See remarks above.
+extern "C" unsigned int __sse2_available = 0;
+
+namespace mini_installer {
+
+// This structure passes data back and forth for the processing
+// of resource callbacks.
+struct Context {
+ // We really have a single string that is used for all operations.
+ // We keep two pointers to it as follows:
+ // [uncompress command]' '[path to exe]\[name of file]
+ // | |
+ // Context->full_path Context->name
+ wchar_t* full_path; // input to the call back method
+ wchar_t* name; // input/output from the call back method (contains file name)
+ size_t max_name_size; // input (contains the size of buffer "name")
+};
+
+
+// Takes the path to file and returns a pointer to the filename component. For
+// exmaple for input of c:\full\path\to\file.ext it returns pointer to file.ext.
+// It also checks that there is an extension (of length 3) in file name and
+// the size of path is at least 7. It returns NULL if extension or path
+// separator is not found.
+wchar_t* GetNameFromPathExt(wchar_t* path, size_t size) {
+ const int kMinPath = 7;
+ const int kExtSize = 4;
+ if ((size < kMinPath) || (path[size - kExtSize] != L'.')) {
+ return NULL;
+ }
+ wchar_t* current = &path[size - kExtSize];
+ while (L'\\' != *current) {
+ --current;
+ if (current == path) {
+ return NULL;
+ }
+ }
+ return (current + 1);
+}
+
+
+// Simple replacement for CRT string copy method that does not overflow.
+// Returns true if the source was copied successfully otherwise returns false.
+// Parameter src is assumed to be NULL terminated and the NULL character is
+// copied over to string dest.
+bool SafeStrCopy(wchar_t* dest, const wchar_t* src, size_t dest_size) {
+ for (size_t length = 0; length < dest_size; ++dest, ++src, ++length) {
+ *dest = *src;
+ if (L'\0' == *src) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// Helper function to read a value from registry. Returns true if value
+// is read successfully and stored in parameter value. Returns false otherwise.
+bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key,
+ const wchar_t *value_name, wchar_t *value,
+ size_t size) {
+ HKEY key;
+
+ if ((::RegOpenKeyEx(root_key, sub_key, NULL,
+ KEY_READ, &key) == ERROR_SUCCESS) &&
+ (::RegQueryValueEx(key, value_name, NULL, NULL,
+ reinterpret_cast<LPBYTE>(value),
+ reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) {
+ ::RegCloseKey(key);
+ return true;
+ }
+ return false;
+}
+
+
+// Gets the setup.exe path from Registry by looking the value of Uninstall
+// string, strips the arguments for uninstall and returns only the full path
+// to setup.exe.
+bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) {
+ if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey,
+ kUninstallRegistryValueName, path, size)) {
+ if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey,
+ kUninstallRegistryValueName, path, size)) {
+ return false;
+ }
+ }
+ wchar_t *tmp = StrStr(path, L" --");
+ if (tmp) {
+ *tmp = L'\0';
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
+// Calls CreateProcess with good default parameters and waits for the process
+// to terminate returning the process exit code.
+bool RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline,
+ int* exit_code) {
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ if (!::CreateProcessW(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW,
+ NULL, NULL, &si, &pi)) {
+ return false;
+ }
+ DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE);
+ if (WAIT_OBJECT_0 != wr) {
+ return false;
+ }
+
+ bool ret = true;
+ if (exit_code) {
+ if (!::GetExitCodeProcess(pi.hProcess,
+ reinterpret_cast<DWORD*>(exit_code))) {
+ ret = false;
+ }
+ }
+ ::CloseHandle(pi.hProcess);
+ ::CloseHandle(pi.hThread);
+ return ret;
+}
+
+
+// Windows defined callback used in the EnumResourceNamesW call. For each
+// matching resource found, the callback is invoked and at this point we write
+// it to disk and possibly uncompress it. Resources of type BL
+// are assumed to be LZ compressed and are uncompressed using 'expand.exe'.
+BOOL CALLBACK OnResourceFound(HMODULE module, const wchar_t* type,
+ wchar_t* name, LONG_PTR context) {
+ if (NULL == context) {
+ return FALSE;
+ }
+ Context* ctx = reinterpret_cast<Context*>(context);
+
+ PEResource resource(name, type, module);
+ if ((!resource.IsValid()) ||
+ (resource.Size() < 1 ) ||
+ (resource.Size() > kMaxResourceSize)) {
+ return FALSE;
+ }
+
+ // Note that the copy operation actually replaces the file name part of
+ // ctx->full_path
+ if ((!SafeStrCopy(ctx->name, name, ctx->max_name_size)) ||
+ (!resource.WriteToDisk(ctx->full_path))) {
+ return FALSE;
+ }
+
+ // If this is LZ compressed resource, uncompress it using the existing
+ // program in the system32 folder named 'expand.exe'.
+ if (0 == ::lstrcmpiW(type, kLZCResourceType)) {
+ wchar_t expand_cmd[MAX_PATH * 2] = UNCOMPRESS_CMD;
+ ::lstrcatW(expand_cmd, L"\"");
+ ::lstrcatW(expand_cmd, ctx->full_path);
+ ::lstrcatW(expand_cmd, L"\"");
+ if (!RunProcessAndWait(NULL, expand_cmd, NULL)) {
+ // Somehow we failed to uncompress the file. Exit now and leave the file
+ // behind for postmortem analysis.
+ return FALSE;
+ }
+ // Uncompression was successful, delete the source but it is not critical
+ // if that fails.
+ ::DeleteFileW(ctx->full_path);
+ }
+ return TRUE;
+}
+
+
+// Finds and writes to disk all resources of various types. Returns false
+// if there is a problem in writing any resource to disk.
+bool UnpackBinaryResources(HMODULE module, const wchar_t* base_path,
+ bool* unpacked_setup, wchar_t* archive_name) {
+ *unpacked_setup = false;
+
+ // Prepare the input to OnResourceFound method that needs a location where
+ // it will write all the resources.
+ wchar_t module_path[MAX_PATH];
+ if (!SafeStrCopy(module_path, base_path, _countof(module_path))) {
+ return false;
+ }
+ size_t length = ::lstrlen(module_path);
+ wchar_t* name = (wchar_t *) module_path + length;
+ Context context = {module_path, name, MAX_PATH - length};
+
+ // Get the resources of type 'B7'
+ if (!::EnumResourceNamesW(module, kLZMAResourceType, OnResourceFound,
+ LONG_PTR(&context))) {
+ // We need a compressed archive to do the installation. So if there
+ // is a problem in fetching B7 resource, just return error.
+ return false;
+ } else {
+ ::lstrcpy(archive_name, name);
+ }
+
+ // Get the resources of type 'BL'. setup.exe can be sent as 'BL' or 'BN'.
+ // So if we get 'resource not found' error just ignore it.
+ if (!::EnumResourceNamesW(module, kLZCResourceType, OnResourceFound,
+ LONG_PTR(&context))) {
+ if (::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) {
+ return false;
+ }
+ } else if (0 == ::lstrcmpiW(name, kSetupLZName)) {
+ *unpacked_setup = true;
+ }
+
+ if (!::EnumResourceNamesW(module, kBinResourceType, OnResourceFound,
+ LONG_PTR(&context))) {
+ if (::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) {
+ return false;
+ }
+ } else if (0 == ::lstrcmpiW(name, kSetupName)) {
+ *unpacked_setup = true;
+ }
+
+ return true;
+}
+
+
+// Executes setup.exe, waits for it to finish and returns the exit code.
+bool RunSetup(bool have_upacked_setup, const wchar_t* base_path,
+ const wchar_t* archive_name, int* exit_code) {
+ wchar_t cmd_line[MAX_PATH * 2];
+ wchar_t cmd_args[MAX_PATH * 2];
+
+ if (!SafeStrCopy(cmd_args, L" --install-archive=\"", _countof(cmd_args)) ||
+ !::lstrcat(cmd_args, base_path) ||
+ !::lstrcat(cmd_args, archive_name) ||
+ !::lstrcat(cmd_args, L"\"")) {
+ return false;
+ }
+
+ if (have_upacked_setup) {
+ if (!SafeStrCopy(cmd_line, L"\"", _countof(cmd_line)) ||
+ !::lstrcat(cmd_line, base_path) ||
+ !::lstrcat(cmd_line, kSetupName) ||
+ !::lstrcat(cmd_line, L"\"")) {
+ return false;
+ }
+ } else {
+ if (!GetSetupExePathFromRegistry(cmd_line, sizeof(cmd_line))) {
+ return false;
+ }
+ }
+
+ return (::lstrcat(cmd_line, cmd_args) &&
+ RunProcessAndWait(NULL, cmd_line, exit_code));
+}
+
+
+void DeleteExtractedFiles(const wchar_t* base_path,
+ const wchar_t* archive_name) {
+ wchar_t file_path[MAX_PATH];
+ // Delete setup.exe.
+ SafeStrCopy(file_path, base_path, MAX_PATH);
+ ::lstrcat(file_path, kSetupName);
+ ::DeleteFile(file_path);
+ // Delete chrome archive file.
+ SafeStrCopy(file_path, base_path, MAX_PATH);
+ ::lstrcat(file_path, archive_name);
+ ::DeleteFile(file_path);
+ // Delete the temp dir (if it is empty, otherwise fail).
+ ::RemoveDirectory(base_path);
+}
+
+// Creates and returns a temporary directory that can be used to extract
+// mini_installer payload.
+bool GetWorkDir(HMODULE module, wchar_t* work_dir) {
+ wchar_t base_path[MAX_PATH];
+ DWORD len = ::GetTempPath(MAX_PATH, base_path);
+ if (len >= MAX_PATH || len <= 0) {
+ // Problem in getting TEMP path so just use current directory as base path
+ len = ::GetModuleFileNameW(module, base_path, MAX_PATH);
+ if (len >= MAX_PATH || len <= 0)
+ return false; // Can't even get current directory? Return with error.
+ wchar_t* name = GetNameFromPathExt(base_path, len);
+ *name = L'\0';
+ }
+
+ wchar_t temp_name[MAX_PATH + 1];
+ if (!GetTempFileName(base_path, L"CR_", 0, temp_name))
+ return false; // Didn't get any temp name to use. Return error.
+ len = GetLongPathName(temp_name, work_dir, MAX_PATH);
+ if (len > MAX_PATH + 1 || len == 0)
+ return false; // Couldn't get full path to temp dir. Return error.
+
+ // GetTempFileName creates the file as well so delete it before creating
+ // the directory in its place.
+ if (!::DeleteFile(work_dir) || !::CreateDirectory(work_dir, NULL))
+ return false; // What's the use of temp dir if we can not create it?
+ ::lstrcat(work_dir, L"\\");
+ return true;
+}
+
+int WMain(HMODULE module) {
+ // First get a path where we can extract payload
+ wchar_t base_path[MAX_PATH];
+ if (!GetWorkDir(module, base_path))
+ return 1;
+
+ wchar_t archive_name[MAX_PATH];
+ bool have_upacked_setup;
+ if (!UnpackBinaryResources(module, base_path,
+ &have_upacked_setup, archive_name)) {
+ return 1;
+ }
+
+ int setup_exit_code = 0;
+ if (!RunSetup(have_upacked_setup, base_path,
+ archive_name, &setup_exit_code)) {
+ return 2;
+ }
+
+ wchar_t value[4];
+ if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey,
+ kCleanupRegistryValueName, value, 4)) ||
+ (value[0] != L'0')) {
+ DeleteExtractedFiles(base_path, archive_name);
+ }
+
+ return setup_exit_code;
+}
+} // namespace mini_installer
+
+
+int MainEntryPoint() {
+ int result = mini_installer::WMain(::GetModuleHandle(NULL));
+ ::ExitProcess(result);
+}
diff --git a/chrome/installer/mini_installer/mini_installer.exe.manifest b/chrome/installer/mini_installer/mini_installer.exe.manifest
new file mode 100644
index 0000000..28469a3
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.exe.manifest
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:security>
+ <ms_asmv2:requestedPrivileges>
+ <ms_asmv2:requestedExecutionLevel level="asInvoker">
+ </ms_asmv2:requestedExecutionLevel>
+ </ms_asmv2:requestedPrivileges>
+ </ms_asmv2:security>
+ </ms_asmv2:trustInfo>
+</assembly>
diff --git a/chrome/installer/mini_installer/mini_installer.h b/chrome/installer/mini_installer/mini_installer.h
new file mode 100644
index 0000000..785749e
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.h
@@ -0,0 +1,68 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_MINI_INSTALLER__
+#define CHROME_INSTALLER_MINI_INSTALLER__
+
+// The windows command line to uncompress a LZ compressed file. It is a define
+// because we need the string to be writable. We don't need the full path
+// since it is located in windows\system32 and is available since windows2k.
+#define UNCOMPRESS_CMD L"expand.exe -r "
+
+namespace mini_installer {
+
+// The installer filename. The installer can be compressed or uncompressed.
+const wchar_t kSetupName[] = L"setup.exe";
+const wchar_t kSetupLZName[] = L"setup.ex_";
+
+// The resource types that would be unpacked from the mini installer.
+// 'BN' is uncompressed binary and 'BL' is LZ compressed binary.
+const wchar_t kBinResourceType[] = L"BN";
+const wchar_t kLZCResourceType[] = L"BL";
+const wchar_t kLZMAResourceType[] = L"B7";
+
+// Uninstall registry location
+const wchar_t kUninstallRegistryKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Chrome";
+const wchar_t kUninstallRegistryValueName[] = L"UninstallString";
+
+// Uninstall registry key that lets user tell Chrome installer not to delete
+// extracted files.
+const wchar_t kCleanupRegistryKey[] = L"Software\\Google";
+const wchar_t kCleanupRegistryValueName[] = L"ChromeInstallerCleanup";
+
+// One gigabyte is the biggest resource size that it can handle.
+const int kMaxResourceSize = 1024*1024*1024;
+
+// This is the file that contains the list of files to be linked in the
+// executable. This file is updated by the installer generator tool chain.
+const wchar_t kManifestFilename[] = L"packed_files.txt";
+
+} // namespace mini_installer
+
+#endif // CHROME_INSTALLER_MINI_INSTALLER__
diff --git a/chrome/installer/mini_installer/mini_installer.ico b/chrome/installer/mini_installer/mini_installer.ico
new file mode 100644
index 0000000..6612f2d
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.ico
Binary files differ
diff --git a/chrome/installer/mini_installer/mini_installer.rc b/chrome/installer/mini_installer/mini_installer.rc
new file mode 100644
index 0000000..420dea9
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.rc
@@ -0,0 +1,76 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "mini_installer_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MINI_INSTALLER ICON "mini_installer.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "mini_installer_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOL\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""mini_installer_exe_version.rc""\r\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+// This file lists the resources that are going to be packed with the exe.
+#include "packed_files.txt"
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "mini_installer_exe_version.rc"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/chrome/installer/mini_installer/mini_installer.vcproj b/chrome/installer/mini_installer/mini_installer.vcproj
new file mode 100644
index 0000000..96cfe0a
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.vcproj
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mini_installer"
+ ProjectGUID="{24A5AC7C-280B-4899-9153-6BA570A081E7}"
+ RootNamespace="mini_installer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ <ToolFile
+ RelativePath="..\..\tools\build\win\release.rules"
+ />
+ <ToolFile
+ RelativePath="..\..\tools\build\win\version.rules"
+ />
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\mini_installer_debug.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="create installer archive"
+ LastChromeInstaller="$(LAST_CHROME_INSTALLER)"
+ LastChromeVersion="$(LAST_CHROME_VERSION)"
+ RebuildArchive="$(REBUILD_CHROME_ARCHIVE)"
+ />
+ <Tool
+ Name="Version"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\mini_installer_release.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="create installer archive"
+ LastChromeInstaller="$(LAST_CHROME_INSTALLER)"
+ LastChromeVersion="$(LAST_CHROME_VERSION)"
+ RebuildArchive="$(REBUILD_CHROME_ARCHIVE)"
+ />
+ <Tool
+ Name="Version"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="resources"
+ >
+ <File
+ RelativePath=".\mini_installer.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\mini_installer.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\mini_installer_exe_version.rc.version"
+ >
+ </File>
+ <File
+ RelativePath=".\mini_installer_resource.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\chrome.release"
+ >
+ </File>
+ <File
+ RelativePath=".\mini_installer.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\mini_installer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\pe_resource.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\pe_resource.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/installer/mini_installer/mini_installer.vsprops b/chrome/installer/mini_installer/mini_installer.vsprops
new file mode 100644
index 0000000..c3920b0
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer.vsprops
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mini_installer"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ EnableIntrinsicFunctions="true"
+ BasicRuntimeChecks="0"
+ BufferSecurityCheck="false"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="&quot;$(VCInstallDir)crt\src\intel\mt_lib\memset.obj&quot; &quot;$(VCInstallDir)crt\src\intel\mt_lib\P4_memset.obj&quot; shlwapi.lib"
+ IgnoreAllDefaultLibraries="true"
+ GenerateMapFile="true"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ EntryPointSymbol="MainEntryPoint"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(OutDir);$(IntDir)"
+ />
+ <Tool
+ Name="VCManifestTool"
+ AdditionalManifestFiles="$(SolutionDir)installer\mini_installer\mini_installer.exe.manifest"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/mini_installer/mini_installer_debug.vsprops b/chrome/installer/mini_installer/mini_installer_debug.vsprops
new file mode 100644
index 0000000..9b43a5a
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer_debug.vsprops
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mini_installer_debug"
+ InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;.\mini_installer.vsprops"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="$(NoInherit) /SAFESEH:NO /NXCOMPAT /DYNAMICBASE:NO /FIXED"
+ DelayLoadDLLs="$(NoInherit)"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/mini_installer/mini_installer_exe_version.rc.version b/chrome/installer/mini_installer/mini_installer_exe_version.rc.version
new file mode 100644
index 0000000..3b024d1
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer_exe_version.rc.version
@@ -0,0 +1,40 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ PRODUCTVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "@COMPANY_FULLNAME@"
+ VALUE "FileDescription", "@PRODUCT_FULLNAME@"
+ VALUE "FileVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+ VALUE "InternalName", "mini_installer"
+ VALUE "LegalCopyright", "@COPYRIGHT@"
+ VALUE "ProductName", "@PRODUCT_FULLNAME@"
+ VALUE "ProductVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+ VALUE "CompanyShortName", "@COMPANY_SHORTNAME@"
+ VALUE "ProductShortName", "@PRODUCT_SHORTNAME@"
+ VALUE "LastChange", "@LASTCHANGE@"
+ VALUE "Official Build", "@OFFICIAL_BUILD@"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/chrome/installer/mini_installer/mini_installer_release.vsprops b/chrome/installer/mini_installer/mini_installer_release.vsprops
new file mode 100644
index 0000000..339f174
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer_release.vsprops
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mini_installer_release"
+ InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;.\mini_installer.vsprops"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="$(NoInherit) /SAFESEH:NO /NXCOMPAT /DYNAMICBASE:NO /FIXED"
+ DelayLoadDLLs="$(NoInherit)"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/mini_installer/mini_installer_resource.h b/chrome/installer/mini_installer/mini_installer_resource.h
new file mode 100644
index 0000000..ca01e39
--- /dev/null
+++ b/chrome/installer/mini_installer/mini_installer_resource.h
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by mini_installer.rc
+//
+#define IDI_MINI_INSTALLER 107
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/chrome/installer/mini_installer/pe_resource.cc b/chrome/installer/mini_installer/pe_resource.cc
new file mode 100644
index 0000000..6084fd3
--- /dev/null
+++ b/chrome/installer/mini_installer/pe_resource.cc
@@ -0,0 +1,73 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/mini_installer/pe_resource.h"
+
+PEResource::PEResource(HRSRC resource, HMODULE module)
+ : resource_(resource), module_(module) {
+}
+
+PEResource::PEResource(const wchar_t* name, const wchar_t* type, HMODULE module)
+ : resource_(NULL), module_(module) {
+ resource_ = ::FindResourceW(module, name, type);
+}
+
+bool PEResource::IsValid() {
+ return (NULL != resource_);
+}
+
+size_t PEResource::Size() {
+ return ::SizeofResource(module_, resource_);
+}
+
+bool PEResource::WriteToDisk(const wchar_t* full_path) {
+ // Resource handles are not real HGLOBALs so do not attempt to close them.
+ // Windows frees them whenever there is memory pressure.
+ HGLOBAL data_handle = ::LoadResource(module_, resource_);
+ if (NULL == data_handle) {
+ return false;
+ }
+ void* data = ::LockResource(data_handle);
+ if (NULL == data) {
+ return false;
+ }
+ size_t resource_size = Size();
+ HANDLE out_file = ::CreateFileW(full_path, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE == out_file) {
+ return false;
+ }
+ DWORD written = 0;
+ if (!::WriteFile(out_file, data, static_cast<DWORD>(resource_size),
+ &written, NULL)) {
+ ::CloseHandle(out_file);
+ return false;
+ }
+ return ::CloseHandle(out_file) ? true : false;
+}
diff --git a/chrome/installer/mini_installer/pe_resource.h b/chrome/installer/mini_installer/pe_resource.h
new file mode 100644
index 0000000..10c892c
--- /dev/null
+++ b/chrome/installer/mini_installer/pe_resource.h
@@ -0,0 +1,66 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_MINI_INSTALLER_PE_RESOURCE__
+#define CHROME_INSTALLER_MINI_INSTALLER_PE_RESOURCE__
+
+#include <windows.h>
+
+// This class models a windows PE resource. It does not pretend to be a full
+// API wrapper and it is just concerned with loading it to memory and writing
+// it to disk. Each resource is unique only in the context of a loaded module,
+// that is why you need to specify one on each constructor.
+class PEResource {
+ public:
+ // This ctor takes the handle to the resource and the module where it was
+ // found. Ownership of the resource is transfered to this object.
+ PEResource(HRSRC resource, HMODULE module);
+
+ // This ctor takes the resource name, the resource type and the module where
+ // to look for the resource. If the resource is found IsValid() returns true.
+ PEResource(const wchar_t* name, const wchar_t* type, HMODULE module);
+
+ // Returns true if the resource is valid.
+ bool IsValid();
+
+ // Returns the size in bytes of the resource. Returns zero if the resource is
+ // not valid.
+ size_t Size();
+
+ // Creates a file in 'path' with a copy of the resource. If the resource can
+ // not be loaded into memory or if it cannot be written to disk it returns
+ // false.
+ bool WriteToDisk(const wchar_t* path);
+
+ private:
+ HRSRC resource_;
+ HMODULE module_;
+};
+
+#endif // CHROME_INSTALLER_MINI_INSTALLER_PE_RESOURCE__
diff --git a/chrome/installer/setup/SConscript b/chrome/installer/setup/SConscript
new file mode 100644
index 0000000..b26790f
--- /dev/null
+++ b/chrome/installer/setup/SConscript
@@ -0,0 +1,153 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env', 'env_res')
+
+env = env.Clone()
+env_res = env_res.Clone()
+
+
+env_res.Append(
+ CPPPATH = [
+ "$TARGET_ROOT",
+ ".",
+ "#/..",
+ ],
+ RCFLAGS = [
+ ["/l", "0x409"],
+ ],
+)
+
+
+resources = [
+ env_res.RES('setup.rc'),
+ env_res.RES('../util/setup_strings.rc'),
+]
+
+
+env.Prepend(
+ CPPPATH = [
+ '../util',
+ '$TARGET_ROOT',
+ '.',
+ '#/..',
+ ],
+ LINKFLAGS = [
+ '/INCREMENTAL',
+ '/DEBUG',
+
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+
+ '/OPT:NOWIN98',
+ '/SUBSYSTEM:WINDOWS',
+ '/MACHINE:X86',
+ '/FIXED:No',
+
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+
+ '/PDB:${TARGETS[1]}',
+ '/MAP:${TARGETS[2]}',
+ ],
+ LIBS = [
+ 'shlwapi.lib',
+
+ 'msi.lib',
+
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+
+ 'DelayImp.lib',
+ ],
+)
+
+input_files = [
+ 'install.cc',
+ 'main.cc',
+ 'setup.cc',
+ 'setup_constants.cc',
+ 'uninstall.cc',
+]
+
+libs = [
+ '../util/util.lib',
+ '$BSPATCH_DIR/bspatch.lib',
+ '$LZMA_SDK_DIR/lzma_sdk.lib',
+ '$ICU38_DIR/icuuc.lib',
+ '$CHROME_DIR/common/common.lib',
+ '$BASE_DIR/base.lib',
+]
+
+exe = env.Program(['setup',
+ 'setup.pdb',
+ 'setup.map'],
+ resources + input_files + libs)
+i = env.Install('$TARGET_ROOT', exe)
+
+env.Alias('chrome', i)
+
+
+
+env_version = env.Clone(
+ VERSION_BAT = File('#/../chrome/tools/build/win/version.bat'),
+ CHROMEDIR = Dir('#/../chrome'),
+ PWD = Dir('.'),
+)
+
+import os
+env_version['ENV']['PROGRAMFILES'] = os.environ['PROGRAMFILES']
+env_version['ENV']['SystemDrive'] = os.environ['SystemDrive']
+env_version['ENV']['USERPROFILE'] = os.environ['USERPROFILE']
+env_version['ENV']['PATH'] = os.environ['PATH']
+
+setup_exe_version_rc = env_version.Command(
+ 'setup_exe_version.rc',
+ ['setup_exe_version.rc.version',
+ '$CHROMEDIR/VERSION',
+ '$CHROMEDIR/BRANDING'],
+ '$VERSION_BAT $SOURCE $CHROMEDIR $PWD $TARGET')
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
new file mode 100644
index 0000000..5cd0f22
--- /dev/null
+++ b/chrome/installer/setup/install.cc
@@ -0,0 +1,269 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <time.h>
+
+#include "base/file_util.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/setup/setup.h"
+#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/util/copy_tree_work_item.h"
+#include "chrome/installer/util/create_dir_work_item.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+#include "chrome/installer/util/work_item_list.h"
+
+namespace {
+std::wstring AppendPath(const std::wstring parent_path,
+ const std::wstring path) {
+ std::wstring new_path(parent_path);
+ file_util::AppendToPath(&new_path, path);
+ return new_path;
+}
+
+
+// This method adds work items to create (or update) Chrome uninstall entry in
+// Control Panel->Add/Remove Programs list.
+void AddUninstallShortcutWorkItems(HKEY reg_root,
+ const std::wstring& exe_path,
+ const std::wstring& install_path,
+ const std::wstring& new_version,
+ WorkItemList* install_list) {
+ std::wstring uninstall_cmd(L"\"");
+ uninstall_cmd.append(installer::GetInstallerPathUnderChrome(install_path,
+ new_version));
+ file_util::AppendToPath(&uninstall_cmd,
+ file_util::GetFilenameFromPath(exe_path));
+ uninstall_cmd.append(L"\" --");
+ uninstall_cmd.append(installer_util::switches::kUninstall);
+
+ // Create DisplayName, UninstallString and InstallLocation keys
+ install_list->AddCreateRegKeyWorkItem(reg_root,
+ installer_util::kUninstallRegPath);
+ install_list->AddSetRegValueWorkItem(
+ reg_root,
+ installer_util::kUninstallRegPath,
+ installer_util::kUninstallDisplayNameField,
+ installer_util::kChrome, true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ installer_util::kUninstallStringField,
+ uninstall_cmd, true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"InstallLocation", install_path, true);
+
+ // DisplayIcon, NoModify and NoRepair
+ std::wstring chrome_icon = AppendPath(install_path,
+ installer_util::kChromeExe);
+ ShellUtil::GetChromeIcon(chrome_icon);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"DisplayIcon", chrome_icon, true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"NoModify", 1, true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"NoRepair", 1, true);
+
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"Publisher",
+ installer_util::kPublisherName, true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"Version", new_version.c_str(), true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"DisplayVersion",
+ new_version.c_str(), true);
+ time_t rawtime = time(NULL);
+ struct tm timeinfo = {0};
+ localtime_s(&timeinfo, &rawtime);
+ wchar_t buffer[9];
+ if (wcsftime(buffer, 9, L"%Y%m%d", &timeinfo) == 8) {
+ install_list->AddSetRegValueWorkItem(reg_root,
+ installer_util::kUninstallRegPath,
+ L"InstallDate",
+ buffer, false);
+ }
+}
+
+void AddInstallerCopyTasks(const std::wstring& exe_path,
+ const std::wstring& archive_path,
+ const std::wstring& temp_path,
+ const std::wstring& install_path,
+ const std::wstring& new_version,
+ WorkItemList* install_list) {
+ std::wstring installer_dir(installer::GetInstallerPathUnderChrome(
+ install_path, new_version));
+ install_list->AddCreateDirWorkItem(installer_dir);
+
+ std::wstring exe_dst(installer_dir);
+ std::wstring archive_dst(installer_dir);
+ file_util::AppendToPath(&exe_dst,
+ file_util::GetFilenameFromPath(exe_path));
+ file_util::AppendToPath(&archive_dst,
+ file_util::GetFilenameFromPath(archive_path));
+
+ install_list->AddCopyTreeWorkItem(exe_path, exe_dst, temp_path,
+ WorkItem::ALWAYS);
+ install_list->AddCopyTreeWorkItem(archive_path, archive_dst, temp_path,
+ WorkItem::ALWAYS);
+}
+
+
+// This method tells if we are running on 64 bit platform so that we can copy
+// one extra exe. If the API call to determine 64 bit fails, we play it safe
+// and return true anyway so that the executable can be copied.
+bool Is64bit() {
+ typedef BOOL (WINAPI *WOW_FUNC)(HANDLE, PBOOL);
+ BOOL is64 = FALSE;
+
+ HANDLE handle = GetCurrentProcess();
+ HMODULE module = GetModuleHandle(L"kernel32.dll");
+ WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module,
+ "IsWow64Process"));
+ if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) {
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+bool installer::InstallNewVersion(const std::wstring& exe_path,
+ const std::wstring& archive_path,
+ const std::wstring& src_path,
+ const std::wstring& install_path,
+ const std::wstring& temp_dir,
+ const HKEY reg_root,
+ const Version& new_version) {
+
+ if (reg_root != HKEY_LOCAL_MACHINE && reg_root != HKEY_CURRENT_USER)
+ return false;
+
+ scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+ // A temp directory that work items need and the actual install directory.
+ install_list->AddCreateDirWorkItem(temp_dir);
+ install_list->AddCreateDirWorkItem(install_path);
+
+ // Browse for all the files in archive, add work items to copy them while
+ // handling special cases of executables.
+ LOG(INFO) << "Looking for Chrome installation files under " << src_path;
+ std::wstring root_path(src_path);
+ file_util::AppendToPath(&root_path, L"*");
+ WIN32_FIND_DATA find_file_data;
+ HANDLE file_handle = FindFirstFile(root_path.c_str(), &find_file_data);
+ BOOL ret = TRUE;
+ while (ret) {
+ LOG(INFO) << "directory found: " << find_file_data.cFileName;
+ // We do not want any directories starting with '.'
+ if ((wcslen(find_file_data.cFileName) <= 0) ||
+ (find_file_data.cFileName[0] == '.')) {
+ LOG(INFO) << "Ignoring directory found: " << find_file_data.cFileName;
+ } else if (_wcsicmp(find_file_data.cFileName,
+ installer_util::kChromeExe) == 0) {
+ // Special case of chrome.exe. Delete any new_chrome.exe if present
+ // (we will create a new one if chrome.exe is in use) and then
+ // copy chrome.exe.
+ install_list->AddDeleteTreeWorkItem(
+ AppendPath(install_path, installer::kChromeNewExe), std::wstring());
+ install_list->AddCopyTreeWorkItem(
+ AppendPath(src_path, installer_util::kChromeExe),
+ AppendPath(install_path, installer_util::kChromeExe),
+ temp_dir, WorkItem::RENAME_IF_IN_USE,
+ AppendPath(install_path, installer::kChromeNewExe));
+ } else if (_wcsicmp(find_file_data.cFileName,
+ installer::kWowHelperExe) == 0) {
+ // Special case of wow_helper.exe which is required only on 64 bit
+ // systems. This exe runs only for a short time when Chrome starts so
+ // it should not be locked most of the times and can be overwritten
+ // directly.
+ if (Is64bit()) {
+ install_list->AddCopyTreeWorkItem(
+ AppendPath(src_path, installer::kWowHelperExe),
+ AppendPath(install_path, installer::kWowHelperExe),
+ temp_dir, WorkItem::ALWAYS);
+ }
+ } else {
+ // In all other cases just copy the file/directory to install location.
+ install_list->AddCopyTreeWorkItem(
+ AppendPath(src_path, find_file_data.cFileName),
+ AppendPath(install_path, find_file_data.cFileName),
+ temp_dir, WorkItem::ALWAYS); // Always overwrite.
+ }
+ ret = FindNextFile(file_handle, &find_file_data);
+ }
+ FindClose(file_handle);
+
+ // Copy installer in install directory and
+ // add shortcut in Control Panel->Add/Remove Programs.
+ AddInstallerCopyTasks(exe_path, archive_path, temp_dir, install_path,
+ new_version.GetString(), install_list.get());
+ AddUninstallShortcutWorkItems(reg_root, exe_path, install_path,
+ new_version.GetString(), install_list.get());
+
+ // Delete any old_chrome.exe if present.
+ install_list->AddDeleteTreeWorkItem(
+ AppendPath(install_path, installer::kChromeOldExe), std::wstring());
+
+ // Create Google Update key (if not already present) and set the new Chrome
+ // version as last step.
+ std::wstring chrome_google_update_key =
+ InstallUtil::GetChromeGoogleUpdateKey();
+ install_list->AddCreateRegKeyWorkItem(reg_root, chrome_google_update_key);
+ install_list->AddSetRegValueWorkItem(reg_root, chrome_google_update_key,
+ google_update::kRegNameField,
+ installer_util::kChrome,
+ false); // Don't overwrite.
+ install_list->AddSetRegValueWorkItem(reg_root, chrome_google_update_key,
+ google_update::kRegVersionField,
+ new_version.GetString(),
+ true); // overwrite version
+
+ // Perform install operations.
+ if (!install_list->Do()) {
+ LOG(ERROR) << "install failed, roll back... ";
+ install_list->Rollback();
+ return false;
+ }
+
+ return true;
+}
diff --git a/chrome/installer/setup/main.cc b/chrome/installer/setup/main.cc
new file mode 100644
index 0000000..233408b
--- /dev/null
+++ b/chrome/installer/setup/main.cc
@@ -0,0 +1,389 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/string_util.h"
+#include "chrome/installer/setup/setup.h"
+#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/setup/uninstall.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/lzma_util.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/work_item.h"
+#include "third_party/bspatch/mbspatch.h"
+
+namespace {
+
+// Checks if the current system is running Windows XP or later. We are not
+// supporting Windows 2K for beta release.
+bool IsWindowsXPorLater() {
+ OSVERSIONINFOEX osvi;
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ GetVersionEx((OSVERSIONINFO *) &osvi);
+
+ // Windows versioning scheme doesn't seem very clear but here is what
+ // the code is checking as the minimum version required for Chrome:
+ // * Major > 5 is Vista or later so no further checks for Service Pack
+ // * Major = 5 && Minor > 1 is Windows Server 2003 so again no SP checks
+ // * Major = 5 && Minor = 1 is WinXP so check for SP1 or later
+ LOG(INFO) << "Windows Version: Major - " << osvi.dwMajorVersion
+ << " Minor - " << osvi.dwMinorVersion
+ << " Service Pack Major - " << osvi.wServicePackMajor
+ << " Service Pack Minor - " << osvi.wServicePackMinor;
+ if ((osvi.dwMajorVersion > 5) || // Vista or later
+ ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion > 1)) || // Win 2003
+ ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1) &&
+ (osvi.wServicePackMajor >= 1))) { // WinXP with SP1
+ return true;
+ }
+ return false;
+}
+
+// Applies a binary patch to existing Chrome installer archive on the system.
+// Uses bspatch library.
+int PatchArchiveFile(bool system_install, const std::wstring& archive_path,
+ const std::wstring& uncompressed_archive,
+ const installer::Version* installed_version) {
+ std::wstring existing_archive =
+ installer::GetChromeInstallPath(system_install);
+ file_util::AppendToPath(&existing_archive,
+ installed_version->GetString());
+ file_util::AppendToPath(&existing_archive, installer::kInstallerDir);
+ file_util::AppendToPath(&existing_archive, installer::kChromeArchive);
+
+ std::wstring patch_archive(archive_path);
+ file_util::AppendToPath(&patch_archive, installer::kChromePatchArchive);
+
+ LOG(INFO) << "Applying patch " << patch_archive
+ << " to file " << existing_archive
+ << " and generating file " << uncompressed_archive;
+ return ApplyBinaryPatch(WideToUTF8(existing_archive).c_str(),
+ WideToUTF8(patch_archive).c_str(),
+ WideToUTF8(uncompressed_archive).c_str());
+}
+
+
+// This method unpacks and uncompresses the given archive file. For Chrome
+// install we are creating a uncompressed archive that contains all the files
+// needed for the installer. This uncompressed archive is later compressed.
+//
+// This method first uncompresses archive specified by parameter "archive"
+// and assumes that it will result in an uncompressed full archive file
+// (chrome.7z) or uncompressed patch archive file (patch.7z). If it is patch
+// archive file, the patch is applied to the old archive file that should be
+// present on the system already. As the final step the new archive file
+// is unpacked in the path specified by parameter "path".
+DWORD UnPackArchive(const std::wstring& archive, bool system_install,
+ const installer::Version* installed_version,
+ const std::wstring& temp_path, const std::wstring& path,
+ bool& incremental_install) {
+ DWORD ret = NO_ERROR;
+ installer::LzmaUtil util;
+ // First uncompress the payload. This could be a differential
+ // update (patch.7z) or full archive (chrome.7z). If this uncompress fails
+ // return with error.
+ LOG(INFO) << "Opening archive " << archive;
+ if ((ret = util.OpenArchive(archive)) != NO_ERROR) {
+ LOG(ERROR) << "unable to open install archive: " << archive;
+ } else {
+ LOG(INFO) << "Uncompressing archive to path " << temp_path;
+ if ((ret = util.UnPack(temp_path)) != NO_ERROR) {
+ LOG(ERROR) << "error during uncompression: " << ret;
+ }
+ util.CloseArchive();
+ }
+ if (ret != NO_ERROR)
+ return ret;
+
+ std::wstring archive_name = file_util::GetFilenameFromPath(archive);
+ std::wstring uncompressed_archive(temp_path);
+ file_util::AppendToPath(&uncompressed_archive, installer::kChromeArchive);
+ // Check if this is differential update and if it is, patch it to the
+ // installer archive that should already be on the machine.
+ std::wstring prefix = installer::kChromeCompressedPatchArchivePrefix;
+ if ((archive_name.size() >= prefix.size()) &&
+ (std::equal(prefix.begin(), prefix.end(), archive_name.begin(),
+ CaseInsensitiveCompare<wchar_t>()))) {
+ LOG(INFO) << "Differential patch found. Applying to existing archive.";
+ incremental_install = true;
+ if (!installed_version) {
+ LOG(ERROR) << "Can not use differential update when Chrome is not "
+ << "installed on the system.";
+ return 1;
+ }
+ if (PatchArchiveFile(system_install, temp_path, uncompressed_archive,
+ installed_version)) {
+ LOG(ERROR) << "Binary patching failed.";
+ return 1;
+ }
+ }
+
+ // If we got the uncompressed archive, lets unpack it
+ LOG(INFO) << "Opening archive " << uncompressed_archive;
+ if ((ret = util.OpenArchive(uncompressed_archive)) != NO_ERROR) {
+ LOG(ERROR) << "unable to open install archive: " <<
+ uncompressed_archive;
+ } else {
+ LOG(INFO) << "Unpacking archive to path " << path;
+ if ((ret = util.UnPack(path)) != NO_ERROR) {
+ LOG(ERROR) << "error during uncompression: " << ret;
+ }
+ util.CloseArchive();
+ }
+
+ return ret;
+}
+
+
+// Find the version of Chrome from an install source directory.
+// Chrome_path should contain a complete and unpacked install package (i.e.
+// a Chrome directory under which there is a version folder).
+// Returns the version or NULL if no version is found.
+installer::Version* GetVersionFromDir(const std::wstring& chrome_path) {
+ LOG(INFO) << "Looking for Chrome version folder under " << chrome_path;
+ std::wstring root_path(chrome_path);
+ file_util::AppendToPath(&root_path, L"*");
+
+ WIN32_FIND_DATA find_file_data;
+ HANDLE file_handle = FindFirstFile(root_path.c_str(), &find_file_data);
+ BOOL ret = TRUE;
+ installer::Version *version = NULL;
+ // Here we are assuming that the installer we have is really valid so there
+ // can not be two version directories. We exit as soon as we find a valid
+ // version directory.
+ while (ret) {
+ if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ LOG(INFO) << "directory found: " << find_file_data.cFileName;
+ version =
+ installer::Version::GetVersionFromString(find_file_data.cFileName);
+ if (version) break;
+ }
+ ret = FindNextFile(file_handle, &find_file_data);
+ }
+ FindClose(file_handle);
+
+ return version;
+}
+
+// This method checks if we need to change "ap" key in Google Update to try
+// full installer as fall back method in case incremental installer fails.
+// - If incremental installer fails we append a magic string ("-full"), if
+// it is not present already, so that Google Update server next time will send
+// full installer to update Chrome on the local machine
+// - If we are currently running full installer, we remove this magic
+// string (if it is present) regardless of whether installer failed or not.
+// There is no fall-back for full installer :)
+void ResetGoogleUpdateApKey(bool system_install, bool incremental_install,
+ installer_util::InstallStatus install_status) {
+ HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ RegKey key;
+ std::wstring ap_key_value;
+ std::wstring chrome_google_update_state_key(
+ google_update::kRegPathClientState);
+ chrome_google_update_state_key.append(L"\\");
+ chrome_google_update_state_key.append(google_update::kChromeGuid);
+ if (!key.Open(reg_root, chrome_google_update_state_key.c_str(),
+ KEY_ALL_ACCESS) || !key.ReadValue(google_update::kRegApFieldName,
+ &ap_key_value)) {
+ LOG(INFO) << "Application key not found. Returning without changing it.";
+ key.Close();
+ return;
+ }
+
+ std::wstring new_value = InstallUtil::GetNewGoogleUpdateApKey(
+ incremental_install, install_status, ap_key_value);
+ if ((new_value.compare(ap_key_value) != 0) &&
+ !key.WriteValue(google_update::kRegApFieldName, new_value.c_str())) {
+ LOG(ERROR) << "Failed to write value " << new_value
+ << " to the registry field " << google_update::kRegApFieldName;
+ }
+ key.Close();
+}
+} // namespace
+
+
+int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
+ wchar_t* command_line, int show_command) {
+ CommandLine parsed_command_line;
+ installer::InitInstallerLogging(parsed_command_line);
+
+ // Check to make sure current system is WinXP or later. If not, log
+ // error message and get out.
+ if (!IsWindowsXPorLater()) {
+ LOG(ERROR) << "Chrome only supports Windows XP or later";
+ return installer_util::OS_NOT_SUPPORTED;
+ }
+
+ // Initialize COM for use later.
+ if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) != S_OK) {
+ LOG(ERROR) << "COM initialization failed.";
+ return installer_util::OS_ERROR;
+ }
+
+ bool system_install =
+ parsed_command_line.HasSwitch(installer_util::switches::kSystemInstall);
+ LOG(INFO) << "system install is " << system_install;
+
+ // Check the existing version installed.
+ scoped_ptr<installer::Version>
+ installed_version(InstallUtil::GetChromeVersion(system_install));
+ if (installed_version.get()) {
+ LOG(INFO) << "version on the system: " << installed_version->GetString();
+ }
+
+ // If --register-chrome-browser option is specified, register all
+ // Chrome protocol/file associations as well as register it as a valid
+ // browser for StarMenu->Internet shortcut. This option should only
+ // be used when setup.exe is launched with admin rights. We do not
+ // make any user specific changes in this option.
+ if (parsed_command_line.HasSwitch(
+ installer_util::switches::kRegisterChromeBrowser)) {
+ std::wstring chrome_exe(parsed_command_line.GetSwitchValue(
+ installer_util::switches::kRegisterChromeBrowser));
+ return ShellUtil::AddChromeToSetAccessDefaults(chrome_exe, true);
+ }
+
+ installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS;
+ if (parsed_command_line.HasSwitch(installer_util::switches::kUninstall)) {
+ bool remove_all = true;
+ if (parsed_command_line.HasSwitch(
+ installer_util::switches::kDoNotRemoveSharedItems))
+ remove_all = false;
+ // If --uninstall option is given, uninstall chrome
+ LOG(INFO) << "Uninstalling Chome";
+ if (!installed_version.get()) {
+ LOG(ERROR) << "No Chrome installation found for uninstall";
+ install_status = installer_util::CHROME_NOT_INSTALLED;
+ } else {
+ install_status = installer_setup::UninstallChrome(
+ parsed_command_line.program(), system_install,
+ *installed_version, remove_all);
+ }
+ } else {
+ // If --uninstall option is not specified, we assume it is install case.
+ // For install the default location for chrome.packed.7z is in current
+ // folder, so get that value first.
+ std::wstring archive_path =
+ file_util::GetDirectoryFromPath(parsed_command_line.program());
+ file_util::AppendToPath(&archive_path,
+ std::wstring(installer::kChromeCompressedArchive));
+ // If --install-archive is given, get the user specified value
+ if (parsed_command_line.HasSwitch(
+ installer_util::switches::kInstallArchive)) {
+ archive_path = parsed_command_line.GetSwitchValue(
+ installer_util::switches::kInstallArchive);
+ }
+ LOG(INFO) << "Archive found to install Chrome " << archive_path;
+
+ // Create a temp folder where we will unpack Chrome archive. If it fails,
+ // then we are doomed so return immediately and no cleanup is required.
+ std::wstring install_temp_path;
+ if (!file_util::CreateNewTempDirectory(std::wstring(L"chrome_"),
+ &install_temp_path)) {
+ LOG(ERROR) << "can not create temporary path";
+ return installer_util::TEMP_DIR_FAILED;
+ }
+ LOG(INFO) << "created path " << install_temp_path;
+ std::wstring unpack_path(install_temp_path);
+ file_util::AppendToPath(&unpack_path,
+ std::wstring(installer::kInstallSourceDir));
+
+ bool incremental_install = false;
+ if (UnPackArchive(archive_path, system_install, installed_version.get(),
+ install_temp_path, unpack_path, incremental_install)) {
+ install_status = installer_util::UNCOMPRESSION_FAILED;
+ } else {
+ LOG(INFO) << "unpacked to " << unpack_path;
+ std::wstring src_path(unpack_path);
+ file_util::AppendToPath(&src_path,
+ std::wstring(installer::kInstallSourceChromeDir));
+ scoped_ptr<installer::Version>
+ installer_version(GetVersionFromDir(src_path));
+ if (!installer_version.get()) {
+ LOG(ERROR) << "didn't find any valid version in installer";
+ install_status = installer_util::INVALID_ARCHIVE;
+ } else {
+ LOG(INFO) << "version to be installed: " <<
+ installer_version->GetString();
+ if (installed_version.get() &&
+ installed_version->IsHigherThan(installer_version.get())) {
+ LOG(ERROR) << "Higher version is already installed.";
+ install_status = installer_util::HIGHER_VERSION_EXISTS;
+ } else {
+ // We want to keep uncompressed archive (chrome.7z) that we get after
+ // uncompressing and binary patching. Get the location for this file.
+ std::wstring archive_to_copy(install_temp_path);
+ file_util::AppendToPath(&archive_to_copy,
+ std::wstring(installer::kChromeArchive));
+ install_status = installer::InstallOrUpdateChrome(
+ parsed_command_line.program(), archive_to_copy,
+ install_temp_path, system_install,
+ *installer_version, installed_version.get());
+ if (install_status == installer_util::FIRST_INSTALL_SUCCESS) {
+ LOG(INFO) << "First install successful. Launching Chrome.";
+ installer::LaunchChrome(system_install);
+ }
+ }
+ }
+ }
+
+ // Delete install temporary directory.
+ LOG(INFO) << "Deleting temporary directory " << install_temp_path;
+ scoped_ptr<DeleteTreeWorkItem> delete_tree(
+ WorkItem::CreateDeleteTreeWorkItem(install_temp_path,
+ std::wstring()));
+ delete_tree->Do();
+
+ ResetGoogleUpdateApKey(system_install, incremental_install, install_status);
+
+ // TBD: The previous installs/updates may leave some temporary files
+ // that were not deleted when the installs/updates exited, probably due
+ // to a crash. Try delete those temporary files again?
+ }
+
+ CoUninitialize();
+ if (InstallUtil::InstallSuccessful(install_status))
+ return 0; // For Google Update's benefit we need to return 0 for success
+ // cases.
+ else
+ return install_status;
+}
diff --git a/chrome/installer/setup/setup.cc b/chrome/installer/setup/setup.cc
new file mode 100644
index 0000000..7452f10
--- /dev/null
+++ b/chrome/installer/setup/setup.cc
@@ -0,0 +1,290 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <shlobj.h>
+
+#include "chrome/installer/setup/setup.h"
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/string_util.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/l10n_string_util.h"
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+#include "chrome/installer/util/work_item_list.h"
+
+#include "setup_strings.h"
+
+namespace {
+
+void AddChromeToMediaPlayerList() {
+ std::wstring reg_path(installer::kMediaPlayerRegPath);
+ // registry paths can also be appended like file system path
+ file_util::AppendToPath(&reg_path, installer_util::kChromeExe);
+ LOG(INFO) << "Adding Chrome to Media player list at " << reg_path;
+ scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem(
+ HKEY_LOCAL_MACHINE, reg_path));
+
+ // if the operation fails we log the error but still continue
+ if (!work_item.get()->Do())
+ LOG(ERROR) << "Couldn't add Chrome to media player inclusion list.";
+
+}
+
+// If we ever rename Chrome shortcuts under Windows Start menu, this
+// function deletes any of the old Chrome shortcuts if they exist. This
+// function will probably contain hard coded names of old shortcuts as they
+// will not longer be used anywhere else.
+// Method returns true if it finds and deletes successfully any old shortcut,
+// in all other cases it returns false.
+bool DeleteOldShortcuts(const std::wstring shortcut_path) {
+ // Check for the existence of shortcuts when they were still created under
+ // Start->Programs->Chrome (as opposed to Start->Programs->Google Chrome).
+ std::wstring shortcut_folder(shortcut_path);
+ file_util::AppendToPath(&shortcut_folder, L"Chrome");
+ if (file_util::PathExists(shortcut_folder)) {
+ LOG(INFO) << "Old shortcut path " << shortcut_folder << " exists.";
+ return file_util::Delete(shortcut_folder, true);
+ }
+ return false;
+}
+
+// Update shortcuts that are created by chrome.exe during first run, but
+// we take care of updating them in case the location of chrome.exe changes.
+void UpdateChromeExeShortcuts(const std::wstring& chrome_exe) {
+ std::wstring desktop_shortcut, ql_shortcut, shortcut_name;
+ if (!ShellUtil::GetQuickLaunchPath(&ql_shortcut) ||
+ !ShellUtil::GetDesktopPath(&desktop_shortcut) ||
+ !ShellUtil::GetChromeShortcutName(&shortcut_name))
+ return;
+ // Migrate the old shortcuts from Chrome.lnk to the localized name.
+ std::wstring old_ql_shortcut = ql_shortcut;
+ file_util::AppendToPath(&old_ql_shortcut, L"Chrome.lnk");
+ file_util::AppendToPath(&ql_shortcut, shortcut_name);
+ std::wstring old_desktop_shortcut = desktop_shortcut;
+ file_util::AppendToPath(&old_desktop_shortcut, L"Chrome.lnk");
+ file_util::AppendToPath(&desktop_shortcut, shortcut_name);
+
+ if (file_util::Move(old_ql_shortcut, ql_shortcut)) {
+ // Notify the Windows Shell that we renamed the file so it can remove the
+ // old icon. It's safe to not cehck for MAX_PATH because file_util::Move
+ // does the check for us.
+ SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, old_ql_shortcut.c_str(),
+ ql_shortcut.c_str());
+ }
+ if (file_util::Move(old_desktop_shortcut, desktop_shortcut)) {
+ SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, old_desktop_shortcut.c_str(),
+ desktop_shortcut.c_str());
+ }
+
+ // Go ahead and update the shortcuts if they exist.
+ ShellUtil::UpdateChromeShortcut(chrome_exe, ql_shortcut, false);
+ ShellUtil::UpdateChromeShortcut(chrome_exe, desktop_shortcut, false);
+}
+
+// This method creates Chrome shortcuts in Start->Programs for all users or
+// only for current user depending on whether it is system wide install or
+// user only install.
+//
+// If first_install is true, it creates shortcuts for launching and
+// uninstalling chrome.
+// If first_install is false, the function only updates the shortcut for
+// uninstalling chrome. According to
+// http://blogs.msdn.com/oldnewthing/archive/2005/11/24/496690.aspx,
+// updating uninstall shortcut should not trigger Windows "new application
+// installed" notification.
+//
+// If the shortcuts do not exist, the function does not recreate them during
+// update.
+bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path,
+ bool system_install,
+ installer_util::InstallStatus install_status,
+ const std::wstring& install_path,
+ const std::wstring& new_version) {
+ std::wstring shortcut_path;
+ int dir_enum = (system_install) ? base::DIR_COMMON_START_MENU :
+ base::DIR_START_MENU;
+ if (!PathService::Get(dir_enum, &shortcut_path)) {
+ LOG(ERROR) << "Failed to get location for shortcut.";
+ return false;
+ }
+
+ // Check for existence of old shortcuts
+ bool old_shortcuts_existed = DeleteOldShortcuts(shortcut_path);
+
+ // The location of Start->Programs->Google Chrome folder
+ const std::wstring& product_name =
+ installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
+ file_util::AppendToPath(&shortcut_path, product_name);
+
+ // Create/update Chrome link (points to chrome.exe) & Uninstall Chrome link
+ // (which points to setup.exe) under this folder only if:
+ // - This is a new install or install repair
+ // OR
+ // - The shortcut already exists in case of updates (user may have deleted
+ // shortcuts since our install. So on updates we only update if shortcut
+ // already exists)
+ bool ret1 = true;
+ std::wstring chrome_link(shortcut_path); // Chrome link (launches Chrome)
+ file_util::AppendToPath(&chrome_link, product_name + L".lnk");
+ std::wstring chrome_exe(install_path); // Chrome link target
+ file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+
+ if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) ||
+ (install_status == installer_util::INSTALL_REPAIRED) ||
+ (old_shortcuts_existed)) {
+ if (!file_util::PathExists(shortcut_path))
+ file_util::CreateDirectoryW(shortcut_path);
+
+ LOG(INFO) << "Creating shortcut to " << chrome_exe << " at " << chrome_link;
+ ShellUtil::UpdateChromeShortcut(chrome_exe, chrome_link, true);
+ } else if (file_util::PathExists(chrome_link)) {
+ LOG(INFO) << "Updating shortcut at " << chrome_link
+ << " to point to " << chrome_exe;
+ ShellUtil::UpdateChromeShortcut(chrome_exe, chrome_link, false);
+ }
+
+ // Create/update uninstall link
+ bool ret2 = true;
+ std::wstring uninstall_link(shortcut_path); // Uninstall Chrome link
+
+ file_util::AppendToPath(&uninstall_link,
+ installer_util::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE) + L".lnk");
+ if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) ||
+ (install_status == installer_util::INSTALL_REPAIRED) ||
+ (old_shortcuts_existed) ||
+ (file_util::PathExists(uninstall_link))) {
+ if (!file_util::PathExists(shortcut_path))
+ file_util::CreateDirectoryW(shortcut_path);
+ std::wstring setup_exe(installer::GetInstallerPathUnderChrome(install_path,
+ new_version));
+ file_util::AppendToPath(&setup_exe,
+ file_util::GetFilenameFromPath(exe_path));
+ std::wstring arguments(L" --");
+ arguments.append(installer_util::switches::kUninstall);
+ LOG(INFO) << "Creating/updating uninstall link at " << uninstall_link;
+ ret2 = file_util::CreateShortcutLink(setup_exe.c_str(),
+ uninstall_link.c_str(),
+ install_path.c_str(),
+ arguments.c_str(),
+ NULL,
+ setup_exe.c_str(),
+ 0);
+ }
+
+ // Update Desktop and Quick Launch shortcuts (only if they already exist)
+ UpdateChromeExeShortcuts(chrome_exe);
+
+ return ret1 && ret2;
+}
+} // namespace
+
+
+std::wstring installer::GetInstallerPathUnderChrome(
+ const std::wstring& install_path, const std::wstring& new_version) {
+ std::wstring installer_path(install_path);
+ file_util::AppendToPath(&installer_path, new_version);
+ file_util::AppendToPath(&installer_path, installer::kInstallerDir);
+ return installer_path;
+}
+
+
+installer_util::InstallStatus installer::InstallOrUpdateChrome(
+ const std::wstring& exe_path, const std::wstring& archive_path,
+ const std::wstring& install_temp_path, bool system_install,
+ const Version& new_version, const Version* installed_version) {
+
+ std::wstring install_path(GetChromeInstallPath(system_install));
+ if (install_path.empty()) {
+ LOG(ERROR) << "Couldn't get installation destination path";
+ return installer_util::INSTALL_FAILED;
+ } else {
+ LOG(INFO) << "install destination path: " << install_path;
+ }
+
+ std::wstring src_path(install_temp_path);
+ file_util::AppendToPath(&src_path, std::wstring(kInstallSourceDir));
+ file_util::AppendToPath(&src_path, std::wstring(kInstallSourceChromeDir));
+
+ HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ bool install_success = InstallNewVersion(exe_path, archive_path, src_path,
+ install_path, install_temp_path, reg_root, new_version);
+
+ installer_util::InstallStatus result;
+ if (!install_success) {
+ LOG(ERROR) << "Install failed.";
+ result = installer_util::INSTALL_FAILED;
+ } else {
+ if (!installed_version) {
+ LOG(INFO) << "First install of version " << new_version.GetString();
+ result = installer_util::FIRST_INSTALL_SUCCESS;
+ } else if (new_version.GetString() == installed_version->GetString()) {
+ LOG(INFO) << "Install repaired of version " << new_version.GetString();
+ result = installer_util::INSTALL_REPAIRED;
+ } else if (new_version.IsHigherThan(installed_version)) {
+ LOG(INFO) << "Version updated to " << new_version.GetString();
+ result = installer_util::NEW_VERSION_UPDATED;
+ } else {
+ NOTREACHED();
+ }
+
+ if (!CreateOrUpdateChromeShortcuts(exe_path, system_install, result,
+ install_path, new_version.GetString()))
+ LOG(WARNING) << "Failed to create/update start menu shortcut.";
+
+ std::wstring chrome_exe(install_path);
+ file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ if (result == installer_util::FIRST_INSTALL_SUCCESS ||
+ result == installer_util::INSTALL_REPAIRED) {
+ // Try to add Chrome to Media Player shim inclusion list. We don't do any
+ // error checking here because this operation will fail if user doesn't
+ // have admin rights and we want to ignore the error.
+ AddChromeToMediaPlayerList();
+
+ // We try to register Chrome as a valid browser on local machine. This
+ // will work only if current user has admin rights.
+ LOG(INFO) << "Registering Chrome as browser";
+ ShellUtil::RegisterStatus ret =
+ ShellUtil::AddChromeToSetAccessDefaults(chrome_exe, true);
+ LOG(ERROR) << "Return status of Chrome browser registration " << ret;
+ } else {
+ UpdateChromeExeShortcuts(chrome_exe);
+ RemoveOldVersionDirs(install_path, new_version.GetString());
+ }
+ }
+
+ return result;
+}
diff --git a/chrome/installer/setup/setup.exe.manifest b/chrome/installer/setup/setup.exe.manifest
new file mode 100644
index 0000000..28469a3
--- /dev/null
+++ b/chrome/installer/setup/setup.exe.manifest
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:security>
+ <ms_asmv2:requestedPrivileges>
+ <ms_asmv2:requestedExecutionLevel level="asInvoker">
+ </ms_asmv2:requestedExecutionLevel>
+ </ms_asmv2:requestedPrivileges>
+ </ms_asmv2:security>
+ </ms_asmv2:trustInfo>
+</assembly>
diff --git a/chrome/installer/setup/setup.h b/chrome/installer/setup/setup.h
new file mode 100644
index 0000000..0f3ebc5
--- /dev/null
+++ b/chrome/installer/setup/setup.h
@@ -0,0 +1,104 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file contains the specification of setup main functions.
+
+#ifndef CHROME_INSTALLER_SETUP_SETUP_H__
+#define CHROME_INSTALLER_SETUP_SETUP_H__
+
+#include <string>
+#include <windows.h>
+
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+
+namespace installer {
+// Get path to the installer under Chrome version folder
+// (for example <path>\Google\Chrome\<Version>\installer)
+std::wstring GetInstallerPathUnderChrome(const std::wstring& install_path,
+ const std::wstring& new_version);
+
+// This function installs or updates a new version of Chrome. It returns
+// install status (failed, new_install, updated etc).
+//
+// exe_path: Path to the executable (setup.exe) as it will be copied
+// to Chrome install folder after install is complete
+// archive_path: Path to the archive (chrome.7z) as it will be copied
+// to Chrome install folder after install is complete
+// install_temp_path: working directory used during install/update. It should
+// also has a sub dir source that contains a complete
+// and unpacked Chrome package.
+// system_install: if true, the function performs a system wide install/update.
+// Otherwise it installs/updates Chrome for the current user.
+// new_version: new Chrome version that needs to be installed
+// installed_version: currently installed version of Chrome, if any, or
+// NULL otherwise
+//
+// Note: since caller unpacks Chrome to install_temp_path\source, the caller
+// is responsible for cleaning up install_temp_path.
+installer_util::InstallStatus InstallOrUpdateChrome(
+ const std::wstring& exe_path, const std::wstring& archive_path,
+ const std::wstring& install_temp_path, bool system_install,
+ const Version& new_version, const Version* installed_version);
+
+// This function installs a new version of Chrome to the specified location.
+// It returns true if install was successful and false in case of an error.
+//
+// exe_path: Path to the executable (setup.exe) as it will be copied
+// to Chrome install folder after install is complete
+// archive_path: Path to the archive (chrome.7z) as it will be copied
+// to Chrome install folder after install is complete
+// src_path: the path that contains a complete and unpacked Chrome package
+// to be installed.
+// install_path: the destination path for Chrome to be installed to. This
+// path does not need to exist.
+// temp_dir: the path of working directory used during installation. This path
+// does not need to exist.
+// reg_root: the root of registry where the function applies settings for the
+// new Chrome version. It should be either HKLM or HKCU.
+// new_version: new Chrome version that needs to be installed
+//
+// This function makes best effort to do installation in a transactional
+// manner. If failed it tries to rollback all changes on the file system
+// and registry. For example, if install_path exists before calling the
+// function, it rolls back all new file and directory changes under
+// install_path. If install_path does not exist before calling the function
+// (typical new install), the function creates install_path during install
+// and removes the whole directory during rollback.
+bool InstallNewVersion(const std::wstring& exe_path,
+ const std::wstring& archive_path,
+ const std::wstring& src_path,
+ const std::wstring& install_path,
+ const std::wstring& temp_dir,
+ const HKEY reg_root,
+ const Version& new_version);
+
+}
+
+#endif // CHROME_INSTALLER_SETUP_SETUP_H__
diff --git a/chrome/installer/setup/setup.ico b/chrome/installer/setup/setup.ico
new file mode 100644
index 0000000..5ecfcbd
--- /dev/null
+++ b/chrome/installer/setup/setup.ico
Binary files differ
diff --git a/chrome/installer/setup/setup.rc b/chrome/installer/setup/setup.rc
new file mode 100644
index 0000000..2423a76
--- /dev/null
+++ b/chrome/installer/setup/setup.rc
@@ -0,0 +1,82 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "setup_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "setup_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""setup_exe_version.rc""\r\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SETUP ICON "setup.ico"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_UNINSTALL_SURVEY_URL "http://go/chromeuninstall?hl=$1&contact_type=uninstall"
+END
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "setup_exe_version.rc"
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/chrome/installer/setup/setup.vcproj b/chrome/installer/setup/setup.vcproj
new file mode 100644
index 0000000..e6c6abf
--- /dev/null
+++ b/chrome/installer/setup/setup.vcproj
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="setup"
+ ProjectGUID="{21C76E6E-8B38-44D6-8148-B589C13B9554}"
+ RootNamespace="setup"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ <ToolFile
+ RelativePath="..\..\tools\build\win\version.rules"
+ />
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\setup_debug.vsprops;..\util\using_util.vsprops;..\util\prebuild\util_prebuild.vsprops"
+ >
+ <Tool
+ Name="Version"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\setup_release.vsprops;..\util\using_util.vsprops;..\util\prebuild\util_prebuild.vsprops"
+ >
+ <Tool
+ Name="Version"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="resources"
+ >
+ <File
+ RelativePath=".\setup_resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\setup.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\setup.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\setup_exe_version.rc.version"
+ >
+ </File>
+ <File
+ RelativePath="$(IntDir)\..\util_prebuild\setup_strings.h"
+ >
+ </File>
+ <File
+ RelativePath="$(IntDir)\..\util_prebuild\setup_strings.rc"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\install.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\setup.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\setup.h"
+ >
+ </File>
+ <File
+ RelativePath=".\setup_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\setup_constants.h"
+ >
+ </File>
+ <File
+ RelativePath=".\uninstall.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\uninstall.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/installer/setup/setup.vsprops b/chrome/installer/setup/setup.vsprops
new file mode 100644
index 0000000..53258e4
--- /dev/null
+++ b/chrome/installer/setup/setup.vsprops
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="setup"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="$(OutDir);$(IntDir)"
+ EnableIntrinsicFunctions="true"
+ BasicRuntimeChecks="0"
+ BufferSecurityCheck="false"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="msi.lib"
+ GenerateMapFile="true"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(OutDir);$(IntDir)"
+ />
+ <Tool
+ Name="VCManifestTool"
+ AdditionalManifestFiles="$(SolutionDir)installer\setup\setup.exe.manifest"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/setup/setup_constants.cc b/chrome/installer/setup/setup_constants.cc
new file mode 100644
index 0000000..3397836
--- /dev/null
+++ b/chrome/installer/setup/setup_constants.cc
@@ -0,0 +1,49 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/setup/setup_constants.h"
+
+namespace installer {
+// Elements that makes up install target path.
+const wchar_t kChromeOldExe[] = L"old_chrome.exe";
+const wchar_t kChromeNewExe[] = L"new_chrome.exe";
+const wchar_t kWowHelperExe[] = L"wow_helper.exe";
+const wchar_t kChromeArchive[] = L"chrome.7z";
+const wchar_t kChromePatchArchive[] = L"patch.7z";
+const wchar_t kChromeCompressedArchive[] = L"chrome.packed.7z";
+const wchar_t kChromeCompressedPatchArchivePrefix[] = L"patch";
+
+// Sub directory of install source package under install temporary directory.
+const wchar_t kInstallSourceDir[] = L"source";
+const wchar_t kInstallSourceChromeDir[] = L"Chrome-bin";
+
+const wchar_t kInstallerDir[] = L"Installer";
+
+const wchar_t kMediaPlayerRegPath[] = L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList";
+} // namespace installer
diff --git a/chrome/installer/setup/setup_constants.h b/chrome/installer/setup/setup_constants.h
new file mode 100644
index 0000000..7e4bc48
--- /dev/null
+++ b/chrome/installer/setup/setup_constants.h
@@ -0,0 +1,53 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines all the command-line switches used by Chrome installer.
+
+#ifndef CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__
+#define CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__
+
+namespace installer {
+
+extern const wchar_t kChromeOldExe[];
+extern const wchar_t kChromeNewExe[];
+extern const wchar_t kWowHelperExe[];
+extern const wchar_t kChromeArchive[];
+extern const wchar_t kChromePatchArchive[];
+extern const wchar_t kChromeCompressedArchive[];
+extern const wchar_t kChromeCompressedPatchArchivePrefix[];
+
+extern const wchar_t kInstallSourceDir[];
+extern const wchar_t kInstallSourceChromeDir[];
+
+extern const wchar_t kInstallerDir[];
+
+extern const wchar_t kMediaPlayerRegPath[];
+} // namespace installer
+
+#endif // CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__
diff --git a/chrome/installer/setup/setup_debug.vsprops b/chrome/installer/setup/setup_debug.vsprops
new file mode 100644
index 0000000..873c6f1
--- /dev/null
+++ b/chrome/installer/setup/setup_debug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="setup_debug"
+ InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;.\setup.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/setup/setup_exe_version.rc.version b/chrome/installer/setup/setup_exe_version.rc.version
new file mode 100644
index 0000000..5c41cf0
--- /dev/null
+++ b/chrome/installer/setup/setup_exe_version.rc.version
@@ -0,0 +1,40 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ PRODUCTVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "@COMPANY_FULLNAME@"
+ VALUE "FileDescription", "@PRODUCT_FULLNAME@"
+ VALUE "FileVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+ VALUE "InternalName", "setup"
+ VALUE "LegalCopyright", "@COPYRIGHT@"
+ VALUE "ProductName", "@PRODUCT_FULLNAME@"
+ VALUE "ProductVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+ VALUE "CompanyShortName", "@COMPANY_SHORTNAME@"
+ VALUE "ProductShortName", "@PRODUCT_SHORTNAME@"
+ VALUE "LastChange", "@LASTCHANGE@"
+ VALUE "Official Build", "@OFFICIAL_BUILD@"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/chrome/installer/setup/setup_release.vsprops b/chrome/installer/setup/setup_release.vsprops
new file mode 100644
index 0000000..ee6094c
--- /dev/null
+++ b/chrome/installer/setup/setup_release.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="setup_release"
+ InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;.\setup.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/setup/setup_resource.h b/chrome/installer/setup/setup_resource.h
new file mode 100644
index 0000000..6915d21
--- /dev/null
+++ b/chrome/installer/setup/setup_resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by setup.rc
+//
+#define IDI_SETUP 101
+#define IDS_UNINSTALL_SURVEY_URL 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
new file mode 100644
index 0000000..9403a8a
--- /dev/null
+++ b/chrome/installer/setup/uninstall.cc
@@ -0,0 +1,303 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines the methods useful for uninstalling Chrome.
+
+#include "chrome/installer/setup/uninstall.h"
+
+#include <atlbase.h>
+#include <windows.h>
+#include <msi.h>
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "base/wmi_util.h"
+#include "chrome/app/google_update_settings.h"
+#include "chrome/app/result_codes.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/l10n_string_util.h"
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+
+#include "setup_resource.h"
+#include "setup_strings.h"
+
+namespace {
+
+// This method deletes Chrome shortcut folder from Windows Start menu. It
+// checks system_uninstall to see if the shortcut is in all users start menu
+// or current user start menu.
+void DeleteChromeShortcut(bool system_uninstall) {
+ std::wstring shortcut_path;
+ if (system_uninstall) {
+ PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path);
+ } else {
+ PathService::Get(base::DIR_START_MENU, &shortcut_path);
+ }
+ if (shortcut_path.empty()) {
+ LOG(ERROR) << "failed to get location for shortcut";
+ } else {
+ file_util::AppendToPath(&shortcut_path,
+ installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE));
+ LOG(INFO) << "Deleting shortcut " << shortcut_path;
+ if (!file_util::Delete(shortcut_path, true))
+ LOG(ERROR) << "Failed to delete folder: " << shortcut_path;
+ }
+}
+
+// This method tries to delete a registry key and logs an error message
+// in case of failure. It returns true if deletion is successful,
+// otherwise false.
+bool DeleteRegistryKey(RegKey& key, const std::wstring& key_path) {
+ LOG(INFO) << "Deleting registry key " << key_path;
+ if (!key.DeleteKey(key_path.c_str())) {
+ LOG(ERROR) << "Failed to delete registry key: " << key_path
+ << " and the error is " << InstallUtil::FormatLastWin32Error();
+ return false;
+ }
+ return true;
+}
+
+// This method tries to delete a registry value and logs an error message
+// in case of failure. It returns true if deletion is successful,
+// otherwise false.
+bool DeleteRegistryValue(HKEY reg_root, const std::wstring& key_path,
+ const std::wstring& value_name) {
+ RegKey key(reg_root, key_path.c_str(), KEY_ALL_ACCESS);
+ LOG(INFO) << "Deleting registry value " << value_name;
+ if (!key.DeleteValue(value_name.c_str())) {
+ LOG(ERROR) << "Failed to delete registry value: " << value_name
+ << " and the error is " << InstallUtil::FormatLastWin32Error();
+ return false;
+ }
+ return true;
+}
+
+// This method checks if Chrome is currently running or if the user has
+// cancelled the uninstall operation by clicking Cancel on the confirmation
+// box that Chrome pops up.
+installer_util::InstallStatus IsChromeActiveOrUserCancelled(
+ bool system_uninstall) {
+ static const std::wstring kCmdLineOptions(L" --uninstall");
+ static const int32 kTimeOutMs = 30000;
+ int32 exit_code = ResultCodes::NORMAL_EXIT;
+ bool is_timeout = false;
+
+ // We ignore all other errors such as whether launching chrome fails,
+ // whether chrome returns UNINSTALL_ERROR, etc.
+ LOG(INFO) << "Launching Chrome to do uninstall tasks.";
+ if (installer::LaunchChromeAndWaitForResult(system_uninstall,
+ kCmdLineOptions,
+ kTimeOutMs,
+ &exit_code,
+ &is_timeout)) {
+ if (is_timeout || exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) {
+ LOG(ERROR) << "Can't uninstall when chrome is still running";
+ return installer_util::CHROME_RUNNING;
+ } else if (exit_code == ResultCodes::UNINSTALL_USER_CANCEL) {
+ LOG(INFO) << "User cancelled uninstall operation";
+ return installer_util::UNINSTALL_CANCELLED;
+ } else if (exit_code == ResultCodes::UNINSTALL_ERROR) {
+ LOG(ERROR) << "chrome.exe reported error while uninstalling.";
+ return installer_util::UNINSTALL_FAILED;
+ }
+ }
+
+ return installer_util::UNINSTALL_CONFIRMED;
+}
+
+// Read the URL from the resource file and substitute the locale parameter
+// with whatever Google Update tells us is the locale. In case we fail to find
+// the locale, we use US English.
+std::wstring GetUninstallSurveyUrl() {
+ const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage(
+ _AtlBaseModule.GetModuleInstance(), IDS_UNINSTALL_SURVEY_URL);
+ DCHECK(image);
+ std::wstring url = std::wstring(image->achString, image->nLength);
+ DCHECK(!url.empty());
+
+ std::wstring language;
+ if (!GoogleUpdateSettings::GetLanguage(&language))
+ language = L"en-US"; // Default to US English.
+
+ return ReplaceStringPlaceholders(url.c_str(), language.c_str(), NULL);
+}
+
+// This method launches an uninstall survey and is called at the end of
+// uninstall process. We are not doing any error checking here as it is
+// not critical to have this survey. If we fail to launch it, we just
+// ignore it silently.
+void LaunchUninstallSurvey(const installer::Version& installed_version) {
+ // Send the Chrome version and OS version as params to the form.
+ // It would be nice to send the locale, too, but I don't see an
+ // easy way to get that in the existing code. It's something we
+ // can add later, if needed.
+ // We depend on installed_version.GetString() not having spaces or other
+ // characters that need escaping: 0.2.13.4. Should that change, we will
+ // need to escape the string before using it in a URL.
+ const std::wstring kVersionParam = L"crversion";
+ const std::wstring kVersion = installed_version.GetString();
+ const std::wstring kOSParam = L"os";
+ std::wstring os_version = L"na";
+ OSVERSIONINFO version_info;
+ version_info.dwOSVersionInfoSize = sizeof version_info;
+ if (GetVersionEx(&version_info)) {
+ os_version = StringPrintf(L"%d.%d.%d",
+ version_info.dwMajorVersion,
+ version_info.dwMinorVersion,
+ version_info.dwBuildNumber);
+ }
+
+ std::wstring iexplore;
+ if (!PathService::Get(base::DIR_PROGRAM_FILES, &iexplore))
+ return;
+
+ file_util::AppendToPath(&iexplore, L"Internet Explorer");
+ file_util::AppendToPath(&iexplore, L"iexplore.exe");
+
+ std::wstring command = iexplore + L" " + GetUninstallSurveyUrl() + L"&" +
+ kVersionParam + L"=" + kVersion + L"&" + kOSParam + L"=" + os_version;
+ int pid = 0;
+ WMIProcessUtil::Launch(command, &pid);
+}
+
+// Uninstall Chrome specific Gears. First we find Gears MSI ProductId (that
+// changes with every new version of Gears) using Gears MSI UpgradeCode (that
+// does not change) and then uninstall Gears using API.
+void UninstallGears() {
+ wchar_t product[39]; // GUID + '\0'
+ MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); // Don't show any UI to user.
+ for (int i = 0; MsiEnumRelatedProducts(google_update::kGearsUpgradeCode, 0, i,
+ product) != ERROR_NO_MORE_ITEMS; ++i) {
+ LOG(INFO) << "Uninstalling Gears - " << product;
+ unsigned int ret = MsiConfigureProduct(product, INSTALLLEVEL_MAXIMUM,
+ INSTALLSTATE_ABSENT);
+ if (ret != ERROR_SUCCESS)
+ LOG(ERROR) << "Failed to uninstall Gears " << product
+ << " because of error " << ret;
+ }
+}
+
+} // namespace
+
+
+installer_util::InstallStatus installer_setup::UninstallChrome(
+ const std::wstring& exe_path, bool system_uninstall,
+ const installer::Version& installed_version, bool remove_all) {
+ installer_util::InstallStatus status =
+ IsChromeActiveOrUserCancelled(system_uninstall);
+ if (status == installer_util::CHROME_RUNNING ||
+ status == installer_util::UNINSTALL_CANCELLED)
+ return status;
+
+ // Uninstall Gears first.
+ UninstallGears();
+
+ // Chrome is not in use so lets uninstall Chrome by deleting various files
+ // and registry entries. Here we will just make best effort and keep going
+ // in case of errors.
+ // First delete shortcut from Start->Programs.
+ DeleteChromeShortcut(system_uninstall);
+
+ // Delete the registry keys (Uninstall key and Google Update update key).
+ HKEY reg_root = system_uninstall ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ RegKey key(reg_root, L"", KEY_ALL_ACCESS);
+ DeleteRegistryKey(key, installer_util::kUninstallRegPath);
+ DeleteRegistryKey(key, InstallUtil::GetChromeGoogleUpdateKey());
+
+ // Delete Software\Classes\ChromeHTML,
+ // Software\Clients\StartMenuInternet\chrome.exe and
+ // Software\RegisteredApplications\Chrome
+ std::wstring html_prog_id(ShellUtil::kRegClasses);
+ file_util::AppendToPath(&html_prog_id, ShellUtil::kChromeHTMLProgId);
+ DeleteRegistryKey(key, html_prog_id);
+
+ std::wstring set_access_key(ShellUtil::kRegStartMenuInternet);
+ file_util::AppendToPath(&set_access_key, installer_util::kChromeExe);
+ DeleteRegistryKey(key, set_access_key);
+
+ DeleteRegistryValue(reg_root, ShellUtil::kRegRegisteredApplications,
+ installer_util::kApplicationName);
+ key.Close();
+
+ // Delete shared registry keys as well (these require admin rights) if
+ // remove_all option is specified.
+ if (remove_all) {
+ RegKey hklm_key(HKEY_LOCAL_MACHINE, L"", KEY_ALL_ACCESS);
+ DeleteRegistryKey(hklm_key, set_access_key);
+ DeleteRegistryKey(hklm_key, html_prog_id);
+ DeleteRegistryValue(HKEY_LOCAL_MACHINE,
+ ShellUtil::kRegRegisteredApplications,
+ installer_util::kApplicationName);
+
+ // Delete media player registry key that exists only in HKLM.
+ std::wstring reg_path(installer::kMediaPlayerRegPath);
+ file_util::AppendToPath(&reg_path, installer_util::kChromeExe);
+ DeleteRegistryKey(hklm_key, reg_path);
+ hklm_key.Close();
+ }
+
+ // Finally delete all the files from Chrome folder after moving setup.exe
+ // to a temp location.
+ std::wstring install_path(installer::GetChromeInstallPath(system_uninstall));
+ if (install_path.empty()) {
+ LOG(ERROR) << "Couldn't get installation destination path";
+ // Nothing else we could do for uninstall, so we return.
+ return installer_util::UNINSTALL_FAILED;
+ } else {
+ LOG(INFO) << "install destination path: " << install_path;
+ }
+
+ std::wstring setup_exe(install_path);
+ file_util::AppendToPath(&setup_exe, installed_version.GetString());
+ file_util::AppendToPath(&setup_exe, installer::kInstallerDir);
+ file_util::AppendToPath(&setup_exe, file_util::GetFilenameFromPath(exe_path));
+
+ std::wstring temp_file;
+ file_util::CreateTemporaryFileName(&temp_file);
+ file_util::Move(setup_exe, temp_file);
+
+ LOG(INFO) << "Deleting install path " << install_path;
+ if (!file_util::Delete(install_path, true))
+ LOG(ERROR) << "Failed to delete folder: " << install_path;
+
+ LOG(INFO) << "Uninstallation complete. Launching Uninstall survey.";
+ LaunchUninstallSurvey(installed_version);
+ return installer_util::UNINSTALL_SUCCESSFUL;
+}
diff --git a/chrome/installer/setup/uninstall.h b/chrome/installer/setup/uninstall.h
new file mode 100644
index 0000000..9308859
--- /dev/null
+++ b/chrome/installer/setup/uninstall.h
@@ -0,0 +1,56 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file declares Chrome uninstall related functions.
+
+#ifndef CHROME_INSTALLER_SETUP_UNINSTALL_H__
+#define CHROME_INSTALLER_SETUP_UNINSTALL_H__
+
+#include <string>
+
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+
+namespace installer_setup {
+// This function uninstalls Chrome.
+//
+// exe_path: Path to the executable (setup.exe) as it will be copied
+// to temp folder before deleting Chrome folder.
+// system_uninstall: if true, the function uninstalls Chrome installed system
+// wise. otherwise, it uninstalls Chrome installed for the
+// current user.
+// installed_version: currently installed version of Chrome.
+// remove_all: Remove all shared files, registry entries as well.
+installer_util::InstallStatus UninstallChrome(
+ const std::wstring& exe_path, bool system_uninstall,
+ const installer::Version& installed_version, bool remove_all);
+
+} // namespace installer_setup
+
+#endif // CHROME_INSTALLER_SETUP_UNINSTALL_H__
diff --git a/chrome/installer/util/SConscript b/chrome/installer/util/SConscript
new file mode 100644
index 0000000..7a517cf
--- /dev/null
+++ b/chrome/installer/util/SConscript
@@ -0,0 +1,106 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env')
+
+env = env.Clone()
+
+
+env.Prepend(
+ CPPPATH = [
+ Dir("#/../third_party/lzma_sdk"),
+ Dir("../chrome/third_party/wtl/include"),
+ Dir("#/../third_party/npapi"),
+ Dir("#/../third_party/libxml/include"),
+ #/I "C:/src/trunk/chrome/Debug/obj/generated_resources"
+ #/I "C:/src/trunk/chrome/Debug/obj/localized_strings"
+ Dir("#/../skia/include"),
+ Dir("#/../skia/include/corecg"),
+ Dir("#/../skia/platform"),
+ Dir("#/../third_party/libpng"),
+ Dir("#/../third_party/zlib"),
+ Dir("#/../breakpad/src"),
+ Dir("#/../third_party/libjpeg"),
+ Dir("#/../third_party/icu38/public/common"),
+ Dir("#/../third_party/icu38/public/i18n"),
+ Dir("#/.."),
+ Dir("."),
+ ],
+ CPPDEFINES = [
+ "_LZMA_IN_CB",
+ "LIBXML_STATIC",
+ "PNG_USER_CONFIG",
+ "CHROME_PNG_WRITE_SUPPORT"
+ "U_STATIC_IMPLEMENTATION",
+ "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
+ "WIN32_LEAN_AND_MEAN",
+ ],
+ CCFLAGS = [
+ '/TP',
+
+ '/Wp64',
+
+ '/wd4503',
+ '/wd4819',
+ ],
+)
+
+input_files = [
+ "../../app/google_update_settings$OBJSUFFIX",
+ "copy_tree_work_item.cc",
+ "create_dir_work_item.cc",
+ "create_reg_key_work_item.cc",
+ "delete_tree_work_item.cc",
+ "google_update_constants.cc",
+ "helper.cc",
+ "install_util.cc",
+ "l10n_string_util.cc",
+ "logging_installer.cc",
+ "lzma_util.cc",
+ "set_reg_value_work_item.cc",
+ "shell_util.cc",
+ "util_constants.cc",
+ "version.cc",
+ "work_item.cc",
+ "work_item_list.cc",
+]
+
+x = env.StaticLibrary('util', input_files)
+
+
+# create_string_rc.py imports FP.py from the tools/grit/grit/extern
+# directory, so add that to PYTHONPATH for this command execution.
+env_x = env.Clone()
+env_x.AppendENVPath('PYTHONPATH', [Dir('#/../tools/grit/grit/extern').abspath])
+env_x.Command(['$CHROME_DIR/installer/util/setup_strings.rc',
+ '$CHROME_DIR/installer/util/setup_strings.h'],
+ ['$CHROME_DIR/installer/util/prebuild/create_string_rc.py',
+ '$CHROME_DIR/app/generated_resources.grd'] +
+ env.Glob('$CHROME_DIR/app/resources/*.xtb'),
+ "$PYTHON ${SOURCES[0]} ${TARGET.dir}")
diff --git a/chrome/installer/util/copy_tree_work_item.cc b/chrome/installer/util/copy_tree_work_item.cc
new file mode 100644
index 0000000..c6eaacd
--- /dev/null
+++ b/chrome/installer/util/copy_tree_work_item.cc
@@ -0,0 +1,169 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/util/copy_tree_work_item.h"
+
+#include <shlwapi.h>
+#include "base/file_util.h"
+#include "chrome/installer/util/logging_installer.h"
+
+CopyTreeWorkItem::~CopyTreeWorkItem() {
+ if (file_util::PathExists(backup_path_)) {
+ file_util::Delete(backup_path_, true);
+ }
+}
+
+CopyTreeWorkItem::CopyTreeWorkItem(std::wstring source_path,
+ std::wstring dest_path,
+ std::wstring temp_dir,
+ CopyOverWriteOption overwrite_option,
+ std::wstring alternative_path)
+ : source_path_(source_path),
+ dest_path_(dest_path),
+ temp_dir_(temp_dir),
+ overwrite_option_(overwrite_option),
+ alternative_path_(alternative_path),
+ copied_to_dest_path_(false),
+ moved_to_backup_(false),
+ copied_to_alternate_path_(false) {
+}
+
+bool CopyTreeWorkItem::Do() {
+ if (!file_util::PathExists(source_path_)) {
+ LOG(ERROR) << source_path_ << " does not exist";
+ return false;
+ }
+
+ bool dest_exist = file_util::PathExists(dest_path_);
+ // handle overwrite_option_ = IF_DIFFERENT case
+ if ((dest_exist) &&
+ (overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file
+ (!PathIsDirectory(source_path_.c_str())) &&
+ (!PathIsDirectory(dest_path_.c_str())) &&
+ (file_util::ContentsEqual(source_path_, dest_path_))) {
+ LOG(INFO) << "Source file " << source_path_
+ << " and destination file " << dest_path_
+ << " are exactly same. Returning true.";
+ return true;
+ }
+
+ // handle overwrite_option_ = RENAME_IF_IN_USE case
+ if ((dest_exist) &&
+ (overwrite_option_ == WorkItem::RENAME_IF_IN_USE) && // only for a file
+ (!PathIsDirectory(source_path_.c_str())) &&
+ (!PathIsDirectory(dest_path_.c_str())) &&
+ (IsFileInUse(dest_path_))) {
+ if (alternative_path_.empty() ||
+ file_util::PathExists(alternative_path_) ||
+ !file_util::CopyFile(source_path_, alternative_path_)) {
+ LOG(ERROR) << "failed to copy " << source_path_ <<
+ " to " << alternative_path_;
+ return false;
+ } else {
+ copied_to_alternate_path_ = true;
+ LOG(INFO) << "Copied source file " << source_path_
+ << " to alternative path " << alternative_path_;
+ return true;
+ }
+ }
+
+ // All other cases where we move dest if it exists, and copy the files
+ if (dest_exist) {
+ if (!GetBackupPath())
+ return false;
+
+ if (file_util::Move(dest_path_, backup_path_)) {
+ moved_to_backup_ = true;
+ LOG(INFO) << "Moved destination " << dest_path_
+ << " to backup path " << backup_path_;
+ } else {
+ LOG(ERROR) << "failed moving " << dest_path_ << " to " << backup_path_;
+ return false;
+ }
+ }
+
+ if (file_util::CopyDirectory(source_path_, dest_path_, true)) {
+ copied_to_dest_path_ = true;
+ LOG(INFO) << "Copied source " << source_path_
+ << " to destination " << dest_path_;
+ } else {
+ LOG(ERROR) << "failed copy " << source_path_ << " to " << dest_path_;
+ return false;
+ }
+
+ return true;
+}
+
+void CopyTreeWorkItem::Rollback() {
+ // Normally the delete operations below should not fail unless some
+ // programs like anti-virus are inpecting the files we just copied.
+ // If this does happen sometimes, we may consider using Move instead of
+ // Delete here. For now we just log the error and continue with the
+ // rest of rollback operation.
+ if (copied_to_dest_path_ && !file_util::Delete(dest_path_, true)) {
+ LOG(ERROR) << "Can not delete " << dest_path_;
+ }
+ if (moved_to_backup_ && !file_util::Move(backup_path_, dest_path_)) {
+ LOG(ERROR) << "failed move " << backup_path_ << " to " << dest_path_;
+ }
+ if (copied_to_alternate_path_ &&
+ !file_util::Delete(alternative_path_, true)) {
+ LOG(ERROR) << "Can not delete " << alternative_path_;
+ }
+}
+
+bool CopyTreeWorkItem::IsFileInUse(std::wstring path) {
+ if (!file_util::PathExists(path))
+ return false;
+
+ HANDLE handle = ::CreateFile(path.c_str(), FILE_ALL_ACCESS,
+ NULL, NULL, OPEN_EXISTING, NULL, NULL);
+ if (handle == INVALID_HANDLE_VALUE)
+ return true;
+
+ CloseHandle(handle);
+ return false;
+}
+
+bool CopyTreeWorkItem::GetBackupPath() {
+ std::wstring file_name = file_util::GetFilenameFromPath(dest_path_);
+ backup_path_.assign(temp_dir_);
+ file_util::AppendToPath(&backup_path_, file_name);
+
+ if (file_util::PathExists(backup_path_)) {
+ // Ideally we should not fail immediately. Instead we could try some
+ // random paths under temp_dir_ until we reach certain limit.
+ // For now our caller always provides a good temporary directory so
+ // we don't bother.
+ LOG(ERROR) << "backup path " << backup_path_ << " already exists";
+ return false;
+ }
+
+ return true;
+}
diff --git a/chrome/installer/util/copy_tree_work_item.h b/chrome/installer/util/copy_tree_work_item.h
new file mode 100644
index 0000000..c942fe9
--- /dev/null
+++ b/chrome/installer/util/copy_tree_work_item.h
@@ -0,0 +1,105 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_COPY_TREE_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_COPY_TREE_WORK_ITEM_H__
+
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that recursively copies a file system hierarchy from
+// source path to destination path. It also creates all necessary intermediate
+// paths of the destination path if they do not exist. The file system
+// hierarchy could be a single file, or a directory.
+// Under the cover CopyTreeWorkItem moves the destination path, if existing,
+// to the temporary directory passed in, and then copies the source hierarchy
+// to the destination location. During rollback the original destination
+// hierarchy is moved back.
+class CopyTreeWorkItem : public WorkItem {
+ public:
+ virtual ~CopyTreeWorkItem();
+
+ virtual bool Do();
+
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ // See comments on corresponding member varibles for the semantics of
+ // arguments.
+ // Notes on temp_path: to facilitate rollback, the caller needs to supply
+ // a temporary directory to save the original files if they exist under
+ // dest_path.
+ CopyTreeWorkItem(std::wstring source_path, std::wstring dest_path,
+ std::wstring temp_dir, CopyOverWriteOption overwrite_option,
+ std::wstring alternative_path);
+
+ // Checks if the path specified is in use (and hence can not be deleted)
+ bool IsFileInUse(std::wstring path);
+
+ // Get a backup path that can keep the original files under dest_path_,
+ // and set backup_path_ with the result.
+ bool GetBackupPath();
+
+ // Source path to copy files from.
+ std::wstring source_path_;
+
+ // Destination path to copy files to.
+ std::wstring dest_path_;
+
+ // Temporary directory that can be used.
+ std::wstring temp_dir_;
+
+ // Controls the behavior for overwriting.
+ CopyOverWriteOption overwrite_option_;
+
+ // If overwrite_option_ = RENAME_IF_IN_USE, this variables stores the path
+ // to be used if the file is in use and hence we want to copy it to a
+ // different path.
+ std::wstring alternative_path_;
+
+ // Whether the source was copied to dest_path_
+ bool copied_to_dest_path_;
+
+ // Whether the original files have been moved to backup path under
+ // temporary directory. If true, moving back is needed during rollback.
+ bool moved_to_backup_;
+
+ // Whether the source was copied to alternative_path_ because dest_path_
+ // existed and was in use. Needed during rollback.
+ bool copied_to_alternate_path_;
+
+ // The full path in temporary directory that the original dest_path_ has
+ // been moved to.
+ std::wstring backup_path_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_COPY_TREE_WORK_ITEM_H__
diff --git a/chrome/installer/util/copy_tree_work_item_unittest.cc b/chrome/installer/util/copy_tree_work_item_unittest.cc
new file mode 100644
index 0000000..40e4a95
--- /dev/null
+++ b/chrome/installer/util/copy_tree_work_item_unittest.cc
@@ -0,0 +1,620 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/work_item.h"
+#include "chrome/installer/util/copy_tree_work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ class CopyTreeWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Name a subdirectory of the user temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"CopyTreeWorkItemTest");
+
+ // Create a fresh, empty copy of this test directory.
+ file_util::Delete(test_dir_, true);
+ CreateDirectory(test_dir_.c_str(), NULL);
+
+ // Create a tempory directory under the test directory.
+ temp_dir_.assign(test_dir_);
+ file_util::AppendToPath(&temp_dir_, L"temp");
+ CreateDirectory(temp_dir_.c_str(), NULL);
+
+ // Create a log file
+ std::wstring log_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileName(&log_file));
+ ASSERT_TRUE(file_util::PathExists(log_file));
+
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ logging::SetMinLogLevel(logging::LOG_INFO);
+
+ ASSERT_TRUE(file_util::PathExists(test_dir_));
+ ASSERT_TRUE(file_util::PathExists(temp_dir_));
+ }
+
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, false));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ // the path to temporary directory used to contain the test operations
+ std::wstring test_dir_;
+ std::wstring temp_dir_;
+ };
+
+ // Simple function to dump some text into a new file.
+ void CreateTextFile(const std::wstring& filename,
+ const std::wstring& contents) {
+ std::ofstream file;
+ file.open(filename.c_str());
+ ASSERT_TRUE(file.is_open());
+ file << contents;
+ file.close();
+ }
+
+ // Simple function to read text from a file.
+ std::wstring ReadTextFile(const std::wstring& filename) {
+ WCHAR contents[64];
+ std::wifstream file;
+ file.open(filename.c_str());
+ EXPECT_TRUE(file.is_open());
+ file.getline(contents, 64);
+ file.close();
+ return std::wstring(contents);
+ }
+
+ wchar_t text_content_1[] = L"Gooooooooooooooooooooogle";
+ wchar_t text_content_2[] = L"Overwrite Me";
+};
+
+// Copy one file from source to destination.
+TEST_F(CopyTreeWorkItemTest, CopyFile) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From.txt");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create destination path
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To.txt");
+
+ // test Do()
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::ALWAYS));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_TRUE(file_util::ContentsEqual(file_name_from, file_name_to));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_FALSE(file_util::PathExists(file_name_to));
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+}
+
+// Copy one file, overwriting the existing one in destination.
+// Test with always_overwrite being true or false. The file is overwritten
+// regardless since the content at destination file is different from source.
+TEST_F(CopyTreeWorkItemTest, CopyFileOverwrite) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From.txt");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create destination file
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To.txt");
+ CreateTextFile(file_name_to, text_content_2);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ // test Do() with always_overwrite being true.
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::ALWAYS));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_2));
+
+ // test Do() with always_overwrite being false.
+ // the file is still overwritten since the content is different.
+ work_item.reset(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::IF_DIFFERENT));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_2));
+}
+
+// Copy one file, with the existing one in destination having the same
+// content.
+// If always_overwrite being true, the file is overwritten.
+// If always_overwrite being false, the file is unchanged.
+TEST_F(CopyTreeWorkItemTest, CopyFileSameContent) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From.txt");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create destination file
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To.txt");
+ CreateTextFile(file_name_to, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ // Get the path of backup file
+ std::wstring backup_file(temp_dir_);
+ file_util::AppendToPath(&backup_file, L"File_To.txt");
+
+ // test Do() with always_overwrite being true.
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::ALWAYS));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // we verify the file is overwritten by checking the existence of backup
+ // file.
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_EQ(0, ReadTextFile(backup_file).compare(text_content_1));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // the backup file should be gone after rollback
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+
+ // test Do() with always_overwrite being false. nothing should change.
+ work_item.reset(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::IF_DIFFERENT));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // we verify the file is not overwritten by checking that the backup
+ // file does not exist.
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+
+ // test rollback(). nothing should happen here.
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+}
+
+// Copy one file and without rollback. Verify all temporary files are deleted.
+TEST_F(CopyTreeWorkItemTest, CopyFileAndCleanup) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From.txt");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create destination file
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To.txt");
+ CreateTextFile(file_name_to, text_content_2);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ // Get the path of backup file
+ std::wstring backup_file(temp_dir_);
+ file_util::AppendToPath(&backup_file, L"File_To.txt");
+
+ {
+ // test Do().
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::IF_DIFFERENT));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // verify the file is moved to backup place.
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_EQ(0, ReadTextFile(backup_file).compare(text_content_2));
+ }
+
+ // verify the backup file is cleaned up as well.
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+}
+
+// Copy one file, with the existing one in destination being used with
+// overwrite option as IF_DIFFERENT. This destination-file-in-use should
+// be moved to backup location after Do() and moved back after Rollback().
+TEST_F(CopyTreeWorkItemTest, CopyFileInUse) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create an executable in destination path by copying ourself to it.
+ wchar_t exe_full_path_str[MAX_PATH];
+ ::GetModuleFileNameW(NULL, exe_full_path_str, MAX_PATH);
+ std::wstring exe_full_path(exe_full_path_str);
+
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To");
+ file_util::CopyFile(exe_full_path, file_name_to);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ LOG(INFO) << "copy ourself from " << exe_full_path << " to " << file_name_to;
+
+ // Run the executable in destination path
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ ASSERT_TRUE(
+ ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi));
+
+ // Get the path of backup file
+ std::wstring backup_file(temp_dir_);
+ file_util::AppendToPath(&backup_file, L"File_To");
+
+ // test Do().
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::IF_DIFFERENT));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // verify the file in used is moved to backup place.
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, backup_file));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to));
+ // the backup file should be gone after rollback
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+
+ TerminateProcess(pi.hProcess, 0);
+ // make sure the handle is closed.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+}
+
+// Test overwrite option RENAME_IF_IN_USE:
+// 1. If destination file is in use, the source should be copied with the
+// new name after Do() and this new name file should be deleted
+// after rollback.
+// 2. If destination file is not in use, the source should be copied in the
+// destination folder after Do() and should be rolled back after Rollback().
+TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create an executable in destination path by copying ourself to it.
+ wchar_t exe_full_path_str[MAX_PATH];
+ ::GetModuleFileNameW(NULL, exe_full_path_str, MAX_PATH);
+ std::wstring exe_full_path(exe_full_path_str);
+
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to), alternate_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To");
+ file_util::AppendToPath(&alternate_to, L"Alternate_To");
+ file_util::CopyFile(exe_full_path, file_name_to);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ LOG(INFO) << "copy ourself from " << exe_full_path << " to " << file_name_to;
+
+ // Run the executable in destination path
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ ASSERT_TRUE(
+ ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi));
+
+ // Get the path of backup file
+ std::wstring backup_file(temp_dir_);
+ file_util::AppendToPath(&backup_file, L"File_To");
+
+ // test Do().
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::RENAME_IF_IN_USE,
+ alternate_to));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to));
+ // verify that the backup path does not exist
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+ EXPECT_TRUE(file_util::ContentsEqual(file_name_from, alternate_to));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to));
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+ // the alternate file should be gone after rollback
+ EXPECT_FALSE(file_util::PathExists(alternate_to));
+
+ TerminateProcess(pi.hProcess, 0);
+ // make sure the handle is closed.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Now the process has terminated, lets try overwriting the file again
+ work_item.reset(WorkItem::CreateCopyTreeWorkItem(
+ file_name_from, file_name_to, temp_dir_, WorkItem::RENAME_IF_IN_USE,
+ alternate_to));
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_TRUE(file_util::ContentsEqual(file_name_from, file_name_to));
+ // verify that the backup path does exist
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_FALSE(file_util::PathExists(alternate_to));
+
+ // test rollback()
+ work_item->Rollback();
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to));
+ // the backup file should be gone after rollback
+ EXPECT_FALSE(file_util::PathExists(backup_file));
+ EXPECT_FALSE(file_util::PathExists(alternate_to));
+}
+
+// Copy one file without rollback. The existing one in destination is in use.
+// Verify it is moved to backup location and stays there.
+TEST_F(CopyTreeWorkItemTest, CopyFileInUseAndCleanup) {
+ // Create source file
+ std::wstring file_name_from(test_dir_);
+ file_util::AppendToPath(&file_name_from, L"File_From");
+ CreateTextFile(file_name_from, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+ // Create an executable in destination path by copying ourself to it.
+ wchar_t exe_full_path_str[MAX_PATH];
+ ::GetModuleFileNameW(NULL, exe_full_path_str, MAX_PATH);
+ std::wstring exe_full_path(exe_full_path_str);
+
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
+ CreateDirectory(dir_name_to.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+ std::wstring file_name_to(dir_name_to);
+ file_util::AppendToPath(&file_name_to, L"File_To");
+ file_util::CopyFile(exe_full_path, file_name_to);
+ ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+ LOG(INFO) << "copy ourself from " << exe_full_path << " to " << file_name_to;
+
+ // Run the executable in destination path
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ ASSERT_TRUE(
+ ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi));
+
+ // Get the path of backup file
+ std::wstring backup_file(temp_dir_);
+ file_util::AppendToPath(&backup_file, L"File_To");
+
+ // test Do().
+ {
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
+ temp_dir_, WorkItem::IF_DIFFERENT));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(file_name_from));
+ EXPECT_TRUE(file_util::PathExists(file_name_to));
+ EXPECT_EQ(0, ReadTextFile(file_name_from).compare(text_content_1));
+ EXPECT_EQ(0, ReadTextFile(file_name_to).compare(text_content_1));
+ // verify the file in used is moved to backup place.
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, backup_file));
+ }
+
+ // verify the file in used should be still at the backup place.
+ EXPECT_TRUE(file_util::PathExists(backup_file));
+ EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, backup_file));
+
+ TerminateProcess(pi.hProcess, 0);
+ // make sure the handle is closed.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+}
+
+// Copy a tree from source to destination.
+TEST_F(CopyTreeWorkItemTest, CopyTree) {
+ // Create source tree
+ std::wstring dir_name_from(test_dir_);
+ file_util::AppendToPath(&dir_name_from, L"from");
+ CreateDirectory(dir_name_from.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+ std::wstring dir_name_from_1(dir_name_from);
+ file_util::AppendToPath(&dir_name_from_1, L"1");
+ CreateDirectory(dir_name_from_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_from_1));
+
+ std::wstring dir_name_from_2(dir_name_from);
+ file_util::AppendToPath(&dir_name_from_2, L"2");
+ CreateDirectory(dir_name_from_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_from_2));
+
+ std::wstring file_name_from_1(dir_name_from_1);
+ file_util::AppendToPath(&file_name_from_1, L"File_1.txt");
+ CreateTextFile(file_name_from_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from_1));
+
+ std::wstring file_name_from_2(dir_name_from_2);
+ file_util::AppendToPath(&file_name_from_2, L"File_2.txt");
+ CreateTextFile(file_name_from_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_from_2));
+
+ std::wstring dir_name_to(test_dir_);
+ file_util::AppendToPath(&dir_name_to, L"to");
+
+ // test Do()
+ {
+ scoped_ptr<CopyTreeWorkItem> work_item(
+ WorkItem::CreateCopyTreeWorkItem(dir_name_from, dir_name_to,
+ temp_dir_, WorkItem::ALWAYS));
+
+ EXPECT_TRUE(work_item->Do());
+ }
+
+ std::wstring file_name_to_1(dir_name_to);
+ file_util::AppendToPath(&file_name_to_1, L"1");
+ file_util::AppendToPath(&file_name_to_1, L"File_1.txt");
+ EXPECT_TRUE(file_util::PathExists(file_name_to_1));
+ LOG(INFO) << "compare " << file_name_from_1 << " and " << file_name_to_1;
+ EXPECT_TRUE(file_util::ContentsEqual(file_name_from_1, file_name_to_1));
+
+ std::wstring file_name_to_2(dir_name_to);
+ file_util::AppendToPath(&file_name_to_2, L"2");
+ file_util::AppendToPath(&file_name_to_2, L"File_2.txt");
+ EXPECT_TRUE(file_util::PathExists(file_name_to_2));
+ LOG(INFO) << "compare " << file_name_from_2 << " and " << file_name_to_2;
+ EXPECT_TRUE(file_util::ContentsEqual(file_name_from_2, file_name_to_2));
+}
diff --git a/chrome/installer/util/create_dir_work_item.cc b/chrome/installer/util/create_dir_work_item.cc
new file mode 100644
index 0000000..ba0f0a5
--- /dev/null
+++ b/chrome/installer/util/create_dir_work_item.cc
@@ -0,0 +1,94 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/file_util.h"
+#include "chrome/installer/util/create_dir_work_item.h"
+#include "chrome/installer/util/logging_installer.h"
+
+CreateDirWorkItem::~CreateDirWorkItem() {
+}
+
+CreateDirWorkItem::CreateDirWorkItem(const std::wstring& path)
+ : path_(path),
+ rollback_needed_(false) {
+}
+
+void CreateDirWorkItem::GetTopDirToCreate() {
+ if (file_util::PathExists(path_)) {
+ top_path_.clear();
+ return;
+ }
+
+ std::wstring parent_dir(path_);
+ do {
+ top_path_.assign(parent_dir);
+ file_util::UpOneDirectoryOrEmpty(&parent_dir);
+ } while (!parent_dir.empty() && !file_util::PathExists(parent_dir));
+ return;
+}
+
+bool CreateDirWorkItem::Do() {
+ LOG(INFO) << "creating directory " << path_;
+ GetTopDirToCreate();
+ if (top_path_.empty())
+ return true;
+
+ LOG(INFO) << "top directory that needs to be created: " \
+ << top_path_;
+ bool result = file_util::CreateDirectory(path_);
+ LOG(INFO) << "directory creation result: " << result;
+
+ rollback_needed_ = true;
+
+ return result;
+}
+
+void CreateDirWorkItem::Rollback() {
+ if (!rollback_needed_)
+ return;
+
+ // Delete all the directories we created to rollback.
+ // Note we can not recusively delete top_path_ since we don't want to
+ // delete non-empty directory. (We may have created a shared directory).
+ // Instead we walk through path_ to top_path_ and delete directories
+ // along the way.
+ std::wstring path_to_delete(path_);
+
+ while(1) {
+ if (file_util::PathExists(path_to_delete)) {
+ if (!RemoveDirectory(path_to_delete.c_str()))
+ break;
+ }
+ if (!path_to_delete.compare(top_path_))
+ break;
+ file_util::UpOneDirectoryOrEmpty(&path_to_delete);
+ }
+
+ return;
+}
diff --git a/chrome/installer/util/create_dir_work_item.h b/chrome/installer/util/create_dir_work_item.h
new file mode 100644
index 0000000..9d3971d
--- /dev/null
+++ b/chrome/installer/util/create_dir_work_item.h
@@ -0,0 +1,70 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_CREATE_DIR_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_CREATE_DIR_WORK_ITEM_H__
+
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that creates a directory with the specified path.
+// It also creates all necessary intermediate paths if they do not exist.
+class CreateDirWorkItem : public WorkItem {
+ public:
+ virtual ~CreateDirWorkItem();
+
+ virtual bool Do();
+
+ // Rollback tries to remove all directories created along the path.
+ // If the leaf directory or one of the intermediate directories are not
+ // empty, the non-empty directory and its parent directories will not be
+ // removed.
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ CreateDirWorkItem(const std::wstring& path);
+
+ // Get the top most directory that needs to be created in order to create
+ // "path_", and set "top_path_" accordingly. if "path_" already exists,
+ // "top_path_" is set to empty string.
+ void GetTopDirToCreate();
+
+ // Path of the directory to be created.
+ std::wstring path_;
+
+ // The top most directory that needs to be created.
+ std::wstring top_path_;
+
+ bool rollback_needed_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_CREATE_DIR_WORK_ITEM_H__
diff --git a/chrome/installer/util/create_dir_work_item_unittest.cc b/chrome/installer/util/create_dir_work_item_unittest.cc
new file mode 100644
index 0000000..d4ba9b2
--- /dev/null
+++ b/chrome/installer/util/create_dir_work_item_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/work_item.h"
+#include "chrome/installer/util/create_dir_work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ class CreateDirWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Name a subdirectory of the temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"CreateDirWorkItemTest");
+
+ // Create a fresh, empty copy of this directory.
+ file_util::Delete(test_dir_, true);
+ CreateDirectory(test_dir_.c_str(), NULL);
+ }
+ virtual void TearDown() {
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, false));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ // the path to temporary directory used to contain the test operations
+ std::wstring test_dir_;
+ };
+};
+
+TEST_F(CreateDirWorkItemTest, CreatePath) {
+ std::wstring parent_dir(test_dir_);
+ file_util::AppendToPath(&parent_dir, L"a");
+ CreateDirectory(parent_dir.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(parent_dir));
+
+ std::wstring top_dir_to_create(parent_dir);
+ file_util::AppendToPath(&top_dir_to_create, L"b");
+
+ std::wstring dir_to_create(top_dir_to_create);
+ file_util::AppendToPath(&dir_to_create, L"c");
+ file_util::AppendToPath(&dir_to_create, L"d");
+
+ scoped_ptr<CreateDirWorkItem> work_item(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(dir_to_create));
+
+ work_item->Rollback();
+
+ // Rollback should delete all the paths up to top_dir_to_create.
+ EXPECT_FALSE(file_util::PathExists(top_dir_to_create));
+ EXPECT_TRUE(file_util::PathExists(parent_dir));
+}
+
+TEST_F(CreateDirWorkItemTest, CreateExistingPath) {
+ std::wstring dir_to_create(test_dir_);
+ file_util::AppendToPath(&dir_to_create, L"aa");
+ CreateDirectory(dir_to_create.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_to_create));
+
+ scoped_ptr<CreateDirWorkItem> work_item(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(dir_to_create));
+
+ work_item->Rollback();
+
+ // Rollback should not remove the path since it exists before
+ // the CreateDirWorkItem is called.
+ EXPECT_TRUE(file_util::PathExists(dir_to_create));
+}
+
+TEST_F(CreateDirWorkItemTest, CreateSharedPath) {
+ std::wstring dir_to_create_1(test_dir_);
+ file_util::AppendToPath(&dir_to_create_1, L"aaa");
+
+ std::wstring dir_to_create_2(dir_to_create_1);
+ file_util::AppendToPath(&dir_to_create_2, L"bbb");
+
+ std::wstring dir_to_create_3(dir_to_create_2);
+ file_util::AppendToPath(&dir_to_create_3, L"ccc");
+
+ scoped_ptr<CreateDirWorkItem> work_item(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create_3));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(dir_to_create_3));
+
+ // Create another directory under dir_to_create_2
+ std::wstring dir_to_create_4(dir_to_create_2);
+ file_util::AppendToPath(&dir_to_create_4, L"ddd");
+ CreateDirectory(dir_to_create_4.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_to_create_4));
+
+ work_item->Rollback();
+
+ // Rollback should delete dir_to_create_3.
+ EXPECT_FALSE(file_util::PathExists(dir_to_create_3));
+
+ // Rollback should not delete dir_to_create_2 as it is shared.
+ EXPECT_TRUE(file_util::PathExists(dir_to_create_2));
+ EXPECT_TRUE(file_util::PathExists(dir_to_create_4));
+}
+
+TEST_F(CreateDirWorkItemTest, RollbackWithMissingDir) {
+ std::wstring dir_to_create_1(test_dir_);
+ file_util::AppendToPath(&dir_to_create_1, L"aaaa");
+
+ std::wstring dir_to_create_2(dir_to_create_1);
+ file_util::AppendToPath(&dir_to_create_2, L"bbbb");
+
+ std::wstring dir_to_create_3(dir_to_create_2);
+ file_util::AppendToPath(&dir_to_create_3, L"cccc");
+
+ scoped_ptr<CreateDirWorkItem> work_item(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create_3));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(file_util::PathExists(dir_to_create_3));
+
+ RemoveDirectory(dir_to_create_3.c_str());
+ ASSERT_FALSE(file_util::PathExists(dir_to_create_3));
+
+ work_item->Rollback();
+
+ // dir_to_create_3 has already been deleted, Rollback should delete
+ // the rest.
+ EXPECT_FALSE(file_util::PathExists(dir_to_create_1));
+}
diff --git a/chrome/installer/util/create_reg_key_work_item.cc b/chrome/installer/util/create_reg_key_work_item.cc
new file mode 100644
index 0000000..719a4207a
--- /dev/null
+++ b/chrome/installer/util/create_reg_key_work_item.cc
@@ -0,0 +1,131 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "shlwapi.h"
+
+#include "base/file_util.h"
+#include "base/registry.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/logging_installer.h"
+
+CreateRegKeyWorkItem::~CreateRegKeyWorkItem() {
+}
+
+CreateRegKeyWorkItem::CreateRegKeyWorkItem(HKEY predefined_root,
+ std::wstring path)
+ : predefined_root_(predefined_root),
+ path_(path),
+ key_created_(false) {
+}
+
+bool CreateRegKeyWorkItem::Do() {
+ if(!InitKeyList()) {
+ // Nothing needs to be done here.
+ LOG(INFO) << "no key to create";
+ return true;
+ }
+
+ RegKey key;
+ std::wstring key_path;
+
+ // To create keys, we iterate from back to front.
+ for (size_t i = key_list_.size(); i > 0; i--) {
+ DWORD disposition;
+ key_path.assign(key_list_[i - 1]);
+
+ if(key.CreateWithDisposition(predefined_root_, key_path.c_str(),
+ &disposition)) {
+ if (disposition == REG_OPENED_EXISTING_KEY) {
+ if (key_created_) {
+ // This should not happen. Someone created a subkey under the key
+ // we just created?
+ LOG(ERROR) << key_path << " exists, this is not expected.";
+ return false;
+ }
+ LOG(INFO) << key_path << " exists";
+ // Remove the key path from list if it is already present.
+ key_list_.pop_back();
+ } else if (disposition == REG_CREATED_NEW_KEY){
+ LOG(INFO) << "created " << key_path;
+ key_created_ = true;
+ } else {
+ LOG(ERROR) << "unkown disposition";
+ return false;
+ }
+ } else {
+ LOG(ERROR) << "fail to create " << key_path << " and the error is: "
+ << InstallUtil::FormatLastWin32Error();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CreateRegKeyWorkItem::Rollback() {
+ if (!key_created_)
+ return;
+
+ std::wstring key_path;
+ // To delete keys, we iterate from front to back.
+ std::vector<std::wstring>::iterator itr;
+ for (itr = key_list_.begin(); itr != key_list_.end(); ++itr) {
+ key_path.assign(*itr);
+ if (SHDeleteEmptyKey(predefined_root_, key_path.c_str()) ==
+ ERROR_SUCCESS) {
+ LOG(INFO) << "rollback: delete " << key_path;
+ } else {
+ LOG(INFO) << "rollback: can not delete " << key_path;
+ // The key might have been deleted, but we don't reliably know what
+ // error code(s) are returned in this case. So we just keep tring delete
+ // the rest.
+ }
+ }
+
+ key_created_ = false;
+ key_list_.clear();
+ return;
+}
+
+bool CreateRegKeyWorkItem::InitKeyList() {
+ if (path_.empty())
+ return false;
+
+ std::wstring key_path(path_);
+
+ do {
+ key_list_.push_back(key_path);
+ // This is pure string operation so it does not matter whether the
+ // path is file path or registry path.
+ file_util::UpOneDirectoryOrEmpty(&key_path);
+ } while(!key_path.empty());
+
+ return true;
+}
diff --git a/chrome/installer/util/create_reg_key_work_item.h b/chrome/installer/util/create_reg_key_work_item.h
new file mode 100644
index 0000000..ce2b272
--- /dev/null
+++ b/chrome/installer/util/create_reg_key_work_item.h
@@ -0,0 +1,74 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_CREATE_REG_KEY_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_CREATE_REG_KEY_WORK_ITEM_H__
+
+#include <string>
+#include <vector>
+
+#include <windows.h>
+
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that creates a registry key at the given path.
+// It also creates all necessary intermediate keys if they do not exist.
+class CreateRegKeyWorkItem : public WorkItem {
+ public:
+ virtual ~CreateRegKeyWorkItem();
+
+ virtual bool Do();
+
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ CreateRegKeyWorkItem(HKEY predefined_root, std::wstring path);
+
+ // Initialize key_list_ by adding all paths of keys from predefined_root_
+ // to path_. Returns true if key_list_ is non empty.
+ bool InitKeyList();
+
+ // Root key under which we create the new key. The root key can only be
+ // one of the predefined keys on Windows.
+ HKEY predefined_root_;
+
+ // Path of the key to be created.
+ std::wstring path_;
+
+ // List of paths to all keys that need to be created from predefined_root_
+ // to path_.
+ std::vector<std::wstring> key_list_;
+
+ // Whether any key has been created.
+ bool key_created_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_CREATE_REG_KEY_WORK_ITEM_H__
diff --git a/chrome/installer/util/create_reg_key_work_item_unittest.cc b/chrome/installer/util/create_reg_key_work_item_unittest.cc
new file mode 100644
index 0000000..e694491
--- /dev/null
+++ b/chrome/installer/util/create_reg_key_work_item_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ wchar_t test_root[] = L"TmpTmp";
+ class CreateRegKeyWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create a temporary key for testing
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ key.DeleteKey(test_root);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, test_root, KEY_READ));
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, test_root, KEY_READ));
+
+ // Create a log file
+ std::wstring log_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileName(&log_file));
+ ASSERT_TRUE(file_util::PathExists(log_file));
+
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ logging::SetMinLogLevel(logging::LOG_INFO);
+ }
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up the temporary key
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ ASSERT_TRUE(key.DeleteKey(test_root));
+ }
+ };
+};
+
+TEST_F(CreateRegKeyWorkItemTest, CreateKey) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"a");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(), KEY_READ));
+
+ std::wstring top_key_to_create(parent_key);
+ file_util::AppendToPath(&top_key_to_create, L"b");
+
+ std::wstring key_to_create(top_key_to_create);
+ file_util::AppendToPath(&key_to_create, L"c");
+ file_util::AppendToPath(&key_to_create, L"d");
+
+ scoped_ptr<CreateRegKeyWorkItem> work_item(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER, key_to_create));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+
+ work_item->Rollback();
+
+ // Rollback should delete all the keys up to top_key_to_create.
+ EXPECT_FALSE(key.Open(HKEY_CURRENT_USER, top_key_to_create.c_str(),
+ KEY_READ));
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, parent_key.c_str(), KEY_READ));
+}
+
+TEST_F(CreateRegKeyWorkItemTest, CreateExistingKey) {
+ RegKey key;
+
+ std::wstring key_to_create(test_root);
+ file_util::AppendToPath(&key_to_create, L"aa");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+
+ scoped_ptr<CreateRegKeyWorkItem> work_item(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER, key_to_create));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+
+ work_item->Rollback();
+
+ // Rollback should not remove the key since it exists before
+ // the CreateRegKeyWorkItem is called.
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+}
+
+TEST_F(CreateRegKeyWorkItemTest, CreateSharedKey) {
+ RegKey key;
+ std::wstring key_to_create_1(test_root);
+ file_util::AppendToPath(&key_to_create_1, L"aaa");
+
+ std::wstring key_to_create_2(key_to_create_1);
+ file_util::AppendToPath(&key_to_create_2, L"bbb");
+
+ std::wstring key_to_create_3(key_to_create_2);
+ file_util::AppendToPath(&key_to_create_3, L"ccc");
+
+ scoped_ptr<CreateRegKeyWorkItem> work_item(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER,
+ key_to_create_3));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create_3.c_str(), KEY_READ));
+
+ // Create another key under key_to_create_2
+ std::wstring key_to_create_4(key_to_create_2);
+ file_util::AppendToPath(&key_to_create_4, L"ddd");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, key_to_create_4.c_str(),
+ KEY_READ));
+
+ work_item->Rollback();
+
+ // Rollback should delete key_to_create_3.
+ EXPECT_FALSE(key.Open(HKEY_CURRENT_USER, key_to_create_3.c_str(), KEY_READ));
+
+ // Rollback should not delete key_to_create_2 as it is shared.
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create_2.c_str(), KEY_READ));
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create_4.c_str(), KEY_READ));
+}
+
+TEST_F(CreateRegKeyWorkItemTest, RollbackWithMissingKey) {
+ RegKey key;
+ std::wstring key_to_create_1(test_root);
+ file_util::AppendToPath(&key_to_create_1, L"aaaa");
+
+ std::wstring key_to_create_2(key_to_create_1);
+ file_util::AppendToPath(&key_to_create_2, L"bbbb");
+
+ std::wstring key_to_create_3(key_to_create_2);
+ file_util::AppendToPath(&key_to_create_3, L"cccc");
+
+ scoped_ptr<CreateRegKeyWorkItem> work_item(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER,
+ key_to_create_3));
+
+ EXPECT_TRUE(work_item->Do());
+
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create_3.c_str(), KEY_READ));
+ key.Close();
+
+ // now delete key_to_create_3
+ ASSERT_TRUE(RegDeleteKey(HKEY_CURRENT_USER, key_to_create_3.c_str()) ==
+ ERROR_SUCCESS);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, key_to_create_3.c_str(),
+ KEY_READ));
+
+ work_item->Rollback();
+
+ // key_to_create_3 has already been deleted, Rollback should delete
+ // the rest.
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, key_to_create_1.c_str(),
+ KEY_READ));
+}
+
+TEST_F(CreateRegKeyWorkItemTest, RollbackWithSetValue) {
+ RegKey key;
+
+ std::wstring key_to_create(test_root);
+ file_util::AppendToPath(&key_to_create, L"aaaaa");
+
+ scoped_ptr<CreateRegKeyWorkItem> work_item(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER, key_to_create));
+
+ EXPECT_TRUE(work_item->Do());
+
+ // Write a value under the key we just created.
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(),
+ KEY_READ | KEY_SET_VALUE));
+ EXPECT_TRUE(key.WriteValue(L"name", L"value"));
+ key.Close();
+
+ work_item->Rollback();
+
+ // Rollback should not remove the key.
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+}
diff --git a/chrome/installer/util/delete_tree_work_item.cc b/chrome/installer/util/delete_tree_work_item.cc
new file mode 100644
index 0000000..8a96915
--- /dev/null
+++ b/chrome/installer/util/delete_tree_work_item.cc
@@ -0,0 +1,97 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+
+DeleteTreeWorkItem::~DeleteTreeWorkItem() {
+ std::wstring tmp_dir = file_util::GetDirectoryFromPath(backup_path_);
+ if (file_util::PathExists(tmp_dir)) {
+ file_util::Delete(tmp_dir, true);
+ }
+ tmp_dir = file_util::GetDirectoryFromPath(key_backup_path_);
+ if (file_util::PathExists(tmp_dir)) {
+ file_util::Delete(tmp_dir, true);
+ }
+}
+
+DeleteTreeWorkItem::DeleteTreeWorkItem(std::wstring root_path,
+ std::wstring key_path)
+ : root_path_(root_path),
+ key_path_(key_path) {
+}
+
+// We first try to move key_path_ to backup_path. If it succeeds, we go ahead
+// and move the rest.
+bool DeleteTreeWorkItem::Do() {
+ if (!key_path_.empty() && file_util::PathExists(key_path_)) {
+ if (!GetBackupPath(key_path_, &key_backup_path_) ||
+ !file_util::CopyDirectory(key_path_, key_backup_path_, true) ||
+ !file_util::Delete(key_path_, true)) {
+ LOG(ERROR) << "can not delete " << key_path_
+ << " OR copy it to backup path " << key_backup_path_;
+ return false;
+ }
+ }
+
+ if (!root_path_.empty() && file_util::PathExists(root_path_)) {
+ if (!GetBackupPath(root_path_, &backup_path_) ||
+ !file_util::CopyDirectory(root_path_, backup_path_, true) ||
+ !file_util::Delete(root_path_, true)) {
+ LOG(ERROR) << "can not delete " << root_path_
+ << " OR copy it to backup path " << backup_path_;
+ return false;
+ }
+ }
+ return true;
+}
+
+// If there are files in backup paths move them back.
+void DeleteTreeWorkItem::Rollback() {
+ if (!backup_path_.empty() && file_util::PathExists(backup_path_)) {
+ file_util::Move(backup_path_, root_path_);
+ }
+ if (!key_backup_path_.empty() && file_util::PathExists(key_backup_path_)) {
+ file_util::Move(key_backup_path_, key_path_);
+ }
+}
+
+bool DeleteTreeWorkItem::GetBackupPath(std::wstring for_path,
+ std::wstring* backup_path) {
+ if (!file_util::CreateNewTempDirectory(L"", backup_path)) {
+ // We assume that CreateNewTempDirectory() is doing its job well.
+ LOG(ERROR) << "Couldn't get backup path for delete.";
+ return false;
+ }
+ std::wstring file_name = file_util::GetFilenameFromPath(for_path);
+ file_util::AppendToPath(backup_path, file_name);
+
+ return true;
+}
diff --git a/chrome/installer/util/delete_tree_work_item.h b/chrome/installer/util/delete_tree_work_item.h
new file mode 100644
index 0000000..e480eec
--- /dev/null
+++ b/chrome/installer/util/delete_tree_work_item.h
@@ -0,0 +1,74 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H__
+
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that recursively deletes a file system hierarchy at the
+// given root path. The file system hierarchy could be a single file, or a
+// directory.
+// The file system hierarchy to be deleted can have a key file. If the key file
+// is specified, deletion will be performed only if the key file is not in use.
+class DeleteTreeWorkItem : public WorkItem {
+ public:
+ virtual ~DeleteTreeWorkItem();
+
+ virtual bool Do();
+
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ // Get a backup path that can keep root_path_ or key_path_
+ bool GetBackupPath(std::wstring for_path, std::wstring* backup_path);
+
+ DeleteTreeWorkItem(std::wstring root_path, std::wstring key_path);
+
+ // Root path to delete.
+ std::wstring root_path_;
+
+ // Path to the key file. If the key file is specified, deletion will be
+ // performed only if the key file is not in use.
+ std::wstring key_path_;
+
+ // The full path in temporary directory that the original root_path_ has
+ // been moved to.
+ std::wstring backup_path_;
+
+ // The full path in temporary directory that the original key_path_ has
+ // been moved to.
+ std::wstring key_backup_path_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H__
diff --git a/chrome/installer/util/delete_tree_work_item_unittest.cc b/chrome/installer/util/delete_tree_work_item_unittest.cc
new file mode 100644
index 0000000..a055846
--- /dev/null
+++ b/chrome/installer/util/delete_tree_work_item_unittest.cc
@@ -0,0 +1,243 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ class DeleteTreeWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Name a subdirectory of the user temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"DeleteTreeWorkItemTest");
+
+ // Create a fresh, empty copy of this test directory.
+ file_util::Delete(test_dir_, true);
+ CreateDirectory(test_dir_.c_str(), NULL);
+
+ ASSERT_TRUE(file_util::PathExists(test_dir_));
+ }
+
+ virtual void TearDown() {
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, false));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ // the path to temporary directory used to contain the test operations
+ std::wstring test_dir_;
+ };
+
+ // Simple function to dump some text into a new file.
+ void CreateTextFile(const std::wstring& filename,
+ const std::wstring& contents) {
+ std::ofstream file;
+ file.open(filename.c_str());
+ ASSERT_TRUE(file.is_open());
+ file << contents;
+ file.close();
+ }
+
+ wchar_t text_content_1[] = L"delete me";
+ wchar_t text_content_2[] = L"delete me as well";
+};
+
+// Delete a tree without key path. Everything should be deleted.
+TEST_F(DeleteTreeWorkItemTest, DeleteTreeNoKeyPath) {
+ // Create tree to be deleted
+ std::wstring dir_name_delete(test_dir_);
+ file_util::AppendToPath(&dir_name_delete, L"to_be_delete");
+ CreateDirectory(dir_name_delete.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete));
+
+ std::wstring dir_name_delete_1(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_1, L"1");
+ CreateDirectory(dir_name_delete_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_1));
+
+ std::wstring dir_name_delete_2(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_2, L"2");
+ CreateDirectory(dir_name_delete_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_2));
+
+ std::wstring file_name_delete_1(dir_name_delete_1);
+ file_util::AppendToPath(&file_name_delete_1, L"File_1.txt");
+ CreateTextFile(file_name_delete_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_1));
+
+ std::wstring file_name_delete_2(dir_name_delete_2);
+ file_util::AppendToPath(&file_name_delete_2, L"File_2.txt");
+ CreateTextFile(file_name_delete_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_2));
+
+ // test Do()
+ scoped_ptr<DeleteTreeWorkItem> work_item(
+ WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, std::wstring()));
+ EXPECT_TRUE(work_item->Do());
+
+ // everything should be gone
+ EXPECT_FALSE(file_util::PathExists(file_name_delete_1));
+ EXPECT_FALSE(file_util::PathExists(file_name_delete_2));
+ EXPECT_FALSE(file_util::PathExists(dir_name_delete));
+
+ work_item->Rollback();
+ // everything should come back
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_1));
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_2));
+ EXPECT_TRUE(file_util::PathExists(dir_name_delete));
+}
+
+
+// Delete a tree with keypath but not in use. Everything should be gone.
+// Rollback should bring back everything
+TEST_F(DeleteTreeWorkItemTest, DeleteTree) {
+ // Create tree to be deleted
+ std::wstring dir_name_delete(test_dir_);
+ file_util::AppendToPath(&dir_name_delete, L"to_be_delete");
+ CreateDirectory(dir_name_delete.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete));
+
+ std::wstring dir_name_delete_1(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_1, L"1");
+ CreateDirectory(dir_name_delete_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_1));
+
+ std::wstring dir_name_delete_2(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_2, L"2");
+ CreateDirectory(dir_name_delete_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_2));
+
+ std::wstring file_name_delete_1(dir_name_delete_1);
+ file_util::AppendToPath(&file_name_delete_1, L"File_1.txt");
+ CreateTextFile(file_name_delete_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_1));
+
+ std::wstring file_name_delete_2(dir_name_delete_2);
+ file_util::AppendToPath(&file_name_delete_2, L"File_2.txt");
+ CreateTextFile(file_name_delete_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_2));
+
+ // test Do()
+ scoped_ptr<DeleteTreeWorkItem> work_item(
+ WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, file_name_delete_1));
+ EXPECT_TRUE(work_item->Do());
+
+ // everything should be gone
+ EXPECT_FALSE(file_util::PathExists(file_name_delete_1));
+ EXPECT_FALSE(file_util::PathExists(file_name_delete_2));
+ EXPECT_FALSE(file_util::PathExists(dir_name_delete));
+
+ work_item->Rollback();
+ // everything should come back
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_1));
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_2));
+ EXPECT_TRUE(file_util::PathExists(dir_name_delete));
+}
+
+// Delete a tree with key_path in use. Everything should still be there.
+TEST_F(DeleteTreeWorkItemTest, DeleteTreeInUse) {
+ // Create tree to be deleted
+ std::wstring dir_name_delete(test_dir_);
+ file_util::AppendToPath(&dir_name_delete, L"to_be_delete");
+ CreateDirectory(dir_name_delete.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete));
+
+ std::wstring dir_name_delete_1(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_1, L"1");
+ CreateDirectory(dir_name_delete_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_1));
+
+ std::wstring dir_name_delete_2(dir_name_delete);
+ file_util::AppendToPath(&dir_name_delete_2, L"2");
+ CreateDirectory(dir_name_delete_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(dir_name_delete_2));
+
+ std::wstring file_name_delete_1(dir_name_delete_1);
+ file_util::AppendToPath(&file_name_delete_1, L"File_1.txt");
+ CreateTextFile(file_name_delete_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_1));
+
+ std::wstring file_name_delete_2(dir_name_delete_2);
+ file_util::AppendToPath(&file_name_delete_2, L"File_2.txt");
+ CreateTextFile(file_name_delete_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(file_name_delete_2));
+
+ // Create a key path file.
+ std::wstring key_path(dir_name_delete);
+ file_util::AppendToPath(&key_path, L"key_file.exe");
+
+ wchar_t exe_full_path_str[MAX_PATH];
+ ::GetModuleFileNameW(NULL, exe_full_path_str, MAX_PATH);
+ std::wstring exe_full_path(exe_full_path_str);
+
+ file_util::CopyFile(exe_full_path, key_path);
+ ASSERT_TRUE(file_util::PathExists(key_path));
+
+ LOG(INFO) << "copy ourself from " << exe_full_path << " to " << key_path;
+
+ // Run the key path file to keep it in use.
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ ASSERT_TRUE(
+ ::CreateProcessW(NULL, const_cast<wchar_t*>(key_path.c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi));
+
+ // test Do().
+ {
+ scoped_ptr<DeleteTreeWorkItem> work_item(
+ WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, key_path));
+
+ // delete should fail as file in use.
+ EXPECT_FALSE(work_item->Do());
+ }
+
+ // verify everything is still there.
+ EXPECT_TRUE(file_util::PathExists(key_path));
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_1));
+ EXPECT_TRUE(file_util::PathExists(file_name_delete_2));
+
+ TerminateProcess(pi.hProcess, 0);
+ // make sure the handle is closed.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+}
diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc
new file mode 100644
index 0000000..8d89aa7
--- /dev/null
+++ b/chrome/installer/util/google_update_constants.cc
@@ -0,0 +1,43 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/util/google_update_constants.h"
+
+namespace google_update {
+
+const wchar_t kChromeGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
+const wchar_t kGearsUpgradeCode[] = L"{D92DBAED-3E3E-4530-B30D-072D16C7DDD0}";
+const wchar_t kRegPathClients[] = L"Software\\Google\\Update\\Clients";
+const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
+const wchar_t kRegApFieldName[] = L"ap";
+const wchar_t kRegNameField[] = L"name";
+const wchar_t kRegVersionField[] = L"pv";
+const wchar_t kRegLastCheckedField[] = L"LastChecked";
+
+} // namespace installer
diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h
new file mode 100644
index 0000000..984749f
--- /dev/null
+++ b/chrome/installer/util/google_update_constants.h
@@ -0,0 +1,52 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines all the command-line switches used with Google Update.
+
+#ifndef CHROME_INSTALLER_UTIL_GOOGLE_UPDATE_CONSTANTS_H__
+#define CHROME_INSTALLER_UTIL_GOOGLE_UPDATE_CONSTANTS_H__
+
+namespace google_update {
+
+extern const wchar_t kChromeGuid[];
+
+// Strictly speaking Google Update doesn't care about this GUID but it is still
+// related to install as it is used by MSI to identify Gears.
+extern const wchar_t kGearsUpgradeCode[];
+
+extern const wchar_t kRegPathClients[];
+extern const wchar_t kRegPathClientState[];
+extern const wchar_t kRegApFieldName[];
+extern const wchar_t kRegNameField[];
+extern const wchar_t kRegVersionField[];
+extern const wchar_t kRegLastCheckedField[];
+
+} // namespace google_update
+
+#endif // CHROME_INSTALLER_UTIL_GOOGLE_UPDATE_CONSTANTS_H__
diff --git a/chrome/installer/util/helper.cc b/chrome/installer/util/helper.cc
new file mode 100644
index 0000000..271fdb2
--- /dev/null
+++ b/chrome/installer/util/helper.cc
@@ -0,0 +1,147 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/scoped_ptr.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+#include "chrome/installer/util/work_item_list.h"
+
+std::wstring installer::GetChromeInstallPath(bool system_install) {
+ std::wstring install_path;
+ if (system_install) {
+ PathService::Get(base::DIR_PROGRAM_FILES, &install_path);
+ } else {
+ PathService::Get(base::DIR_LOCAL_APP_DATA, &install_path);
+ }
+
+ if (!install_path.empty()) {
+ file_util::AppendToPath(&install_path,
+ std::wstring(installer_util::kInstallGoogleDir));
+ file_util::AppendToPath(&install_path,
+ std::wstring(installer_util::kChrome));
+ file_util::AppendToPath(&install_path,
+ std::wstring(installer_util::kInstallBinaryDir));
+ }
+
+ return install_path;
+}
+
+bool installer::LaunchChrome(bool system_install) {
+ std::wstring chrome_exe(L"\"");
+ chrome_exe.append(installer::GetChromeInstallPath(system_install));
+ file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ chrome_exe.append(L"\"");
+ return process_util::LaunchApp(chrome_exe, false, false, NULL);
+}
+
+bool installer::LaunchChromeAndWaitForResult(bool system_install,
+ const std::wstring& options,
+ int32 timeout_ms,
+ int32* exit_code,
+ bool* is_timeout) {
+ std::wstring chrome_exe(installer::GetChromeInstallPath(system_install));
+ if (chrome_exe.empty())
+ return false;
+ file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+
+ std::wstring command_line(chrome_exe);
+ command_line.append(options);
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ if (!::CreateProcessW(chrome_exe.c_str(),
+ const_cast<wchar_t*>(command_line.c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL,
+ &si, &pi)) {
+ return false;
+ }
+
+ DWORD wr = ::WaitForSingleObject(pi.hProcess, timeout_ms);
+ if (WAIT_TIMEOUT == wr) {
+ if (is_timeout)
+ *is_timeout = true;
+ } else { // WAIT_OBJECT_0
+ if (is_timeout)
+ *is_timeout = false;
+ if (exit_code) {
+ ::GetExitCodeProcess(pi.hProcess, reinterpret_cast<DWORD*>(exit_code));
+ }
+ }
+
+ ::CloseHandle(pi.hProcess);
+ ::CloseHandle(pi.hThread);
+ return true;
+}
+
+void installer::RemoveOldVersionDirs(const std::wstring& chrome_path,
+ const std::wstring& latest_version_str) {
+ std::wstring search_path(chrome_path);
+ file_util::AppendToPath(&search_path, L"*");
+
+ WIN32_FIND_DATA find_file_data;
+ HANDLE file_handle = FindFirstFile(search_path.c_str(), &find_file_data);
+ if (file_handle == INVALID_HANDLE_VALUE)
+ return;
+
+ BOOL ret = TRUE;
+ scoped_ptr<installer::Version> version;
+ scoped_ptr<installer::Version> latest_version(
+ installer::Version::GetVersionFromString(latest_version_str));
+
+ // We try to delete all directories whose versions are lower than
+ // latest_version.
+ while (ret) {
+ if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ LOG(INFO) << "directory found: " << find_file_data.cFileName;
+ version.reset(
+ installer::Version::GetVersionFromString(find_file_data.cFileName));
+ if (version.get() && latest_version->IsHigherThan(version.get())) {
+ std::wstring remove_dir(chrome_path);
+ file_util::AppendToPath(&remove_dir, find_file_data.cFileName);
+ std::wstring chrome_dll_path(remove_dir);
+ file_util::AppendToPath(&chrome_dll_path, installer_util::kChromeDll);
+ LOG(INFO) << "deleting directory " << remove_dir;
+ scoped_ptr<DeleteTreeWorkItem> item;
+ item.reset(WorkItem::CreateDeleteTreeWorkItem(remove_dir,
+ chrome_dll_path));
+ item->Do();
+ }
+ }
+ ret = FindNextFile(file_handle, &find_file_data);
+ }
+
+ FindClose(file_handle);
+}
diff --git a/chrome/installer/util/helper.h b/chrome/installer/util/helper.h
new file mode 100644
index 0000000..68e5115
--- /dev/null
+++ b/chrome/installer/util/helper.h
@@ -0,0 +1,72 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file contains helper functions used by setup.
+
+#ifndef CHROME_INSTALLER_UTIL_HELPER_H__
+#define CHROME_INSTALLER_UTIL_HELPER_H__
+
+#include <string>
+
+namespace installer {
+
+// This function returns the install path for Chrome depending on whether its
+// system wide install or user specific install.
+// system_install: if true, the function returns system wide location
+// (ProgramFiles\Google). Otherwise it returns user specific
+// location (Document And Settings\<user>\Local Settings...)
+std::wstring GetChromeInstallPath(bool system_install);
+
+// Launches Chrome without waiting for its exit.
+bool LaunchChrome(bool system_install);
+
+// Launches Chrome with given command line, waits for Chrome to terminate
+// within timeout_ms, and gets the process exit code if available.
+// The function returns true as long as Chrome is successfully launched.
+// The status of Chrome at the return of the function is given by exit_code
+// and is_timeout.
+bool LaunchChromeAndWaitForResult(bool system_install,
+ const std::wstring& options,
+ int32 timeout_ms,
+ int32* exit_code,
+ bool* is_timeout);
+
+// This function tries to remove all previous version directories after a new
+// Chrome update. If an instance of Chrome with older version is still running
+// on the system, its corresponding version directory will be left intact.
+// (The version directory is subject for removal again during next update.)
+//
+// chrome_path: the root path of Chrome installation.
+// latest_version_str: the latest version of Chrome installed.
+void RemoveOldVersionDirs(const std::wstring& chrome_path,
+ const std::wstring& latest_version_str);
+
+} // namespace installer
+
+#endif
diff --git a/chrome/installer/util/helper_unittest.cc b/chrome/installer/util/helper_unittest.cc
new file mode 100644
index 0000000..be6b183
--- /dev/null
+++ b/chrome/installer/util/helper_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ class SetupHelperTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Name a subdirectory of the user temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"SetupHelperTest");
+
+ // Create a fresh, empty copy of this test directory.
+ file_util::Delete(test_dir_, true);
+ CreateDirectory(test_dir_.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(test_dir_));
+
+ // Create a log file
+ std::wstring log_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileName(&log_file));
+ ASSERT_TRUE(file_util::PathExists(log_file));
+
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ logging::SetMinLogLevel(logging::LOG_INFO);
+ }
+
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, false));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ // the path to temporary directory used to contain the test operations
+ std::wstring test_dir_;
+ };
+
+ // Simple function to dump some text into a new file.
+ void CreateTextFile(const std::wstring& filename,
+ const std::wstring& contents) {
+ std::ofstream file;
+ file.open(filename.c_str());
+ ASSERT_TRUE(file.is_open());
+ file << contents;
+ file.close();
+ }
+
+ wchar_t text_content_1[] = L"delete me";
+ wchar_t text_content_2[] = L"delete me as well";
+};
+
+// Delete version directories. Everything lower than the given version
+// should be deleted.
+TEST_F(SetupHelperTest, Delete) {
+ // Create a Chrome dir
+ std::wstring chrome_dir(test_dir_);
+ file_util::AppendToPath(&chrome_dir, L"chrome");
+ CreateDirectory(chrome_dir.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir));
+
+ std::wstring chrome_dir_1(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_1, L"1.0.1.0");
+ CreateDirectory(chrome_dir_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
+
+ std::wstring chrome_dir_2(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_2, L"1.0.2.0");
+ CreateDirectory(chrome_dir_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
+
+ std::wstring chrome_dir_3(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_3, L"1.0.3.0");
+ CreateDirectory(chrome_dir_3.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
+
+ std::wstring chrome_dir_4(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_4, L"1.0.4.0");
+ CreateDirectory(chrome_dir_4.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
+
+ std::wstring chrome_dll_1(chrome_dir_1);
+ file_util::AppendToPath(&chrome_dll_1, L"chrome.dll");
+ CreateTextFile(chrome_dll_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
+
+ std::wstring chrome_dll_2(chrome_dir_2);
+ file_util::AppendToPath(&chrome_dll_2, L"chrome.dll");
+ CreateTextFile(chrome_dll_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
+
+ std::wstring chrome_dll_3(chrome_dir_3);
+ file_util::AppendToPath(&chrome_dll_3, L"chrome.dll");
+ CreateTextFile(chrome_dll_3, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
+
+ std::wstring chrome_dll_4(chrome_dir_4);
+ file_util::AppendToPath(&chrome_dll_4, L"chrome.dll");
+ CreateTextFile(chrome_dll_4, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
+
+ std::wstring latest_version(L"1.0.4.0");
+ installer::RemoveOldVersionDirs(chrome_dir, latest_version);
+
+ // old versions should be gone
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_2));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
+ // the latest version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
+}
+
+// Delete older version directories, keeping the one in used intact.
+TEST_F(SetupHelperTest, DeleteInUsed) {
+ // Create a Chrome dir
+ std::wstring chrome_dir(test_dir_);
+ file_util::AppendToPath(&chrome_dir, L"chrome");
+ CreateDirectory(chrome_dir.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir));
+
+ std::wstring chrome_dir_1(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_1, L"1.0.1.0");
+ CreateDirectory(chrome_dir_1.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
+
+ std::wstring chrome_dir_2(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_2, L"1.0.2.0");
+ CreateDirectory(chrome_dir_2.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
+
+ std::wstring chrome_dir_3(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_3, L"1.0.3.0");
+ CreateDirectory(chrome_dir_3.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
+
+ std::wstring chrome_dir_4(chrome_dir);
+ file_util::AppendToPath(&chrome_dir_4, L"1.0.4.0");
+ CreateDirectory(chrome_dir_4.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
+
+ std::wstring chrome_dll_1(chrome_dir_1);
+ file_util::AppendToPath(&chrome_dll_1, L"chrome.dll");
+ CreateTextFile(chrome_dll_1, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
+
+ std::wstring chrome_dll_2(chrome_dir_2);
+ file_util::AppendToPath(&chrome_dll_2, L"chrome.dll");
+ CreateTextFile(chrome_dll_2, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
+
+ // Open the file to make it in use.
+ std::ofstream file;
+ file.open(chrome_dll_2.c_str());
+
+ std::wstring chrome_othera_2(chrome_dir_2);
+ file_util::AppendToPath(&chrome_othera_2, L"othera.dll");
+ CreateTextFile(chrome_othera_2, text_content_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_othera_2));
+
+ std::wstring chrome_otherb_2(chrome_dir_2);
+ file_util::AppendToPath(&chrome_otherb_2, L"otherb.dll");
+ CreateTextFile(chrome_otherb_2, text_content_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_otherb_2));
+
+ std::wstring chrome_dll_3(chrome_dir_3);
+ file_util::AppendToPath(&chrome_dll_3, L"chrome.dll");
+ CreateTextFile(chrome_dll_3, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
+
+ std::wstring chrome_dll_4(chrome_dir_4);
+ file_util::AppendToPath(&chrome_dll_4, L"chrome.dll");
+ CreateTextFile(chrome_dll_4, text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
+
+ std::wstring latest_version(L"1.0.4.0");
+ installer::RemoveOldVersionDirs(chrome_dir, latest_version);
+
+ // old versions not in used should be gone
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
+ // every thing under in used version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dir_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_othera_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_otherb_2));
+ // the latest version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
+}
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
new file mode 100644
index 0000000..6424bd6
--- /dev/null
+++ b/chrome/installer/util/install_util.cc
@@ -0,0 +1,120 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// See the corresponding header file for description of the functions in this
+// file.
+
+#include "install_util.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/registry.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/google_update_constants.h"
+
+
+std::wstring InstallUtil::FormatLastWin32Error() {
+ unsigned messageid = GetLastError();
+ wchar_t* string_buffer = NULL;
+ unsigned string_length = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, messageid, 0, reinterpret_cast<wchar_t *>(&string_buffer), 0, NULL);
+
+ std::wstring formatted_string;
+ if (string_buffer) {
+ formatted_string = string_buffer;
+ LocalFree(reinterpret_cast<HLOCAL>(string_buffer));
+ } else {
+ // The formating failed. simply convert the message value into a string.
+ SStringPrintf(&formatted_string, L"message number %d", messageid);
+ }
+ return formatted_string;
+}
+
+
+std::wstring InstallUtil::GetChromeGoogleUpdateKey() {
+ std::wstring chrome_google_update_key(google_update::kRegPathClients);
+ chrome_google_update_key.append(L"\\");
+ chrome_google_update_key.append(google_update::kChromeGuid);
+ return chrome_google_update_key;
+}
+
+installer::Version* InstallUtil::GetChromeVersion(bool system_install) {
+ RegKey key;
+ std::wstring version_str;
+
+ HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ if (!key.Open(reg_root, GetChromeGoogleUpdateKey().c_str(), KEY_READ) ||
+ !key.ReadValue(google_update::kRegVersionField, &version_str)) {
+ LOG(INFO) << "No existing Chrome install found.";
+ key.Close();
+ return NULL;
+ }
+ key.Close();
+ LOG(INFO) << "Existing Chrome version found " << version_str;
+ return installer::Version::GetVersionFromString(version_str);
+}
+
+std::wstring InstallUtil::GetNewGoogleUpdateApKey(bool diff_install,
+ installer_util::InstallStatus status, const std::wstring& value) {
+ // Magic suffix that we need to add or remove to "ap" key value.
+ const std::wstring kMagicSuffix = L"-full";
+
+ bool has_magic_string = false;
+ if ((value.length() >= kMagicSuffix.length()) &&
+ (value.rfind(kMagicSuffix) == (value.length() - kMagicSuffix.length()))) {
+ LOG(INFO) << "Incremental installer failure key already set.";
+ has_magic_string = true;
+ }
+
+ std::wstring new_value(value);
+ if ((!diff_install || InstallSuccessful(status)) && has_magic_string) {
+ LOG(INFO) << "Removing failure key from value " << value;
+ new_value = value.substr(0, value.length() - kMagicSuffix.length());
+ } else if ((diff_install && !InstallSuccessful(status)) &&
+ !has_magic_string) {
+ LOG(INFO) << "Incremental installer failed, setting failure key.";
+ new_value.append(kMagicSuffix);
+ }
+
+ return new_value;
+}
+
+bool InstallUtil::InstallSuccessful(installer_util::InstallStatus status) {
+ switch (status) {
+ case installer_util::FIRST_INSTALL_SUCCESS:
+ case installer_util::INSTALL_REPAIRED:
+ case installer_util::NEW_VERSION_UPDATED:
+ case installer_util::HIGHER_VERSION_EXISTS:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
new file mode 100644
index 0000000..8ef79bf
--- /dev/null
+++ b/chrome/installer/util/install_util.h
@@ -0,0 +1,89 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file declares utility functions for the installer. The original reason
+// for putting these functions in installer\util library is so that we can
+// separate out the critical logic and write unit tests for it.
+
+#ifndef CHROME_INSTALLER_UTIL_INSTALL_UTIL_H__
+#define CHROME_INSTALLER_UTIL_INSTALL_UTIL_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+
+// This is a utility class that provides common installation related
+// utility methods that can be used by installer and also unit tested
+// independently.
+class InstallUtil {
+ public:
+ // Gets the last Win32 error and generates a human readable message string.
+ // Uses the Win32 API GetLastError() to get the last error and API
+ // FormatMessage() to generate a string. This function has been copied
+ // from chrome\common\win_util.{h.cc} to avoid making setup.exe dependent
+ // on all the other libs (base_gfx, libjpeg, libpng and others) that we
+ // need to pull in and the size of setup.exe goes up by ~140KB.
+ static std::wstring FormatLastWin32Error();
+
+ // This method gets the Google Update registry key path for Chrome.
+ // i.e. - Software\Google\Update\Clients\<chrome-guid>";
+ static std::wstring GetChromeGoogleUpdateKey();
+
+ // Find the version of Chrome installed on the system by checking the
+ // Google Update registry key. Returns the version or NULL if no version is
+ // found.
+ // system_install: if true, looks for version number under the HKLM root,
+ // otherwise looks under the HKCU.
+ static installer::Version * GetChromeVersion(bool system_install);
+
+ // This method generates the new value for Oamaha "ap" key for Chrome
+ // based on whether we are doing incremental install (or not) and whether
+ // the install succeeded.
+ // - If install worked, remove the magic string (if present).
+ // - If incremental installer failed, append a magic string (if
+ // not present already).
+ // - If full installer failed, still remove this magic
+ // string (if it is present already).
+ //
+ // diff_install: tells whether this is incremental install or not.
+ // install_status: if 0, means installation was successful.
+ // value: current value of Google Update "ap" key.
+ static std::wstring GetNewGoogleUpdateApKey(bool diff_install,
+ installer_util::InstallStatus status, const std::wstring& value);
+
+ // Given an InstallStatus it tells whether the install was sucessful or not.
+ static bool InstallSuccessful(installer_util::InstallStatus status);
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(InstallUtil);
+};
+
+
+#endif // CHROME_INSTALLER_UTIL_INSTALL_UTIL_H__
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc
new file mode 100644
index 0000000..b0a816a
--- /dev/null
+++ b/chrome/installer/util/install_util_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Unit tests for InstallUtil class.
+
+#include <windows.h>
+
+#include "chrome/installer/util/install_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+class InstallUtilTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Currently no setup required.
+ }
+
+ virtual void TearDown() {
+ // Currently no tear down required.
+ }
+};
+} // namespace
+
+TEST_F(InstallUtilTest, GetNewGoogleUpdateApKeyTest) {
+ installer_util::InstallStatus s = installer_util::FIRST_INSTALL_SUCCESS;
+ installer_util::InstallStatus f = installer_util::INSTALL_FAILED;
+
+ // Incremental Installer that worked.
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L""), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L"1.1"), L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L"1.1-dev"),
+ L"1.1-dev");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L"-full"), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L"1.1-full"),
+ L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, s, L"1.1-dev-full"),
+ L"1.1-dev");
+
+ // Incremental Installer that failed.
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L""), L"-full");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L"1.1"), L"1.1-full");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L"1.1-dev"),
+ L"1.1-dev-full");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L"-full"), L"-full");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L"1.1-full"),
+ L"1.1-full");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(true, f, L"1.1-dev-full"),
+ L"1.1-dev-full");
+
+ // Full Installer that worked.
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L""), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L"1.1"), L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L"1.1-dev"),
+ L"1.1-dev");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L"-full"), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L"1.1-full"),
+ L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, s, L"1.1-dev-full"),
+ L"1.1-dev");
+
+ // Full Installer that failed.
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L""), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L"1.1"), L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L"1.1-dev"),
+ L"1.1-dev");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L"-full"), L"");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L"1.1-full"),
+ L"1.1");
+ EXPECT_EQ(InstallUtil::GetNewGoogleUpdateApKey(false, f, L"1.1-dev-full"),
+ L"1.1-dev");
+}
diff --git a/chrome/installer/util/installer_unittests.vcproj b/chrome/installer/util/installer_unittests.vcproj
new file mode 100644
index 0000000..b7e3eef
--- /dev/null
+++ b/chrome/installer/util/installer_unittests.vcproj
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="installer_unittests"
+ ProjectGUID="{903F8C1E-537A-4C9E-97BE-075147CBE769}"
+ RootNamespace="installer_unittests"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)\tools\build\win\unit_test.vsprops;$(SolutionDir)\installer\util\using_util.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ AdditionalManifestFiles="$(SolutionDir)installer\mini_installer\mini_installer.exe.manifest"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)\tools\build\win\unit_test.vsprops;$(SolutionDir)\installer\util\using_util.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ AdditionalManifestFiles="$(SolutionDir)installer\mini_installer\mini_installer.exe.manifest"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="support"
+ >
+ <File
+ RelativePath="run_all_unittests.cc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="tests"
+ >
+ <File
+ RelativePath="copy_tree_work_item_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="create_dir_work_item_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="create_reg_key_work_item_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="delete_tree_work_item_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="helper_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="install_util_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="set_reg_value_work_item_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\setup_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath="work_item_list_unittest.cc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/installer/util/l10n_string_util.cc b/chrome/installer/util/l10n_string_util.cc
new file mode 100644
index 0000000..b10e1a4
--- /dev/null
+++ b/chrome/installer/util/l10n_string_util.cc
@@ -0,0 +1,148 @@
+#include <atlbase.h>
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+#include "setup_strings.h"
+
+namespace {
+
+// Gets the language from the OS. If we're unable to get the system language,
+// defaults to en-us.
+std::wstring GetSystemLanguage() {
+ static std::wstring language;
+ if (!language.empty())
+ return language;
+ // We don't have ICU at this point, so we use win32 apis.
+ LCID id = GetThreadLocale();
+ int length = GetLocaleInfo(id, LOCALE_SISO639LANGNAME, 0, 0);
+ if (0 == length)
+ return false;
+ length = GetLocaleInfo(id, LOCALE_SISO639LANGNAME,
+ WriteInto(&language, length), length);
+ DCHECK(length == language.length() + 1);
+ StringToLowerASCII(&language);
+
+ // Add the country if we need it.
+ std::wstring country;
+ length = GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, 0, 0);
+ if (0 != length) {
+ length = GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME,
+ WriteInto(&country, length), length);
+ DCHECK(length == country.length() + 1);
+ StringToLowerASCII(&country);
+ if (L"en" == language) {
+ if (L"gb" == country) {
+ language.append(L"-gb");
+ } else {
+ language.append(L"-us");
+ }
+ } else if (L"es" == language && L"es" != country) {
+ language.append(L"-419");
+ } else if (L"pt" == language) {
+ if (L"br" == country) {
+ language.append(L"-br");
+ } else {
+ language.append(L"-pt");
+ }
+ } else if (L"zh" == language) {
+ if (L"tw" == country) {
+ language.append(L"-tw");
+ } else {
+ language.append(L"-cn");
+ }
+ }
+ }
+
+ if (language.empty())
+ language = L"en-us";
+
+ return language;
+}
+
+// This method returns the appropriate language offset given the language as a
+// string. Note: This method is not thread safe because of how we create
+// |offset_map|.
+int GetLanguageOffset(const std::wstring& language) {
+ static std::map<std::wstring, int> offset_map;
+ if (offset_map.empty()) {
+ offset_map[L"ar"] = IDS_L10N_OFFSET_AR;
+ offset_map[L"bg"] = IDS_L10N_OFFSET_BG;
+ offset_map[L"ca"] = IDS_L10N_OFFSET_CA;
+ offset_map[L"cs"] = IDS_L10N_OFFSET_CS;
+ offset_map[L"da"] = IDS_L10N_OFFSET_DA;
+ offset_map[L"de"] = IDS_L10N_OFFSET_DE;
+ offset_map[L"el"] = IDS_L10N_OFFSET_EL;
+ offset_map[L"en-gb"] = IDS_L10N_OFFSET_EN_GB;
+ offset_map[L"en-us"] = IDS_L10N_OFFSET_EN_US;
+ offset_map[L"es"] = IDS_L10N_OFFSET_ES;
+ offset_map[L"es-419"] = IDS_L10N_OFFSET_ES_419;
+ offset_map[L"et"] = IDS_L10N_OFFSET_ET;
+ offset_map[L"fi"] = IDS_L10N_OFFSET_FI;
+ offset_map[L"fil"] = IDS_L10N_OFFSET_FIL;
+ offset_map[L"fr"] = IDS_L10N_OFFSET_FR;
+ offset_map[L"he"] = IDS_L10N_OFFSET_HE;
+ offset_map[L"hi"] = IDS_L10N_OFFSET_HI;
+ offset_map[L"hr"] = IDS_L10N_OFFSET_HR;
+ offset_map[L"hu"] = IDS_L10N_OFFSET_HU;
+ offset_map[L"id"] = IDS_L10N_OFFSET_ID;
+ offset_map[L"it"] = IDS_L10N_OFFSET_IT;
+ offset_map[L"ja"] = IDS_L10N_OFFSET_JA;
+ offset_map[L"ko"] = IDS_L10N_OFFSET_KO;
+ offset_map[L"lt"] = IDS_L10N_OFFSET_LT;
+ offset_map[L"lv"] = IDS_L10N_OFFSET_LV;
+ // Google web properties use no for nb. Handle both just to be safe.
+ offset_map[L"nb"] = IDS_L10N_OFFSET_NO;
+ offset_map[L"nl"] = IDS_L10N_OFFSET_NL;
+ offset_map[L"no"] = IDS_L10N_OFFSET_NO;
+ offset_map[L"pl"] = IDS_L10N_OFFSET_PL;
+ offset_map[L"pt-br"] = IDS_L10N_OFFSET_PT_BR;
+ offset_map[L"pt-pt"] = IDS_L10N_OFFSET_PT_PT;
+ offset_map[L"ro"] = IDS_L10N_OFFSET_RO;
+ offset_map[L"ru"] = IDS_L10N_OFFSET_RU;
+ offset_map[L"sk"] = IDS_L10N_OFFSET_SK;
+ offset_map[L"sl"] = IDS_L10N_OFFSET_SL;
+ offset_map[L"sr"] = IDS_L10N_OFFSET_SR;
+ offset_map[L"sv"] = IDS_L10N_OFFSET_SV;
+ offset_map[L"th"] = IDS_L10N_OFFSET_TH;
+ offset_map[L"tr"] = IDS_L10N_OFFSET_TR;
+ offset_map[L"uk"] = IDS_L10N_OFFSET_UK;
+ offset_map[L"vi"] = IDS_L10N_OFFSET_VI;
+ offset_map[L"zh-cn"] = IDS_L10N_OFFSET_ZH_CN;
+ offset_map[L"zh-tw"] = IDS_L10N_OFFSET_ZH_TW;
+ }
+
+ std::map<std::wstring, int>::iterator it = offset_map.find(
+ StringToLowerASCII(language));
+ if (it != offset_map.end())
+ return it->second;
+
+ NOTREACHED() << "unknown system language-country";
+
+ // Fallback on the en-US offset just in case.
+ return IDS_L10N_OFFSET_EN_US;
+}
+
+} // namespace
+
+namespace installer_util {
+
+std::wstring GetLocalizedString(int base_message_id) {
+ std::wstring language = GetSystemLanguage();
+ std::wstring localized_string;
+
+ int message_id = base_message_id + GetLanguageOffset(language);
+ const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage(
+ _AtlBaseModule.GetModuleInstance(), message_id);
+ if (image) {
+ localized_string = std::wstring(image->achString, image->nLength);
+ } else {
+ NOTREACHED() << "Unable to find resource id " << message_id;
+ }
+
+ return localized_string;
+}
+
+} // namespace installer_util
diff --git a/chrome/installer/util/l10n_string_util.h b/chrome/installer/util/l10n_string_util.h
new file mode 100644
index 0000000..91989ce
--- /dev/null
+++ b/chrome/installer/util/l10n_string_util.h
@@ -0,0 +1,52 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file contains helper functions for getting strings that are included in
+// our DLL for all languages (i.e., does not come from our language DLL).
+//
+// These resource strings are organized such that we can get a localized string
+// by taking the base resource ID and adding a language offset. For example,
+// to get the resource id for the localized product name in en-US, we take
+// IDS_PRODUCT_NAME_BASE + IDS_L10N_OFFSET_EN_US.
+
+#ifndef CHROME_INSTALLER_UTIL_L10N_STRING_UTIL_H_
+#define CHROME_INSTALLER_UTIL_L10N_STRING_UTIL_H_
+
+#include <string>
+
+namespace installer_util {
+
+// Given a string base id, return the localized version of the string based on
+// the system language. This is used for shortcuts placed on the user's
+// desktop.
+std::wstring GetLocalizedString(int base_message_id);
+
+}
+
+#endif // CHROME_INSTALLER_UTIL_L10N_STRING_UTIL_H_
diff --git a/chrome/installer/util/logging_installer.cc b/chrome/installer/util/logging_installer.cc
new file mode 100644
index 0000000..ab0786d
--- /dev/null
+++ b/chrome/installer/util/logging_installer.cc
@@ -0,0 +1,92 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "chrome/installer/util/logging_installer.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "chrome/installer/util/util_constants.h"
+
+namespace installer {
+
+// This should be true for the period between the end of
+// InitInstallerLogging() and the beginning of EndInstallerLogging().
+bool installer_logging_ = false;
+
+void InitInstallerLogging(const CommandLine& command_line) {
+
+ if (installer_logging_)
+ return;
+
+ if (command_line.HasSwitch(installer_util::switches::kDisableLogging)) {
+ installer_logging_ = true;
+ return;
+ }
+
+ logging::InitLogging(GetLogFilePath(command_line).c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+
+ if (command_line.HasSwitch(installer_util::switches::kVerboseLogging)) {
+ logging::SetMinLogLevel(logging::LOG_INFO);
+ } else {
+ logging::SetMinLogLevel(logging::LOG_ERROR);
+ }
+
+ installer_logging_ = true;
+}
+
+void EndInstallerLogging() {
+ logging::CloseLogFile();
+
+ installer_logging_ = false;
+}
+
+std::wstring GetLogFilePath(const CommandLine& command_line) {
+ if (command_line.HasSwitch(installer_util::switches::kLogFile)) {
+ return command_line.GetSwitchValue(installer_util::switches::kLogFile);
+ }
+
+ const std::wstring log_filename(L"chrome_installer.log");
+ std::wstring log_path;
+
+ if (PathService::Get(base::DIR_TEMP, &log_path)) {
+ file_util::AppendToPath(&log_path, log_filename);
+ return log_path;
+ } else {
+ return log_filename;
+ }
+}
+
+} // namespace installer
diff --git a/chrome/installer/util/logging_installer.h b/chrome/installer/util/logging_installer.h
new file mode 100644
index 0000000..769dec3
--- /dev/null
+++ b/chrome/installer/util/logging_installer.h
@@ -0,0 +1,52 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_LOGGING_INSTALLER_H__
+#define CHROME_INSTALLER_LOGGING_INSTALLER_H__
+
+#include <string>
+
+#include "base/logging.h"
+
+class CommandLine;
+
+namespace installer {
+
+// Call to initialize logging for Chrome installer.
+void InitInstallerLogging(const CommandLine& command_line);
+
+// Call when done using logging for Chrome installer.
+void EndInstallerLogging();
+
+// Returns the full path of the log file.
+std::wstring GetLogFilePath(const CommandLine& command_line);
+
+} // namespace installer
+
+#endif
diff --git a/chrome/installer/util/lzma_util.cc b/chrome/installer/util/lzma_util.cc
new file mode 100644
index 0000000..45c30c4
--- /dev/null
+++ b/chrome/installer/util/lzma_util.cc
@@ -0,0 +1,210 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "lzma_util.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+extern "C" {
+#include "Archive/7z/7zExtract.h"
+#include "Archive/7z/7zIn.h"
+#include "7zCrc.h"
+}
+
+
+namespace installer {
+
+typedef struct _CFileInStream {
+ ISzInStream InStream;
+ HANDLE File;
+} CFileInStream;
+
+
+size_t LzmaReadFile(HANDLE file, void *data, size_t size) {
+ if (size == 0)
+ return 0;
+
+ size_t processedSize = 0;
+ do {
+ DWORD processedLoc = 0;
+ BOOL res = ReadFile(file, data, (DWORD) size, &processedLoc, NULL);
+ data = (void *)((unsigned char *) data + processedLoc);
+ size -= processedLoc;
+ processedSize += processedLoc;
+ if (!res || processedLoc == 0)
+ break;
+ } while (size > 0);
+
+ return processedSize;
+}
+
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) {
+ CFileInStream *s = (CFileInStream *) object;
+ LARGE_INTEGER value;
+ value.LowPart = (DWORD) pos;
+ value.HighPart = (LONG) ((UInt64) pos >> 32);
+ value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart,
+ FILE_BEGIN);
+ if (value.LowPart == 0xFFFFFFFF) {
+ if(GetLastError() != NO_ERROR) {
+ return SZE_FAIL;
+ }
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzFileReadImp(void *object, void **buffer,
+ size_t maxRequiredSize, size_t *processedSize) {
+ const int kBufferSize = 1 << 12;
+ static Byte g_Buffer[kBufferSize];
+ if (maxRequiredSize > kBufferSize) {
+ maxRequiredSize = kBufferSize;
+ }
+
+ CFileInStream *s = (CFileInStream *) object;
+ size_t processedSizeLoc;
+ processedSizeLoc = LzmaReadFile(s->File, g_Buffer, maxRequiredSize);
+ *buffer = g_Buffer;
+ if (processedSize != 0) {
+ *processedSize = processedSizeLoc;
+ }
+ return SZ_OK;
+}
+
+
+LzmaUtil::LzmaUtil() : archive_handle_(NULL) {}
+
+LzmaUtil::~LzmaUtil() {
+ if (archive_handle_) CloseArchive();
+}
+
+DWORD LzmaUtil::OpenArchive(const std::wstring& archivePath) {
+ DWORD ret = NO_ERROR;
+ archive_handle_ = CreateFile(archivePath.c_str(), GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (archive_handle_ == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ }
+ return ret;
+}
+
+// Unpacks the archive to the given location.
+DWORD LzmaUtil::UnPack(const std::wstring& location) {
+ CFileInStream archiveStream;
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+ CArchiveDatabaseEx db;
+ DWORD ret = NO_ERROR;
+
+ archiveStream.File = archive_handle_;
+ archiveStream.InStream.Read = SzFileReadImp;
+ archiveStream.InStream.Seek = SzFileSeekImp;
+ allocImp.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ CrcGenerateTable();
+ SzArDbExInit(&db);
+ if ((ret = SzArchiveOpen(&archiveStream.InStream, &db,
+ &allocImp, &allocTempImp)) != SZ_OK) {
+ return ret;
+ }
+
+ Byte *outBuffer = 0; // it must be 0 before first call for each new archive
+ UInt32 blockIndex = 0xFFFFFFFF; // can have any value if outBuffer = 0
+ size_t outBufferSize = 0; // can have any value if outBuffer = 0
+ for (unsigned int i = 0; i < db.Database.NumFiles; i++) {
+ DWORD written;
+ size_t offset;
+ size_t outSizeProcessed;
+ CFileItem *f = db.Database.Files + i;
+
+ if ((ret = SzExtract(&archiveStream.InStream, &db, i, &blockIndex,
+ &outBuffer, &outBufferSize, &offset, &outSizeProcessed,
+ &allocImp, &allocTempImp)) != SZ_OK) {
+ break;
+ }
+
+ // Append location to the file path in archive, to get full path.
+ std::wstring wfileName(location);
+ file_util::AppendToPath(&wfileName, UTF8ToWide(f->Name));
+
+ // If archive entry is directory create it and move on to the next entry.
+ if (f->IsDirectory) {
+ file_util::CreateDirectory(wfileName);
+ continue;
+ }
+
+ HANDLE hFile;
+ std::wstring directory = file_util::GetDirectoryFromPath(wfileName);
+ file_util::CreateDirectory(directory);
+
+ hFile = CreateFile(wfileName.c_str(), GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ break;
+ }
+
+ WriteFile(hFile, outBuffer + offset, (DWORD) outSizeProcessed,
+ &written, NULL);
+ if (written != outSizeProcessed) {
+ ret = GetLastError();
+ CloseHandle(hFile);
+ break;
+ }
+
+ if (f->IsLastWriteTimeDefined) {
+ if (!SetFileTime(hFile, NULL, NULL,
+ (const FILETIME *)&(f->LastWriteTime))) {
+ ret = GetLastError();
+ CloseHandle(hFile);
+ break;
+ }
+ }
+ if (!CloseHandle(hFile)) {
+ ret = GetLastError();
+ break;
+ }
+ } // for loop
+
+ allocImp.Free(outBuffer);
+ SzArDbExFree(&db, allocImp.Free);
+ return ret;
+}
+
+void LzmaUtil::CloseArchive() {
+ CloseHandle(archive_handle_);
+ archive_handle_ = NULL;
+}
+
+} // namespace installer
diff --git a/chrome/installer/util/lzma_util.h b/chrome/installer/util/lzma_util.h
new file mode 100644
index 0000000..67b98d2
--- /dev/null
+++ b/chrome/installer/util/lzma_util.h
@@ -0,0 +1,62 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_LZMA_UTIL_H__
+#define CHROME_INSTALLER_UTIL_LZMA_UTIL_H__
+
+#include <string>
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace installer {
+
+// This is a utility class that acts as a wrapper around LZMA SDK library
+class LzmaUtil {
+ public:
+ LzmaUtil();
+ ~LzmaUtil();
+
+ DWORD OpenArchive(const std::wstring& archivePath);
+
+ // Unpacks the archive to the given location
+ DWORD UnPack(const std::wstring& location);
+
+ void CloseArchive();
+
+ private:
+ HANDLE archive_handle_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(LzmaUtil);
+};
+
+} // namespace installer
+
+
+#endif // CHROME_INSTALLER_UTIL_LZMA_UTIL_H__
diff --git a/chrome/installer/util/prebuild/create_string_rc.bat b/chrome/installer/util/prebuild/create_string_rc.bat
new file mode 100644
index 0000000..51d1c39
--- /dev/null
+++ b/chrome/installer/util/prebuild/create_string_rc.bat
@@ -0,0 +1,10 @@
+:: A wrapper file for running create_string_rc.py from visual studio.
+
+setlocal
+set OUTFILE=%~1
+set PYTHON=%~dp0..\..\..\..\third_party\python_24\python.exe
+
+:: Add grit to the python path so we can import FP.py.
+set PYTHONPATH=%~dp0..\..\..\..\tools\grit\grit\extern
+
+%PYTHON% create_string_rc.py %OUTFILE%
diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py
new file mode 100644
index 0000000..a617646
--- /dev/null
+++ b/chrome/installer/util/prebuild/create_string_rc.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# Copyright 2008 Google Inc. All rights reserved.
+
+"""This script generates an rc file and header (setup_strings.{rc,h}) to be
+included in setup.exe. The rc file includes translations for strings pulled
+from generated_resource.grd and the localized .xtb files.
+
+The header file includes IDs for each string, but also has values to allow
+getting a string based on a language offset. For example, the header file
+looks like this:
+
+#define IDS_L10N_OFFSET_AR 0
+#define IDS_L10N_OFFSET_BG 1
+#define IDS_L10N_OFFSET_CA 2
+...
+#define IDS_L10N_OFFSET_ZH_TW 41
+
+#define IDS_MY_STRING_AR 1600
+#define IDS_MY_STRING_BG 1601
+...
+#define IDS_MY_STRING_BASE IDS_MY_STRING_AR
+
+This allows us to lookup an an ID for a string by adding IDS_MY_STRING_BASE and
+IDS_L10N_OFFSET_* for the language we are interested in.
+"""
+
+import glob
+import os
+import sys
+from xml.dom import minidom
+
+from google import path_utils
+
+import FP
+
+# The IDs of strings we want to import from generated_resources.grd and include
+# in setup.exe's resources.
+kStringIds = [
+ 'IDS_PRODUCT_NAME',
+ 'IDS_UNINSTALL_CHROME',
+]
+
+# The ID of the first resource string.
+kFirstResourceID = 1600
+
+class TranslationStruct:
+ """A helper struct that holds information about a single translation."""
+ def __init__(self, resource_id_str, language, translation):
+ self.resource_id_str = resource_id_str
+ self.language = language
+ self.translation = translation
+
+ def __cmp__(self, other):
+ """Allow TranslationStructs to be sorted by id."""
+ return cmp(self.resource_id_str, other.resource_id_str)
+
+
+def CollectTranslatedStrings():
+ """Collects all the translations for "Google Chrome" from the XTB files.
+ Returns a list of tuples of (language, translated string). The list is
+ sorted by language codes."""
+ kGeneratedResourcesPath = os.path.join(path_utils.ScriptDir(), '..', '..',
+ '..', 'app/generated_resources.grd')
+ kTranslationDirectory = os.path.join(path_utils.ScriptDir(), '..', '..',
+ '..', 'app', 'resources')
+ kTranslationFiles = glob.glob(os.path.join(kTranslationDirectory, '*.xtb'))
+
+ # Get the strings out of generated_resources.grd.
+ dom = minidom.parse(kGeneratedResourcesPath)
+ # message_nodes is a list of message dom nodes corresponding to the string
+ # ids we care about. We want to make sure that this list is in the same
+ # order as kStringIds so we can associate them together.
+ message_nodes = []
+ all_message_nodes = dom.getElementsByTagName('message')
+ for string_id in kStringIds:
+ message_nodes.append([x for x in all_message_nodes if
+ x.getAttribute('name') == string_id][0])
+ message_texts = [node.firstChild.nodeValue.strip() for node in message_nodes]
+
+ # The fingerprint of the string is the message ID in the translation files
+ # (xtb files).
+ translation_ids = [str(FP.FingerPrint(text)) for text in message_texts]
+
+ # Manually put _EN_US in the list of translated strings because it doesn't
+ # have a .xtb file.
+ translated_strings = []
+ for string_id, message_text in zip(kStringIds, message_texts):
+ translated_strings.append(TranslationStruct(string_id + '_EN_US',
+ 'EN_US',
+ message_text))
+
+ # Gather the translated strings from the .xtb files. If an .xtb file doesn't
+ # have the string we want, use the en-US string.
+ for xtb_filename in kTranslationFiles:
+ dom = minidom.parse(xtb_filename)
+ language = dom.documentElement.getAttribute('lang')
+ language = language.replace('-', '_').upper()
+ translation_nodes = {}
+ for translation_node in dom.getElementsByTagName('translation'):
+ translation_id = translation_node.getAttribute('id')
+ if translation_id in translation_ids:
+ translation_nodes[translation_id] = (translation_node.firstChild
+ .nodeValue
+ .strip())
+ for i, string_id in enumerate(kStringIds):
+ translated_string = translation_nodes.get(translation_ids[i],
+ message_texts[i])
+ translated_strings.append(TranslationStruct(string_id + '_' + language,
+ language,
+ translated_string))
+
+ translated_strings.sort()
+ return translated_strings
+
+def WriteRCFile(translated_strings, out_filename):
+ """Writes a resource (rc) file with all the language strings provided in
+ |translated_strings|."""
+ kHeaderText = (
+ u'#include "setup_strings.h"\n\n'
+ u'STRINGTABLE\n'
+ u'BEGIN\n'
+ )
+ kFooterText = (
+ u'END\n'
+ )
+ lines = [kHeaderText]
+ for translation_struct in translated_strings:
+ lines.append(u' %s "%s"\n' % (translation_struct.resource_id_str,
+ translation_struct.translation))
+ lines.append(kFooterText)
+ outfile = open(out_filename, 'wb')
+ outfile.write(''.join(lines).encode('utf-16'))
+ outfile.close()
+
+def WriteHeaderFile(translated_strings, out_filename):
+ """Writes a .h file with resource ids. This file can be included by the
+ executable to refer to identifiers."""
+ lines = []
+
+ # Write the values for how the languages ids are offset.
+ seen_languages = set()
+ offset_id = 0
+ for translation_struct in translated_strings:
+ lang = translation_struct.language
+ if lang not in seen_languages:
+ seen_languages.add(lang)
+ lines.append(u'#define IDS_L10N_OFFSET_%s %s' % (lang, offset_id))
+ offset_id += 1
+ else:
+ break
+
+ # Write the resource ids themselves.
+ resource_id = kFirstResourceID
+ for translation_struct in translated_strings:
+ lines.append(u'#define %s %s' % (translation_struct.resource_id_str,
+ resource_id))
+ resource_id += 1
+
+ # Write out base ID values.
+ for string_id in kStringIds:
+ lines.append(u'#define %s_BASE %s_%s' % (string_id,
+ string_id,
+ translated_strings[0].language))
+
+ outfile = open(out_filename, 'wb')
+ outfile.write('\n'.join(lines))
+ outfile.write('\n') # .rc files must end in a new line
+ outfile.close()
+
+def main(argv):
+ translated_strings = CollectTranslatedStrings()
+ kFilebase = os.path.join(argv[1], 'setup_strings')
+ WriteRCFile(translated_strings, kFilebase + '.rc')
+ WriteHeaderFile(translated_strings, kFilebase + '.h')
+
+if '__main__' == __name__:
+ if len(sys.argv) < 2:
+ print 'Usage:\n %s <output_directory>' % sys.argv[0]
+ sys.exit(1)
+ main(sys.argv)
diff --git a/chrome/installer/util/prebuild/util_prebuild.vcproj b/chrome/installer/util/prebuild/util_prebuild.vcproj
new file mode 100644
index 0000000..1269dde
--- /dev/null
+++ b/chrome/installer/util/prebuild/util_prebuild.vcproj
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="util_prebuild"
+ ProjectGUID="{0026A376-C4F1-4575-A1BA-578C69F07013}"
+ RootNamespace="util_prebuild"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="create_string_rc.bat $(IntDir)"
+ AdditionalDependencies="create_string_rc.py;$(SolutionDir)\app\generated_resources.grd"
+ Outputs="$(IntDir)\setup_strings.rc;$(IntDir)\setup_strings.h"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="create_string_rc.bat $(IntDir)"
+ AdditionalDependencies="create_string_rc.py;$(SolutionDir)\app\generated_resources.grd"
+ Outputs="$(IntDir)\setup_strings.rc;$(IntDir)\setup_strings.h"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/installer/util/prebuild/util_prebuild.vsprops b/chrome/installer/util/prebuild/util_prebuild.vsprops
new file mode 100644
index 0000000..2fa7bc5
--- /dev/null
+++ b/chrome/installer/util/prebuild/util_prebuild.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="util_prebuild"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="$(IntDir)\..\util_prebuild\"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/util/run_all_unittests.cc b/chrome/installer/util/run_all_unittests.cc
new file mode 100644
index 0000000..69b2d3f
--- /dev/null
+++ b/chrome/installer/util/run_all_unittests.cc
@@ -0,0 +1,34 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/test_suite.h"
+
+int main(int argc, char** argv) {
+ return TestSuite(argc, argv).Run();
+}
diff --git a/chrome/installer/util/set_reg_value_work_item.cc b/chrome/installer/util/set_reg_value_work_item.cc
new file mode 100644
index 0000000..8f8d4b4
--- /dev/null
+++ b/chrome/installer/util/set_reg_value_work_item.cc
@@ -0,0 +1,176 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/registry.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/logging_installer.h"
+
+SetRegValueWorkItem::~SetRegValueWorkItem() {
+}
+
+SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ std::wstring value_data,
+ bool overwrite)
+ : predefined_root_(predefined_root),
+ key_path_(key_path),
+ value_name_(value_name),
+ value_data_str_(value_data),
+ overwrite_(overwrite),
+ status_(SET_VALUE),
+ is_str_type_(true) {
+}
+
+SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ DWORD value_data,
+ bool overwrite)
+ : predefined_root_(predefined_root),
+ key_path_(key_path),
+ value_name_(value_name),
+ value_data_dword_(value_data),
+ overwrite_(overwrite),
+ status_(SET_VALUE),
+ is_str_type_(false) {
+}
+
+bool SetRegValueWorkItem::Do() {
+ if (status_ != SET_VALUE) {
+ // we already did something.
+ LOG(ERROR) << "multiple calls to Do()";
+ return false;
+ }
+
+ RegKey key;
+ if (!key.Open(predefined_root_, key_path_.c_str(),
+ KEY_READ | KEY_SET_VALUE)) {
+ LOG(ERROR) << "can not open " << key_path_;
+ status_ = VALUE_UNCHANGED;
+ return false;
+ }
+
+ bool result = false;
+ if (key.ValueExists(value_name_.c_str())) {
+ if (overwrite_) {
+ bool success = true;
+ // Read previous value for rollback and write new value
+ if (is_str_type_) {
+ std::wstring data;
+ if (key.ReadValue(value_name_.c_str(), &data)) {
+ previous_value_str_.assign(data);
+ }
+ success = key.WriteValue(value_name_.c_str(), value_data_str_.c_str());
+ } else {
+ DWORD data;
+ if (key.ReadValueDW(value_name_.c_str(), &data)) {
+ previous_value_dword_ = data;
+ }
+ success = key.WriteValue(value_name_.c_str(), value_data_dword_);
+ }
+ if (success) {
+ LOG(INFO) << "overwritten value for " << value_name_;
+ status_ = VALUE_OVERWRITTEN;
+ result = true;
+ } else {
+ LOG(ERROR) << "failed to overwrite value for " << value_name_;
+ status_ = VALUE_UNCHANGED;
+ result = false;
+ }
+ } else {
+ LOG(INFO) << value_name_ << " exists. not changed ";
+ status_ = VALUE_UNCHANGED;
+ result = true;
+ }
+ } else {
+ bool success = true;
+ if (is_str_type_) {
+ success = key.WriteValue(value_name_.c_str(), value_data_str_.c_str());
+ } else {
+ success = key.WriteValue(value_name_.c_str(), value_data_dword_);
+ }
+ if (success) {
+ LOG(INFO) << "created value for " << value_name_;
+ status_ = NEW_VALUE_CREATED;
+ result = true;
+ } else {
+ LOG(ERROR) << "failed to create value for " << value_name_;
+ status_ = VALUE_UNCHANGED;
+ result = false;
+ }
+ }
+
+ key.Close();
+ return result;
+}
+
+void SetRegValueWorkItem::Rollback() {
+ if (status_ == SET_VALUE || status_ == VALUE_ROLL_BACK)
+ return;
+
+ if (status_ == VALUE_UNCHANGED) {
+ status_ = VALUE_ROLL_BACK;
+ LOG(INFO) << "rollback: setting unchanged, nothing to do";
+ return;
+ }
+
+ RegKey key;
+ if (!key.Open(predefined_root_, key_path_.c_str(),
+ KEY_READ | KEY_SET_VALUE)) {
+ status_ = VALUE_ROLL_BACK;
+ LOG(INFO) << "rollback: can not open " << key_path_;
+ return;
+ }
+
+ std::wstring result_str(L" failed");
+ if (status_ == NEW_VALUE_CREATED) {
+ if (key.DeleteValue(value_name_.c_str()))
+ result_str.assign(L" succeeded");
+ LOG(INFO) << "rollback: deleting " << value_name_ << result_str;
+ } else if (status_ == VALUE_OVERWRITTEN) {
+ // try restore the previous value
+ bool success = true;
+ if (is_str_type_) {
+ success = key.WriteValue(value_name_.c_str(),
+ previous_value_str_.c_str());
+ } else {
+ success = key.WriteValue(value_name_.c_str(), previous_value_dword_);
+ }
+ if (success)
+ result_str.assign(L" succeeded");
+ LOG(INFO) << "rollback: restoring " << value_name_ << result_str;
+ } else {
+ // Not reached.
+ }
+
+ status_ = VALUE_ROLL_BACK;
+ key.Close();
+ return;
+}
diff --git a/chrome/installer/util/set_reg_value_work_item.h b/chrome/installer/util/set_reg_value_work_item.h
new file mode 100644
index 0000000..2b12509
--- /dev/null
+++ b/chrome/installer/util/set_reg_value_work_item.h
@@ -0,0 +1,101 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_SET_REG_VALUE_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_SET_REG_VALUE_WORK_ITEM_H__
+
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that sets a registry value with REG_SZ or REG_DWORD
+// type at the specified path. The value is only set if the target key exists.
+class SetRegValueWorkItem : public WorkItem {
+ public:
+ virtual ~SetRegValueWorkItem();
+
+ virtual bool Do();
+
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ enum SettingStatus {
+ // The status before Do is called.
+ SET_VALUE,
+ // One possible outcome after Do(). A new value is created under the key.
+ NEW_VALUE_CREATED,
+ // One possible outcome after Do(). The previous value under the key has
+ // been overwritten.
+ VALUE_OVERWRITTEN,
+ // One possible outcome after Do(). No change is applied, either
+ // because we are not allowed to overwrite the previous value, or due to
+ // some errors like the key does not exist.
+ VALUE_UNCHANGED,
+ // The status after Do and Rollback is called.
+ VALUE_ROLL_BACK
+ };
+
+ SetRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, std::wstring value_data,
+ bool overwrite);
+
+ SetRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, DWORD value_data,
+ bool overwrite);
+
+ // Root key of the target key under which the value is set. The root key can
+ // only be one of the predefined keys on Windows.
+ HKEY predefined_root_;
+
+ // Path of the target key under which the value is set.
+ std::wstring key_path_;
+
+ // Name of the value to be set.
+ std::wstring value_name_;
+
+ // Data of the value to be set.
+ std::wstring value_data_str_; // if data is of type REG_SZ
+ DWORD value_data_dword_; // if data is of type REG_DWORD
+
+ // Whether to overwrite the existing value under the target key.
+ bool overwrite_;
+
+ // boolean that tells whether data value is of type REG_SZ.
+ bool is_str_type_;
+
+ SettingStatus status_;
+
+ // Data of the previous value.
+ std::wstring previous_value_str_; // if data is of type REG_SZ
+ DWORD previous_value_dword_; // if data is of type REG_DWORD
+};
+
+#endif // CHROME_INSTALLER_UTIL_SET_REG_VALUE_WORK_ITEM_H__
diff --git a/chrome/installer/util/set_reg_value_work_item_unittest.cc b/chrome/installer/util/set_reg_value_work_item_unittest.cc
new file mode 100644
index 0000000..67e68e8
--- /dev/null
+++ b/chrome/installer/util/set_reg_value_work_item_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ wchar_t test_root[] = L"TempTemp";
+ wchar_t data_str_1[] = L"data_111";
+ wchar_t data_str_2[] = L"data_222";
+ DWORD dword1 = 0;
+ DWORD dword2 = 1;
+ class SetRegValueWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create a temporary key for testing
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ key.DeleteKey(test_root);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, test_root, KEY_READ));
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, test_root, KEY_READ));
+
+ // Create a log file
+ std::wstring log_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileName(&log_file));
+ ASSERT_TRUE(file_util::PathExists(log_file));
+
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ logging::SetMinLogLevel(logging::LOG_INFO);
+ }
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up the temporary key
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ ASSERT_TRUE(key.DeleteKey(test_root));
+ }
+ };
+};
+
+// Write a new value without overwrite flag. The value should be set.
+TEST_F(SetRegValueWorkItemTest, WriteNewNonOverwrite) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteNewNonOverwrite");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(), KEY_READ));
+
+ std::wstring name_str(L"name_str");
+ std::wstring data_str(data_str_1);
+ scoped_ptr<SetRegValueWorkItem> work_item1(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_str, data_str, false));
+
+ std::wstring name_dword(L"name_dword");
+ scoped_ptr<SetRegValueWorkItem> work_item2(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_dword, dword1, false));
+
+ EXPECT_TRUE(work_item1->Do());
+ EXPECT_TRUE(work_item2->Do());
+
+ std::wstring read_out;
+ DWORD read_dword;
+ EXPECT_TRUE(key.ReadValue(name_str.c_str(), &read_out));
+ EXPECT_TRUE(key.ReadValueDW(name_dword.c_str(), &read_dword));
+ EXPECT_EQ(read_out, data_str_1);
+ EXPECT_EQ(read_dword, dword1);
+
+ work_item1->Rollback();
+ work_item2->Rollback();
+
+ // Rollback should delete the value.
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+}
+
+// Write a new value with overwrite flag. The value should be set.
+TEST_F(SetRegValueWorkItemTest, WriteNewOverwrite) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteNewOverwrite");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(), KEY_READ));
+
+ std::wstring name_str(L"name_str");
+ std::wstring data_str(data_str_1);
+ scoped_ptr<SetRegValueWorkItem> work_item1(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_str, data_str, true));
+
+ std::wstring name_dword(L"name_dword");
+ scoped_ptr<SetRegValueWorkItem> work_item2(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_dword, dword1, true));
+
+ EXPECT_TRUE(work_item1->Do());
+ EXPECT_TRUE(work_item2->Do());
+
+ std::wstring read_out;
+ DWORD read_dword;
+ EXPECT_TRUE(key.ReadValue(name_str.c_str(), &read_out));
+ EXPECT_TRUE(key.ReadValueDW(name_dword.c_str(), &read_dword));
+ EXPECT_EQ(read_out, data_str_1);
+ EXPECT_EQ(read_dword, dword1);
+
+ work_item1->Rollback();
+ work_item2->Rollback();
+
+ // Rollback should delete the value.
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+}
+
+// Write to an existing value without overwrite flag. There should be
+// no change.
+TEST_F(SetRegValueWorkItemTest, WriteExistingNonOverwrite) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteExistingNonOverwrite");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(),
+ KEY_READ | KEY_SET_VALUE));
+
+ // First test REG_SZ value.
+ // Write data to the value we are going to set.
+ std::wstring name(L"name_str");
+ ASSERT_TRUE(key.WriteValue(name.c_str(), data_str_1));
+
+ std::wstring data(data_str_2);
+ scoped_ptr<SetRegValueWorkItem> work_item(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name, data, false));
+ EXPECT_TRUE(work_item->Do());
+
+ std::wstring read_out;
+ EXPECT_TRUE(key.ReadValue(name.c_str(), &read_out));
+ EXPECT_EQ(0, read_out.compare(data_str_1));
+
+ work_item->Rollback();
+ EXPECT_TRUE(key.ValueExists(name.c_str()));
+ EXPECT_TRUE(key.ReadValue(name.c_str(), &read_out));
+ EXPECT_EQ(read_out, data_str_1);
+
+ // Now test REG_DWORD value.
+ // Write data to the value we are going to set.
+ name.assign(L"name_dword");
+ ASSERT_TRUE(key.WriteValue(name.c_str(), dword1));
+ work_item.reset(WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
+ parent_key, name, dword2, false));
+ EXPECT_TRUE(work_item->Do());
+
+ DWORD read_dword;
+ EXPECT_TRUE(key.ReadValueDW(name.c_str(), &read_dword));
+ EXPECT_EQ(read_dword, dword1);
+
+ work_item->Rollback();
+ EXPECT_TRUE(key.ValueExists(name.c_str()));
+ EXPECT_TRUE(key.ReadValueDW(name.c_str(), &read_dword));
+ EXPECT_EQ(read_dword, dword1);
+}
+
+// Write to an existing value with overwrite flag. The value should be
+// overwritten.
+TEST_F(SetRegValueWorkItemTest, WriteExistingOverwrite) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteExistingOverwrite");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(),
+ KEY_READ | KEY_SET_VALUE));
+
+ // First test REG_SZ value.
+ // Write data to the value we are going to set.
+ std::wstring name(L"name_str");
+ ASSERT_TRUE(key.WriteValue(name.c_str(), data_str_1));
+
+ std::wstring data(data_str_2);
+ scoped_ptr<SetRegValueWorkItem> work_item(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name, data, true));
+ EXPECT_TRUE(work_item->Do());
+
+ std::wstring read_out;
+ EXPECT_TRUE(key.ReadValue(name.c_str(), &read_out));
+ EXPECT_EQ(0, read_out.compare(data_str_2));
+
+ work_item->Rollback();
+ EXPECT_TRUE(key.ValueExists(name.c_str()));
+ EXPECT_TRUE(key.ReadValue(name.c_str(), &read_out));
+ EXPECT_EQ(read_out, data_str_1);
+
+ // Now test REG_DWORD value.
+ // Write data to the value we are going to set.
+ name.assign(L"name_dword");
+ ASSERT_TRUE(key.WriteValue(name.c_str(), dword1));
+ work_item.reset(WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
+ parent_key, name, dword2, true));
+ EXPECT_TRUE(work_item->Do());
+
+ DWORD read_dword;
+ EXPECT_TRUE(key.ReadValueDW(name.c_str(), &read_dword));
+ EXPECT_EQ(read_dword, dword2);
+
+ work_item->Rollback();
+ EXPECT_TRUE(key.ValueExists(name.c_str()));
+ EXPECT_TRUE(key.ReadValueDW(name.c_str(), &read_dword));
+ EXPECT_EQ(read_dword, dword1);
+}
+
+// Write a value to a non-existing key. This should fail.
+TEST_F(SetRegValueWorkItemTest, WriteNonExistingKey) {
+ RegKey key;
+
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteNonExistingKey");
+
+ std::wstring name(L"name");
+ std::wstring data(data_str_1);
+ scoped_ptr<SetRegValueWorkItem> work_item(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name, data, false));
+ EXPECT_FALSE(work_item->Do());
+
+ work_item.reset(WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
+ parent_key, name, dword1, false));
+ EXPECT_FALSE(work_item->Do());
+}
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
new file mode 100644
index 0000000..c8ebfc8
--- /dev/null
+++ b/chrome/installer/util/shell_util.cc
@@ -0,0 +1,376 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines functions that integrate Chrome in Windows shell. These
+// functions can be used by Chrome as well as Chrome installer. All of the
+// work is done by the local functions defined in anonymous namespace in
+// this class.
+
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+
+#include "shell_util.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/l10n_string_util.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/work_item.h"
+
+#include "setup_strings.h"
+
+namespace {
+
+// This class represents a single registry entry. The objective is to
+// encapsulate all the registry entries required for registering Chrome at one
+// place. This class can not be instantiated outside the class and the objects
+// of this class type can be obtained only by calling a static method of this
+// class.
+class RegistryEntry {
+ public:
+ // This method returns a list of all the registry entries that are needed
+ // to register Chrome.
+ static std::list<RegistryEntry*> GetAllEntries(const std::wstring& chrome_exe) {
+ std::list<RegistryEntry*> entries;
+ std::wstring icon_path(chrome_exe);
+ ShellUtil::GetChromeIcon(icon_path);
+ std::wstring quoted_exe_path = L"\"" + chrome_exe + L"\"";
+ std::wstring open_cmd = quoted_exe_path + L" \"%1\"";
+
+ entries.push_front(new RegistryEntry(L"Software\\Classes\\ChromeHTML",
+ L"Chrome HTML"));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Classes\\ChromeHTML\\DefaultIcon", icon_path));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Classes\\ChromeHTML\\shell\\open\\command", open_cmd));
+
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe",
+ installer_util::kApplicationName));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\shell\\open\\command",
+ quoted_exe_path));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\DefaultIcon",
+ icon_path));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\InstallInfo",
+ L"ReinstallCommand",
+ quoted_exe_path + L" --" + switches::kMakeDefaultBrowser));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\InstallInfo",
+ L"HideIconsCommand",
+ quoted_exe_path + L" --" + switches::kHideIcons));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\InstallInfo",
+ L"ShowIconsCommand",
+ quoted_exe_path + L" --" + switches::kShowIcons));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\InstallInfo",
+ L"IconsVisible", 1));
+
+ entries.push_front(new RegistryEntry(
+ ShellUtil::kRegRegisteredApplications,
+ installer_util::kApplicationName,
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities"));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities",
+ L"ApplicationDescription", installer_util::kApplicationName));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities",
+ L"ApplicationIcon", icon_path));
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities",
+ L"ApplicationName", installer_util::kApplicationName));
+
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities\\StartMenu",
+ L"StartMenuInternet", L"chrome.exe"));
+ for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) {
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities\\FileAssociations",
+ ShellUtil::kFileAssociations[i], ShellUtil::kChromeHTMLProgId));
+ }
+ for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) {
+ entries.push_front(new RegistryEntry(
+ L"Software\\Clients\\StartMenuInternet\\chrome.exe\\Capabilities\\URLAssociations",
+ ShellUtil::kProtocolAssociations[i], ShellUtil::kChromeHTMLProgId));
+ }
+ return entries;
+ }
+
+ // Generate work_item tasks required to create current regitry entry and
+ // add them to the given work item list.
+ void AddToWorkItemList(HKEY root, WorkItemList *items) {
+ items->AddCreateRegKeyWorkItem(root, _key_path);
+ if (_is_string) {
+ items->AddSetRegValueWorkItem(root, _key_path, _name, _value, true);
+ } else {
+ items->AddSetRegValueWorkItem(root, _key_path, _name, _int_value, true);
+ }
+ }
+
+ // Check if the current registry entry exists in HKLM registry.
+ bool ExistsInHKLM() {
+ RegKey key(HKEY_LOCAL_MACHINE, _key_path.c_str());
+ bool found = false;
+ if (_is_string) {
+ std::wstring read_value;
+ found = key.ReadValue(_name.c_str(), &read_value) &&
+ read_value == _value;
+ } else {
+ DWORD read_value;
+ found = key.ReadValueDW(_name.c_str(), &read_value) &&
+ read_value == _int_value;
+ }
+ key.Close();
+ return found;
+ }
+
+ private:
+ // Create a object that represent default value of a key
+ RegistryEntry(const std::wstring& key_path, const std::wstring& value) :
+ _key_path(key_path), _name(L""), _value(value),
+ _is_string(true) {
+ }
+
+ // Create a object that represent a key of type REG_SZ
+ RegistryEntry(const std::wstring& key_path, const std::wstring& name,
+ const std::wstring& value) : _key_path(key_path),
+ _name(name), _value(value), _is_string(true) {
+ }
+
+ // Create a object that represent a key of integer type
+ RegistryEntry(const std::wstring& key_path, const std::wstring& name,
+ DWORD value) : _key_path(key_path),
+ _name(name), _int_value(value), _is_string(false) {
+ }
+
+ bool _is_string; // true if current registry entry is of type REG_SZ
+ std::wstring _key_path; // key path for the registry entry
+ std::wstring _name; // name of the registry entry
+ std::wstring _value; // string value (useful if _is_string = true)
+ DWORD _int_value; // integer value (useful if _is_string = false)
+}; // class RegistryEntry
+
+
+// This method checks if Chrome is already registered on the local machine.
+// It gets all the required registry entries for Chrome and then checks if
+// they exist in HKLM. Returns true if all the entries exist, otherwise false.
+bool IsChromeRegistered(const std::wstring& chrome_exe) {
+ bool registered = true;
+ std::list<RegistryEntry*> entries = RegistryEntry::GetAllEntries(chrome_exe);
+ for (std::list<RegistryEntry*>::iterator itr = entries.begin();
+ itr != entries.end(); ++itr) {
+ if (registered && !(*itr)->ExistsInHKLM())
+ registered = false;
+ delete (*itr);
+ }
+ LOG(INFO) << "Check for Chrome registeration returned " << registered;
+ return registered;
+}
+
+
+// This method creates the registry entries required for Add/Remove Programs->
+// Set Program Access and Defaults, Start->Default Programs on Windows Vista
+// and Chrome ProgIds for file extension and protocol handler. root_key is
+// the root registry (HKLM or HKCU).
+bool SetAccessDefaultRegEntries(HKEY root_key,
+ const std::wstring& chrome_exe) {
+ LOG(INFO) << "Registering Chrome browser " << chrome_exe;
+ // Create a list of registry entries work items so that we can rollback
+ // in case of problem.
+ scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList());
+
+ std::list<RegistryEntry*> entries = RegistryEntry::GetAllEntries(chrome_exe);
+ for (std::list<RegistryEntry*>::iterator itr = entries.begin();
+ itr != entries.end(); ++itr) {
+ (*itr)->AddToWorkItemList(root_key, items.get());
+ delete (*itr);
+ }
+
+ // Apply all the registry changes and if there is a problem, rollback.
+ if (!items->Do()) {
+ LOG(ERROR) << "Failed to add Chrome to Set Program Access and Defaults";
+ items->Rollback();
+ return false;
+ }
+
+ return true;
+}
+
+
+// This method registers Chrome on Vista. It checks if we are currently
+// running as admin and if not, it launches setup.exe as administrator which
+// will show user standard Vista elevation prompt. If user accepts it
+// the new process will make the necessary changes and return SUCCESS that
+// we capture and return.
+ShellUtil::RegisterStatus RegisterOnVista(const std::wstring& chrome_exe,
+ bool skip_if_not_admin) {
+ if (IsUserAnAdmin() &&
+ SetAccessDefaultRegEntries(HKEY_LOCAL_MACHINE, chrome_exe))
+ return ShellUtil::SUCCESS;
+
+ if (!skip_if_not_admin) {
+ std::wstring exe_path(file_util::GetDirectoryFromPath(chrome_exe));
+ file_util::AppendToPath(&exe_path, installer_util::kSetupExe);
+ if (!file_util::PathExists(exe_path)) {
+ RegKey key(HKEY_CURRENT_USER, installer_util::kUninstallRegPath);
+ key.ReadValue(installer_util::kUninstallStringField, &exe_path);
+ exe_path = exe_path.substr(0, exe_path.find_first_of(L" --"));
+ TrimString(exe_path, L" \"", &exe_path);
+ }
+ if (file_util::PathExists(exe_path)) {
+ SHELLEXECUTEINFO info = {0};
+ info.cbSize = sizeof(SHELLEXECUTEINFO);
+ info.fMask = SEE_MASK_NOCLOSEPROCESS;
+ info.lpVerb = L"runas";
+ info.lpFile = exe_path.c_str();
+ std::wstring params(L"--");
+ params.append(installer_util::switches::kRegisterChromeBrowser);
+ params.append(L"=\"" + chrome_exe + L"\"");
+ info.lpParameters = params.c_str();
+ info.nShow = SW_SHOW;
+ if (::ShellExecuteEx(&info)) {
+ ::WaitForSingleObject(info.hProcess, INFINITE);
+ DWORD ret_val = ShellUtil::SUCCESS;
+ if (::GetExitCodeProcess(info.hProcess, &ret_val) &&
+ (ret_val == ShellUtil::SUCCESS))
+ return ShellUtil::SUCCESS;
+ }
+ }
+ }
+ return ShellUtil::FAILURE;
+}
+
+} // namespace
+
+
+const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon";
+const wchar_t* ShellUtil::kRegShellPath = L"\\shell";
+const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command";
+const wchar_t* ShellUtil::kRegStartMenuInternet =
+ L"Software\\Clients\\StartMenuInternet";
+const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes";
+const wchar_t* ShellUtil::kRegRegisteredApplications =
+ L"Software\\RegisteredApplications";
+const wchar_t* ShellUtil::kRegShellChromeHTML = L"\\shell\\ChromeHTML";
+const wchar_t* ShellUtil::kRegShellChromeHTMLCommand =
+ L"\\shell\\ChromeHTML\\command";
+
+const wchar_t* ShellUtil::kChromeHTMLProgId = L"ChromeHTML";
+const wchar_t* ShellUtil::kFileAssociations[] = {L".htm", L".html", L".shtml",
+ L".xht", L".xhtml", NULL};
+const wchar_t* ShellUtil::kProtocolAssociations[] = {L"ftp", L"http", L"https",
+ NULL};
+
+
+ShellUtil::RegisterStatus ShellUtil::AddChromeToSetAccessDefaults(
+ const std::wstring& chrome_exe, bool skip_if_not_admin) {
+ if (IsChromeRegistered(chrome_exe))
+ return ShellUtil::SUCCESS;
+
+ if (win_util::GetWinVersion() == win_util::WINVERSION_VISTA)
+ return RegisterOnVista(chrome_exe, skip_if_not_admin);
+
+ // Try adding these entries to HKLM first and if that fails try adding
+ // to HKCU.
+ if (SetAccessDefaultRegEntries(HKEY_LOCAL_MACHINE, chrome_exe))
+ return ShellUtil::SUCCESS;
+
+ if (!skip_if_not_admin &&
+ SetAccessDefaultRegEntries(HKEY_CURRENT_USER, chrome_exe))
+ return ShellUtil::REGISTERED_PER_USER;
+
+ return ShellUtil::FAILURE;
+}
+
+bool ShellUtil::GetChromeIcon(std::wstring& chrome_icon) {
+ if (chrome_icon.empty())
+ return false;
+
+ chrome_icon.append(L",0");
+ return true;
+}
+
+bool ShellUtil::GetChromeShortcutName(std::wstring* shortcut) {
+ shortcut->assign(installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE));
+ shortcut->append(L".lnk");
+ return true;
+}
+
+bool ShellUtil::GetDesktopPath(std::wstring* path) {
+ wchar_t desktop[MAX_PATH];
+ if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT,
+ desktop)))
+ return false;
+ *path = desktop;
+ return true;
+}
+
+bool ShellUtil::GetQuickLaunchPath(std::wstring* path) {
+ if (!PathService::Get(base::DIR_APP_DATA, path))
+ return false;
+ // This path works on Vista as well.
+ file_util::AppendToPath(path, L"Microsoft\\Internet Explorer\\Quick Launch");
+ return true;
+}
+
+bool ShellUtil::UpdateChromeShortcut(const std::wstring& chrome_exe,
+ const std::wstring& shortcut,
+ bool create_new) {
+ std::wstring chrome_path = file_util::GetDirectoryFromPath(chrome_exe);
+ if (create_new) {
+ return file_util::CreateShortcutLink(chrome_exe.c_str(), // target
+ shortcut.c_str(), // shortcut
+ chrome_path.c_str(), // working dir
+ NULL, // arguments
+ NULL, // description
+ chrome_exe.c_str(), // icon file
+ 0); // icon index
+ } else {
+ return file_util::UpdateShortcutLink(chrome_exe.c_str(), // target
+ shortcut.c_str(), // shortcut
+ chrome_path.c_str(), // working dir
+ NULL, // arguments
+ NULL, // description
+ chrome_exe.c_str(), // icon file
+ 0); // icon index
+ }
+}
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
new file mode 100644
index 0000000..d741a76
--- /dev/null
+++ b/chrome/installer/util/shell_util.h
@@ -0,0 +1,145 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file declares methods that are useful for integrating Chrome in
+// Windows shell. These methods are all static and currently part of
+// ShellUtil class.
+
+#ifndef CHROME_INSTALLER_UTIL_SHELL_UTIL_H__
+#define CHROME_INSTALLER_UTIL_SHELL_UTIL_H__
+
+#include <windows.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/installer/util/work_item_list.h"
+
+// This is a utility class that provides common shell integration methods
+// that can be used by installer as well as Chrome.
+class ShellUtil {
+ public:
+ // Return value of AddChromeToSetAccessDefaults.
+ enum RegisterStatus {
+ SUCCESS, // Registration of Chrome successful (in HKLM)
+ FAILURE, // Registration failed (no changes made)
+ REGISTERED_PER_USER // Registered Chrome as per user (in HKCU)
+ };
+
+ // Relative path of DefaultIcon registry entry (prefixed with '\').
+ static const wchar_t* kRegDefaultIcon;
+
+ // Relative path of "shell" registry key.
+ static const wchar_t* kRegShellPath;
+
+ // Relative path of shell open command in Windows registry
+ // (i.e. \\shell\\open\\command).
+ static const wchar_t* kRegShellOpen;
+
+ // Relative path of registry key under which applications need to register
+ // to control Windows Start menu links.
+ static const wchar_t* kRegStartMenuInternet;
+
+ // Relative path of Classes registry entry under which file associations
+ // are added on Windows.
+ static const wchar_t* kRegClasses;
+
+ // Relative path of RegisteredApplications registry entry under which
+ // we add Chrome as a Windows application
+ static const wchar_t* kRegRegisteredApplications;
+
+ // Name that we give to Chrome file association handler ProgId.
+ static const wchar_t* kChromeHTMLProgId;
+
+ // Relative path of shell Chrome Progid in Windows registry
+ // (i.e. \\shell\\ChromeHTML).
+ static const wchar_t* kRegShellChromeHTML;
+
+ // Relative path of shell Chrome Progid command in Windows registry
+ // (i.e. \\shell\\ChromeHTML\\command).
+ static const wchar_t* kRegShellChromeHTMLCommand;
+
+ // File extensions that Chrome registers itself for.
+ static const wchar_t* kFileAssociations[];
+
+ // Protocols that Chrome registers itself for.
+ static const wchar_t* kProtocolAssociations[];
+
+ // This method adds Chrome to the list that shows up in Add/Remove Programs->
+ // Set Program Access and Defaults and also creates Chrome ProgIds under
+ // Software\Classes. This method requires write access to HKLM so is just
+ // best effort deal. If write to HKLM fails and skip_if_not_admin is false,
+ // this method will:
+ // - add the ProgId entries to HKCU on XP. HKCU entries will not make
+ // Chrome show in Set Program Access and Defaults but they are still useful
+ // because we can make Chrome run when user clicks on http link or html
+ // file.
+ // - will try to launch setup.exe with admin priviledges on Vista to do
+ // these tasks. Users will see standard Vista elevation prompt and if they
+ // enter the right credentials, the write operation will work.
+ // Currently skip_if_not_admin is false only when user tries to make Chrome
+ // default browser and Chrome is not registered on the machine.
+ //
+ // chrome_exe: full path to chrome.exe.
+ // skip_if_not_admin: if false will make this method try alternate methods
+ // as described above.
+ static RegisterStatus AddChromeToSetAccessDefaults(
+ const std::wstring& chrome_exe, bool skip_if_not_admin);
+
+ // This method appends the Chrome icon index inside chrome.exe to the
+ // chrome.exe path passed in as input, to generate the full path for
+ // Chrome icon that can be used as value for Windows registry keys.
+ // chrome_icon: full path to chrome.exe.
+ static bool GetChromeIcon(std::wstring& chrome_icon);
+
+ // Returns the localized name of Chrome shortcut.
+ static bool GetChromeShortcutName(std::wstring* shortcut);
+
+ // Gets the desktop path for the current user and returns it in 'path'
+ // argument. Return true if successful, otherwise returns false.
+ static bool GetDesktopPath(std::wstring* path);
+
+ // Gets the Quick Launch shortcuts path for the current user and
+ // returns it in 'path' argument. Return true if successful, otherwise
+ // returns false.
+ static bool GetQuickLaunchPath(std::wstring* path);
+
+ // Updates shortcut (or creates a new shortcut) at destination given by
+ // shortcut to a target given by chrome_exe. The arguments is left NULL
+ // for the target and icon is set as icon at index 0 from exe.
+ // If create_new is set to true, the function will create a new shortcut if
+ // if doesn't exist.
+ static bool UpdateChromeShortcut(const std::wstring& chrome_exe,
+ const std::wstring& shortcut,
+ bool create_new);
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(ShellUtil);
+};
+
+
+#endif // CHROME_INSTALLER_UTIL_SHELL_UTIL_H__
diff --git a/chrome/installer/util/using_util.vsprops b/chrome/installer/util/using_util.vsprops
new file mode 100644
index 0000000..fe84cd9
--- /dev/null
+++ b/chrome/installer/util/using_util.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="using_util"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/installer/util/util.vcproj b/chrome/installer/util/util.vcproj
new file mode 100644
index 0000000..a63254c
--- /dev/null
+++ b/chrome/installer/util/util.vcproj
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="util"
+ ProjectGUID="{EFBB1436-A63F-4CD8-9E99-B89226E782EC}"
+ RootNamespace="util"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)common\common.vsprops;$(SolutionDir)..\third_party\lzma_sdk\using_lzma_sdk.vsprops;prebuild\util_prebuild.vsprops"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)common\common.vsprops;$(SolutionDir)..\third_party\lzma_sdk\using_lzma_sdk.vsprops;prebuild\util_prebuild.vsprops"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\app\google_update_settings.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\app\google_update_settings.h"
+ >
+ </File>
+ <File
+ RelativePath="copy_tree_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="copy_tree_work_item.h"
+ >
+ </File>
+ <File
+ RelativePath="create_dir_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="create_dir_work_item.h"
+ >
+ </File>
+ <File
+ RelativePath="create_reg_key_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="create_reg_key_work_item.h"
+ >
+ </File>
+ <File
+ RelativePath="delete_tree_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="delete_tree_work_item.h"
+ >
+ </File>
+ <File
+ RelativePath="helper.cc"
+ >
+ </File>
+ <File
+ RelativePath="helper.h"
+ >
+ </File>
+ <File
+ RelativePath="install_util.cc"
+ >
+ </File>
+ <File
+ RelativePath="install_util.h"
+ >
+ </File>
+ <File
+ RelativePath="l10n_string_util.cc"
+ >
+ </File>
+ <File
+ RelativePath="l10n_string_util.h"
+ >
+ </File>
+ <File
+ RelativePath="logging_installer.cc"
+ >
+ </File>
+ <File
+ RelativePath="logging_installer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lzma_util.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\lzma_util.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google_update_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google_update_constants.h"
+ >
+ </File>
+ <File
+ RelativePath="set_reg_value_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="set_reg_value_work_item.h"
+ >
+ </File>
+ <File
+ RelativePath=".\shell_util.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\shell_util.h"
+ >
+ </File>
+ <File
+ RelativePath="util_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath="util_constants.h"
+ >
+ </File>
+ <File
+ RelativePath="version.cc"
+ >
+ </File>
+ <File
+ RelativePath="version.h"
+ >
+ </File>
+ <File
+ RelativePath="work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="work_item.h"
+ >
+ </File>
+ <File
+ RelativePath="work_item_list.cc"
+ >
+ </File>
+ <File
+ RelativePath="work_item_list.h"
+ >
+ </File>
+ </Files>
+</VisualStudioProject>
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
new file mode 100644
index 0000000..9833671
--- /dev/null
+++ b/chrome/installer/util/util_constants.cc
@@ -0,0 +1,82 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/util/util_constants.h"
+
+namespace installer_util {
+
+namespace switches {
+
+// Disable logging
+const wchar_t kDisableLogging[] = L"disable-logging";
+
+// Enable logging at the error level. This is the default behavior.
+const wchar_t kEnableLogging[] = L"enable-logging";
+
+// Specify the file path of Chrome archive for install.
+const wchar_t kInstallArchive[] = L"install-archive";
+
+// If present, specify file path to write logging info.
+const wchar_t kLogFile[] = L"log-file";
+
+// Register Chrome as a valid browser on the current sytem. This option
+// requires that setup.exe is running as admin. If this option is specified,
+// options kInstallArchive and kUninstall are ignored.
+const wchar_t kRegisterChromeBrowser[] = L"register-chrome-browser";
+
+// By default we remove all shared (between users) files, registry entries etc
+// during uninstall. If this option is specified together with kUninstall option
+// we do not clean up shared entries otherwise this option is ignored.
+const wchar_t kDoNotRemoveSharedItems[] = L"do-not-remove-shared-items";
+
+// Install Chrome to system wise location. The default is per user install.
+const wchar_t kSystemInstall[] = L"system-install";
+
+// If present, setup will uninstall chrome.
+const wchar_t kUninstall[] = L"uninstall";
+
+// Enable verbose logging (info level).
+const wchar_t kVerboseLogging[] = L"verbose-logging";
+
+} // namespace switches
+
+const wchar_t kInstallBinaryDir[] = L"Application";
+const wchar_t kInstallGoogleDir[] = L"Google";
+const wchar_t kChrome[] = L"Chrome";
+const wchar_t kChromeExe[] = L"chrome.exe";
+const wchar_t kChromeDll[] = L"chrome.dll";
+
+const wchar_t kPublisherName[] = L"Google";
+const wchar_t kApplicationName[] = L"Google Chrome";
+const wchar_t kSetupExe[] = L"setup.exe";
+
+const wchar_t kUninstallRegPath[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Chrome";
+const wchar_t kUninstallStringField[] = L"UninstallString";
+const wchar_t kUninstallDisplayNameField[] = L"DisplayName";
+} // namespace installer_util
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
new file mode 100644
index 0000000..af9596f
--- /dev/null
+++ b/chrome/installer/util/util_constants.h
@@ -0,0 +1,88 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Defines all install related constants that need to be used by Chrome as
+// well as Chrome Installer.
+
+#ifndef CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H__
+#define CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H__
+
+namespace installer_util {
+
+// Return status of installer
+enum InstallStatus {
+ FIRST_INSTALL_SUCCESS, // Successfully installed Chrome for the first time
+ INSTALL_REPAIRED, // Same version reinstalled for repair
+ NEW_VERSION_UPDATED, // Chrome successfully updated to new version
+ HIGHER_VERSION_EXISTS, // Higher version of Chrome already exists
+ INSTALL_FAILED, // Install/update failed
+ OS_NOT_SUPPORTED, // Current OS not supported
+ OS_ERROR, // OS API call failed
+ TEMP_DIR_FAILED, // Unable to get Temp directory
+ UNCOMPRESSION_FAILED, // Failed to uncompress Chrome archive
+ INVALID_ARCHIVE, // Something wrong with the installer archive
+ CHROME_NOT_INSTALLED, // Chrome not installed (returned in case of uninstall)
+ CHROME_RUNNING, // Chrome currently running (when trying to uninstall)
+ UNINSTALL_CONFIRMED, // User has confirmed Chrome uninstall
+ UNINSTALL_SUCCESSFUL, // Chrome successfully uninstalled
+ UNINSTALL_FAILED, // Chrome uninstallation failed
+ UNINSTALL_CANCELLED, // User cancelled Chrome uninstallation
+ UNKNOWN_STATUS, // Unknown status (this should never happen)
+};
+
+namespace switches {
+extern const wchar_t kDisableLogging[];
+extern const wchar_t kEnableLogging[];
+extern const wchar_t kInstallArchive[];
+extern const wchar_t kLogFile[];
+extern const wchar_t kRegisterChromeBrowser[];
+extern const wchar_t kDoNotRemoveSharedItems[];
+extern const wchar_t kSystemInstall[];
+extern const wchar_t kUninstall[];
+extern const wchar_t kVerboseLogging[];
+} // namespace switches
+
+extern const wchar_t kInstallBinaryDir[];
+extern const wchar_t kInstallGoogleDir[];
+extern const wchar_t kChrome[];
+extern const wchar_t kChromeExe[];
+extern const wchar_t kChromeDll[];
+
+// Bug 1214772 - these should be removed for public beta and replaced with
+// a localized string.
+extern const wchar_t kPublisherName[];
+extern const wchar_t kApplicationName[];
+extern const wchar_t kSetupExe[];
+
+extern const wchar_t kUninstallRegPath[];
+extern const wchar_t kUninstallStringField[];
+extern const wchar_t kUninstallDisplayNameField[];
+} // namespace installer_util
+
+#endif // CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H__
diff --git a/chrome/installer/util/version.cc b/chrome/installer/util/version.cc
new file mode 100644
index 0000000..925c950
--- /dev/null
+++ b/chrome/installer/util/version.cc
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <vector>
+
+#include "base/string_util.h"
+#include "chrome/installer/util/version.h"
+
+installer::Version::Version(int64 major, int64 minor, int64 build,
+ int64 patch) :
+ major_(major), minor_(minor), build_(build), patch_(patch) {
+ version_str_.append(Int64ToWString(major_));
+ version_str_.append(L".");
+ version_str_.append(Int64ToWString(minor_));
+ version_str_.append(L".");
+ version_str_.append(Int64ToWString(build_));
+ version_str_.append(L".");
+ version_str_.append(Int64ToWString(patch_));
+}
+
+installer::Version::~Version() {
+}
+
+bool installer::Version::IsHigherThan(const installer::Version* other) const {
+ return ((major_ > other->major_) ||
+ ((major_ == other->major_) && (minor_ > other->minor_)) ||
+ ((major_ == other->major_) && (minor_ == other->minor_)
+ && (build_ > other->build_)) ||
+ ((major_ == other->major_) && (minor_ == other->minor_)
+ && (build_ == other->build_)
+ && (patch_ > other->patch_)));
+}
+
+installer::Version* installer::Version::GetVersionFromString(
+ std::wstring version_str) {
+ std::vector<std::wstring> numbers;
+ SplitString(version_str, '.', &numbers);
+
+ if (numbers.size() != 4) {
+ return NULL;
+ }
+
+ return new Version(StringToInt64(numbers[0]), StringToInt64(numbers[1]),
+ StringToInt64(numbers[2]), StringToInt64(numbers[3]));
+}
diff --git a/chrome/installer/util/version.h b/chrome/installer/util/version.h
new file mode 100644
index 0000000..fba1f9a
--- /dev/null
+++ b/chrome/installer/util/version.h
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_VERSION_H__
+#define CHROME_INSTALLER_UTIL_VERSION_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace installer {
+
+class Version {
+public:
+ virtual ~Version();
+
+ // Check if the current version is higher than the version object passed
+ // as parameter
+ bool IsHigherThan(const Version* other) const;
+
+ // Return the string representation of this version
+ const std::wstring& GetString() const {
+ return version_str_;
+ }
+
+ // Assume that the version string is specified by four integers separated
+ // by character '.'. Return NULL if string is not of this format.
+ // Caller is responsible for freeing the Version object once done.
+ static Version* GetVersionFromString(std::wstring version_str);
+
+private:
+ int64 major_;
+ int64 minor_;
+ int64 build_;
+ int64 patch_;
+ std::wstring version_str_;
+
+ // Classes outside this file do not have any need to create objects of
+ // this type so declare constructor as private.
+ Version(int64 major, int64 minor, int64 build, int64 patch);
+};
+
+} // namespace installer
+
+#endif
diff --git a/chrome/installer/util/work_item.cc b/chrome/installer/util/work_item.cc
new file mode 100644
index 0000000..c273cf3
--- /dev/null
+++ b/chrome/installer/util/work_item.cc
@@ -0,0 +1,85 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/util/work_item.h"
+#include "chrome/installer/util/copy_tree_work_item.h"
+#include "chrome/installer/util/create_dir_work_item.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/work_item_list.h"
+
+WorkItem::WorkItem() {
+}
+
+WorkItem::~WorkItem() {
+}
+
+CopyTreeWorkItem* WorkItem::CreateCopyTreeWorkItem(
+ std::wstring source_path, std::wstring dest_path, std::wstring temp_dir,
+ CopyOverWriteOption overwrite_option, std::wstring alternative_path) {
+ return new CopyTreeWorkItem(source_path, dest_path, temp_dir,
+ overwrite_option, alternative_path);
+}
+
+CreateDirWorkItem* WorkItem::CreateCreateDirWorkItem(std::wstring path) {
+ return new CreateDirWorkItem(path);
+}
+
+CreateRegKeyWorkItem* WorkItem::CreateCreateRegKeyWorkItem(
+ HKEY predefined_root, std::wstring path) {
+ return new CreateRegKeyWorkItem(predefined_root, path);
+}
+
+DeleteTreeWorkItem* WorkItem::CreateDeleteTreeWorkItem(std::wstring root_path,
+ std::wstring key_path) {
+ return new DeleteTreeWorkItem(root_path, key_path);
+}
+
+SetRegValueWorkItem* WorkItem::CreateSetRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, std::wstring value_data, bool overwrite) {
+ return new SetRegValueWorkItem(predefined_root, key_path,
+ value_name, value_data, overwrite);
+}
+
+SetRegValueWorkItem* WorkItem::CreateSetRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, DWORD value_data, bool overwrite) {
+ return new SetRegValueWorkItem(predefined_root, key_path,
+ value_name, value_data, overwrite);
+}
+
+WorkItemList* WorkItem::CreateWorkItemList() {
+ return new WorkItemList();
+}
+
+std::wstring WorkItem::Dump() {
+ return std::wstring(L"Work Item");
+}
diff --git a/chrome/installer/util/work_item.h b/chrome/installer/util/work_item.h
new file mode 100644
index 0000000..c167cf3
--- /dev/null
+++ b/chrome/installer/util/work_item.h
@@ -0,0 +1,124 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Base class for managing an action of a sequence of actions to be carried
+// out during install/update/uninstall. Supports rollback of actions if this
+// process fails.
+
+#ifndef CHROME_INSTALLER_UTIL_WORK_ITEM_H__
+#define CHROME_INSTALLER_UTIL_WORK_ITEM_H__
+
+#include <string>
+#include <windows.h>
+
+class CopyTreeWorkItem;
+class CreateDirWorkItem;
+class CreateRegKeyWorkItem;
+class DeleteTreeWorkItem;
+class SetRegValueWorkItem;
+class WorkItemList;
+
+// A base class that defines APIs to perform/rollback an action or a
+// sequence of actions during install/update/uninstall.
+class WorkItem {
+ public:
+ // Possible states
+ typedef enum CopyOverWriteOption {
+ ALWAYS, // Always overwrite regardless of what existed before.
+ NEVER, // Not used currently.
+ IF_DIFFERENT, // Overwrite if different. Currently only applies to file.
+ RENAME_IF_IN_USE // Copy to a new path instead of overwriting (only files).
+ };
+
+ virtual ~WorkItem();
+
+ // Create a CopyTreeWorkItem that recursively copies a file system hierarchy
+ // from source path to destination path. If overwrite_option is ALWAYS, the
+ // created CopyTreeWorkItem always overwrites files. If overwrite_option is
+ // RENAME_IF_IN_USE, file is copied with an alternate name specified by
+ // alternative_path.
+ static CopyTreeWorkItem* CreateCopyTreeWorkItem(std::wstring source_path,
+ std::wstring dest_path, std::wstring temp_dir,
+ CopyOverWriteOption overwrite_option,
+ std::wstring alternative_path = L"");
+
+ // Create a CreateDirWorkItem that creates a directory at the given path.
+ static CreateDirWorkItem* CreateCreateDirWorkItem(std::wstring path);
+
+ // Create a CreateRegKeyWorkItem that creates a registry key at the given
+ // path.
+ static CreateRegKeyWorkItem* CreateCreateRegKeyWorkItem(
+ HKEY predefined_root, std::wstring path);
+
+ // Create a DeleteTreeWorkItem that recursively deletes a file system
+ // hierarchy at the given root path. A key file can be optionally specified
+ // by key_path.
+ static DeleteTreeWorkItem* CreateDeleteTreeWorkItem(std::wstring root_path,
+ std::wstring key_path);
+
+ // Create a SetRegValueWorkItem that sets a registry value with REG_SZ type
+ // at the key with specified path.
+ static SetRegValueWorkItem* CreateSetRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, std::wstring value_data, bool overwrite);
+
+ // Create a SetRegValueWorkItem that sets a registry value with REG_DWORD type
+ // at the key with specified path.
+ static SetRegValueWorkItem* CreateSetRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, DWORD value_data, bool overwrite);
+
+ // Create an empty WorkItemList. A WorkItemList can recursively contains
+ // a list of WorkItems.
+ static WorkItemList* CreateWorkItemList();
+
+ // Perform the actions of WorkItem. Returns true if success, returns false
+ // otherwise.
+ // If the WorkItem is transactional, then Do() is done as a transaction.
+ // If it returns false, there will be no change on the system.
+ virtual bool Do() = 0;
+
+ // Rollback any actions previously carried out by this WorkItem. If the
+ // WorkItem is transactional, then the previous actions can be fully
+ // rolled back. If the WorkItem is non-transactional, the rollback is a
+ // best effort.
+ virtual void Rollback() = 0;
+
+ // Return true if the WorkItem is transactional, return false if
+ // non-transactional.
+ virtual bool IsTransactional() { return false; }
+
+ // For diagnostics.
+ virtual std::wstring Dump();
+
+ protected:
+ WorkItem();
+};
+
+#endif // CHROME_INSTALLER_UTIL_WORK_ITEM_H__
diff --git a/chrome/installer/util/work_item_list.cc b/chrome/installer/util/work_item_list.cc
new file mode 100644
index 0000000..d9c4b54
--- /dev/null
+++ b/chrome/installer/util/work_item_list.cc
@@ -0,0 +1,142 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/installer/util/logging_installer.h"
+#include "chrome/installer/util/work_item_list.h"
+
+WorkItemList::~WorkItemList() {
+ for (WorkItemIterator itr = list_.begin(); itr != list_.end(); ++itr) {
+ delete (*itr);
+ }
+ for (WorkItemIterator itr = executed_list_.begin();
+ itr != executed_list_.end(); ++itr) {
+ delete (*itr);
+ }
+}
+
+WorkItemList::WorkItemList()
+ : status_(ADD_ITEM) {
+}
+
+bool WorkItemList::Do() {
+ if (status_ != ADD_ITEM)
+ return false;
+
+ bool result = true;
+ while (!list_.empty()) {
+ WorkItem* work_item = list_.front();
+ list_.pop_front();
+ executed_list_.push_front(work_item);
+ if (!work_item->Do()) {
+ LOG(ERROR) << "list execution failed";
+ result = false;
+ break;
+ }
+ }
+
+ if (result)
+ LOG(INFO) << "list execution succeeded";
+
+ status_ = LIST_EXECUTED;
+ return result;
+}
+
+void WorkItemList::Rollback() {
+ if (status_ != LIST_EXECUTED)
+ return;
+
+ for (WorkItemIterator itr = executed_list_.begin();
+ itr != executed_list_.end(); ++itr) {
+ (*itr)->Rollback();
+ }
+
+ status_ = LIST_ROLLED_BACK;
+ return;
+}
+
+bool WorkItemList::AddWorkItem(WorkItem* work_item) {
+ if (status_ != ADD_ITEM)
+ return false;
+
+ list_.push_back(work_item);
+ return true;
+}
+
+bool WorkItemList::AddCopyTreeWorkItem(std::wstring source_path,
+ std::wstring dest_path,
+ std::wstring temp_dir,
+ CopyOverWriteOption overwrite_option,
+ std::wstring alternative_path) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCopyTreeWorkItem(source_path, dest_path, temp_dir,
+ overwrite_option, alternative_path));
+ return AddWorkItem(item);
+}
+
+bool WorkItemList::AddCreateDirWorkItem(std::wstring path) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateDirWorkItem(path));
+ return AddWorkItem(item);
+}
+
+bool WorkItemList::AddCreateRegKeyWorkItem(HKEY predefined_root,
+ std::wstring path) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateRegKeyWorkItem(predefined_root, path));
+ return AddWorkItem(item);
+}
+
+bool WorkItemList::AddDeleteTreeWorkItem(std::wstring root_path,
+ std::wstring key_path) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateDeleteTreeWorkItem(root_path, key_path));
+ return AddWorkItem(item);
+}
+
+bool WorkItemList::AddSetRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ std::wstring value_data,
+ bool overwrite) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateSetRegValueWorkItem(predefined_root, key_path, value_name,
+ value_data, overwrite));
+ return AddWorkItem(item);
+}
+
+bool WorkItemList::AddSetRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ DWORD value_data,
+ bool overwrite) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateSetRegValueWorkItem(predefined_root, key_path, value_name,
+ value_data, overwrite));
+ return AddWorkItem(item);
+}
diff --git a/chrome/installer/util/work_item_list.h b/chrome/installer/util/work_item_list.h
new file mode 100644
index 0000000..a33a21888
--- /dev/null
+++ b/chrome/installer/util/work_item_list.h
@@ -0,0 +1,116 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_INSTALLER_UTIL_WORK_ITEM_LIST_H__
+#define CHROME_INSTALLER_UTIL_WORK_ITEM_LIST_H__
+
+#include <list>
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that recursively contains a list of WorkItems. Thus it
+// provides functionalities to carry out or roll back the sequence of actions
+// defined by the list of WorkItems it contains.
+// The WorkItems are executed in the same order as they are added to the list.
+class WorkItemList : public WorkItem {
+ public:
+ virtual ~WorkItemList();
+
+ // Execute the WorkItems in the same order as they are added to the list.
+ // It aborts as soon as one WorkItem fails.
+ virtual bool Do();
+
+ // Rollback the WorkItems in the reverse order as they are executed.
+ virtual void Rollback();
+
+ // Add a WorkItem to the list. Return true if the WorkItem is successfully
+ // added. Return false otherwise.
+ // A WorkItem can only be added to the list before the list's DO() is called.
+ // Once a WorkItem is added to the list. The list owns the WorkItem.
+ bool AddWorkItem(WorkItem* work_item);
+
+ // Add a CopyTreeWorkItem to the list of work items.
+ bool AddCopyTreeWorkItem(std::wstring source_path, std::wstring dest_path,
+ std::wstring temp_dir,
+ CopyOverWriteOption overwrite_option,
+ std::wstring alternative_path = L"");
+
+ // Add a CreateDirWorkItem that creates a directory at the given path.
+ bool AddCreateDirWorkItem(std::wstring path);
+
+ // Add a CreateRegKeyWorkItem that creates a registry key at the given
+ // path.
+ bool AddCreateRegKeyWorkItem(HKEY predefined_root, std::wstring path);
+
+ // Add a DeleteTreeWorkItem that recursively deletes a file system
+ // hierarchy at the given root path. A key file can be optionally specified
+ // by key_path.
+ bool AddDeleteTreeWorkItem(std::wstring root_path, std::wstring key_path);
+
+ // Add a SetRegValueWorkItem that sets a registry value with REG_SZ type
+ // at the key with specified path.
+ bool AddSetRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, std::wstring value_data,
+ bool overwrite);
+
+ // Add a SetRegValueWorkItem that sets a registry value with REG_DWORD type
+ // at the key with specified path.
+ bool AddSetRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, DWORD value_data,
+ bool overwrite);
+
+ private:
+ friend class WorkItem;
+
+ typedef std::list<WorkItem*> WorkItems;
+ typedef WorkItems::iterator WorkItemIterator;
+
+ enum ListStatus {
+ // List has not been executed. Ok to add new WorkItem.
+ ADD_ITEM,
+ // List has been executed. Can not add new WorkItem.
+ LIST_EXECUTED,
+ // List has been executed and rolled back. No further action is acceptable.
+ LIST_ROLLED_BACK
+ };
+
+ WorkItemList();
+
+ ListStatus status_;
+
+ // The list of WorkItems, in the order of them being added.
+ WorkItems list_;
+
+ // The list of executed WorkItems, in the reverse order of them being
+ // executed.
+ WorkItems executed_list_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_WORK_ITEM_LIST_H__
diff --git a/chrome/installer/util/work_item_list_unittest.cc b/chrome/installer/util/work_item_list_unittest.cc
new file mode 100644
index 0000000..f381b01
--- /dev/null
+++ b/chrome/installer/util/work_item_list_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/work_item.h"
+#include "chrome/installer/util/work_item_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ wchar_t test_root[] = L"ListList";
+ wchar_t data_str[] = L"data_111";
+
+ class WorkItemListTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create a temporary key for testing
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ key.DeleteKey(test_root);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, test_root, KEY_READ));
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, test_root, KEY_READ));
+
+ // Create a temp directory for test.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"WorkItemListTest");
+ file_util::Delete(test_dir_, true);
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ CreateDirectory(test_dir_.c_str(), NULL);
+ ASSERT_TRUE(file_util::PathExists(test_dir_));
+
+ // Create a log file
+ std::wstring log_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileName(&log_file));
+ ASSERT_TRUE(file_util::PathExists(log_file));
+
+ logging::InitLogging(log_file.c_str(),
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ logging::SetMinLogLevel(logging::LOG_INFO);
+ }
+
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, true));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ // Clean up the temporary key
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ ASSERT_TRUE(key.DeleteKey(test_root));
+ }
+
+ std::wstring test_dir_;
+ };
+};
+
+// Execute a WorkItem list successfully and then rollback.
+TEST_F(WorkItemListTest, ExecutionSuccess) {
+ scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+ scoped_ptr<WorkItem> work_item;
+
+ std::wstring top_dir_to_create(test_dir_);
+ file_util::AppendToPath(&top_dir_to_create, L"a");
+ std::wstring dir_to_create(top_dir_to_create);
+ file_util::AppendToPath(&dir_to_create, L"b");
+ ASSERT_FALSE(file_util::PathExists(dir_to_create));
+
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ std::wstring key_to_create(test_root);
+ file_util::AppendToPath(&key_to_create, L"ExecutionSuccess");
+
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER, key_to_create)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ std::wstring name(L"name");
+ std::wstring data(data_str);
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, key_to_create,
+ name, data, false)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ EXPECT_TRUE(work_item_list->Do());
+
+ // Verify all WorkItems have been executed.
+ RegKey key;
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+ std::wstring read_out;
+ EXPECT_TRUE(key.ReadValue(name.c_str(), &read_out));
+ EXPECT_EQ(0, read_out.compare(data_str));
+ key.Close();
+ EXPECT_TRUE(file_util::PathExists(dir_to_create));
+
+ work_item_list->Rollback();
+
+ // Verify everything is rolled back.
+ // The value must have been deleted first in roll back otherwise the key
+ // can not be deleted.
+ EXPECT_FALSE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+ EXPECT_FALSE(file_util::PathExists(top_dir_to_create));
+}
+
+// Execute a WorkItem list. Fail in the middle. Rollback what has been done.
+TEST_F(WorkItemListTest, ExecutionFailAndRollback) {
+ scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+ scoped_ptr<WorkItem> work_item;
+
+ std::wstring top_dir_to_create(test_dir_);
+ file_util::AppendToPath(&top_dir_to_create, L"a");
+ std::wstring dir_to_create(top_dir_to_create);
+ file_util::AppendToPath(&dir_to_create, L"b");
+ ASSERT_FALSE(file_util::PathExists(dir_to_create));
+
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateDirWorkItem(dir_to_create)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ std::wstring key_to_create(test_root);
+ file_util::AppendToPath(&key_to_create, L"ExecutionFail");
+
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER, key_to_create)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ std::wstring not_created_key(test_root);
+ file_util::AppendToPath(&not_created_key, L"NotCreated");
+ std::wstring name(L"name");
+ std::wstring data(data_str);
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, not_created_key,
+ name, data, false)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ // This one will not be executed because we will fail early.
+ work_item.reset(reinterpret_cast<WorkItem*>(
+ WorkItem::CreateCreateRegKeyWorkItem(HKEY_CURRENT_USER,
+ not_created_key)));
+ EXPECT_TRUE(work_item_list->AddWorkItem(work_item.release()));
+
+ EXPECT_FALSE(work_item_list->Do());
+
+ // Verify the first 2 WorkItems have been executed.
+ RegKey key;
+ EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+ key.Close();
+ EXPECT_TRUE(file_util::PathExists(dir_to_create));
+ // The last one should not be there.
+ EXPECT_FALSE(key.Open(HKEY_CURRENT_USER, not_created_key.c_str(),
+ KEY_READ));
+
+ work_item_list->Rollback();
+
+ // Verify everything is rolled back.
+ EXPECT_FALSE(key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ));
+ EXPECT_FALSE(file_util::PathExists(top_dir_to_create));
+}