Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // mini_installer.exe is the first exe that is run when chrome is being | 5 // mini_installer.exe is the first exe that is run when chrome is being |
| 6 // installed or upgraded. It is designed to be extremely small (~5KB with no | 6 // installed or upgraded. It is designed to be extremely small (~5KB with no |
| 7 // extra resources linked) and it has two main jobs: | 7 // extra resources linked) and it has two main jobs: |
| 8 // 1) unpack the resources (possibly decompressing some) | 8 // 1) unpack the resources (possibly decompressing some) |
| 9 // 2) run the real installer (setup.exe) with appropriate flags. | 9 // 2) run the real installer (setup.exe) with appropriate flags. |
| 10 // | 10 // |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 #include <shellapi.h> | 25 #include <shellapi.h> |
| 26 #include <stdlib.h> | 26 #include <stdlib.h> |
| 27 | 27 |
| 28 #include "chrome/installer/mini_installer/appid.h" | 28 #include "chrome/installer/mini_installer/appid.h" |
| 29 #include "chrome/installer/mini_installer/configuration.h" | 29 #include "chrome/installer/mini_installer/configuration.h" |
| 30 #include "chrome/installer/mini_installer/decompress.h" | 30 #include "chrome/installer/mini_installer/decompress.h" |
| 31 #include "chrome/installer/mini_installer/exit_code.h" | 31 #include "chrome/installer/mini_installer/exit_code.h" |
| 32 #include "chrome/installer/mini_installer/mini_installer_constants.h" | 32 #include "chrome/installer/mini_installer/mini_installer_constants.h" |
| 33 #include "chrome/installer/mini_installer/mini_string.h" | 33 #include "chrome/installer/mini_installer/mini_string.h" |
| 34 #include "chrome/installer/mini_installer/pe_resource.h" | 34 #include "chrome/installer/mini_installer/pe_resource.h" |
| 35 #include "chrome/installer/mini_installer/regkey.h" | |
| 35 | 36 |
| 36 namespace mini_installer { | 37 namespace mini_installer { |
| 37 | 38 |
| 38 typedef DWORD ProcessExitCode; | |
| 39 typedef StackString<MAX_PATH> PathString; | 39 typedef StackString<MAX_PATH> PathString; |
| 40 typedef StackString<MAX_PATH * 4> CommandString; | 40 typedef StackString<MAX_PATH * 4> CommandString; |
| 41 | 41 |
| 42 struct ProcessExitCode { | |
|
robertshield
2015/08/04 03:11:36
This isn't a just an exit code anymore, suggest ca
bcwhite
2015/08/04 19:34:30
Done.
| |
| 43 DWORD exit_code; | |
| 44 DWORD windows_code; | |
|
robertshield
2015/08/04 03:11:36
It isn't clear to a Windows dev what "windows_code
bcwhite
2015/08/04 19:34:31
It's usually the result of ::GetLastError() but so
robertshield
2015/08/05 18:39:48
Ok.
| |
| 45 | |
| 46 explicit ProcessExitCode(DWORD exit) : exit_code(exit), windows_code(0) {} | |
| 47 ProcessExitCode(DWORD exit, DWORD win) : exit_code(exit), windows_code(win) { | |
| 48 } | |
| 49 | |
| 50 bool IsSuccess() { | |
| 51 return exit_code == ERROR_SUCCESS; | |
|
robertshield
2015/08/04 03:11:36
Nit: ERROR_SUCCESS is a windows error code, not a
bcwhite
2015/08/04 19:34:30
Done.
| |
| 52 } | |
| 53 }; | |
| 54 | |
| 42 // This structure passes data back and forth for the processing | 55 // This structure passes data back and forth for the processing |
| 43 // of resource callbacks. | 56 // of resource callbacks. |
| 44 struct Context { | 57 struct Context { |
| 45 // Input to the call back method. Specifies the dir to save resources. | 58 // Input to the call back method. Specifies the dir to save resources. |
| 46 const wchar_t* base_path; | 59 const wchar_t* base_path; |
| 47 // First output from call back method. Full path of Chrome archive. | 60 // First output from call back method. Full path of Chrome archive. |
| 48 PathString* chrome_resource_path; | 61 PathString* chrome_resource_path; |
| 49 // Second output from call back method. Full path of Setup archive/exe. | 62 // Second output from call back method. Full path of Setup archive/exe. |
| 50 PathString* setup_resource_path; | 63 PathString* setup_resource_path; |
| 51 }; | 64 }; |
| 52 | 65 |
| 53 // A helper class used to manipulate the Windows registry. Typically, members | |
| 54 // return Windows last-error codes a la the Win32 registry API. | |
| 55 class RegKey { | |
| 56 public: | |
| 57 RegKey() : key_(NULL) { } | |
| 58 ~RegKey() { Close(); } | |
| 59 | 66 |
| 60 // Opens the key named |sub_key| with given |access| rights. Returns | 67 // Opens the Google Update ClientState key for the current install |
| 61 // ERROR_SUCCESS or some other error. | 68 // configuration. This includes locating the correct key in the face of |
| 62 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); | 69 // multi-install. The flag will by default be written to HKCU, but if |
| 70 // --system-level is included in the command line, it will be written to | |
| 71 // HKLM instead. | |
| 72 bool OpenInstallStateKey(const Configuration& configuration, RegKey* key) { | |
| 73 const HKEY root_key = | |
| 74 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 75 const wchar_t* app_guid = configuration.chrome_app_guid(); | |
| 76 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
| 77 LONG ret = ERROR_SUCCESS; | |
| 63 | 78 |
| 64 // Returns true if a key is open. | 79 return RegKey::OpenClientStateKey(root_key, app_guid, key_access, key); |
| 65 bool is_valid() const { return key_ != NULL; } | |
| 66 | |
| 67 // Read a REG_SZ value from the registry into the memory indicated by |value| | |
| 68 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, | |
| 69 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is | |
| 70 // guaranteed to be null-terminated on success. | |
| 71 LONG ReadValue(const wchar_t* value_name, | |
| 72 wchar_t* value, | |
| 73 size_t value_size) const; | |
| 74 | |
| 75 // Write a REG_SZ value to the registry. |value| must be null-terminated. | |
| 76 // Returns ERROR_SUCCESS or an error code. | |
| 77 LONG WriteValue(const wchar_t* value_name, const wchar_t* value); | |
| 78 | |
| 79 // Closes the key if it was open. | |
| 80 void Close(); | |
| 81 | |
| 82 private: | |
| 83 RegKey(const RegKey&); | |
| 84 RegKey& operator=(const RegKey&); | |
| 85 | |
| 86 HKEY key_; | |
| 87 }; // class RegKey | |
| 88 | |
| 89 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) { | |
| 90 Close(); | |
| 91 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_); | |
| 92 } | 80 } |
| 93 | 81 |
| 94 LONG RegKey::ReadValue(const wchar_t* value_name, | 82 // Writes install results into registry where it is read by Google Update. |
| 95 wchar_t* value, | 83 // Don't write anything if there is already a result present, likely |
| 96 size_t value_size) const { | 84 // written by setup.exe. |
| 97 DWORD type; | 85 void WriteInstallResults(const Configuration& configuration, |
| 98 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); | 86 ProcessExitCode result) { |
| 99 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, | 87 #if defined(GOOGLE_CHROME_BUILD) |
| 100 reinterpret_cast<BYTE*>(value), | 88 // Calls to setup.exe will write a "success" result if everything was good |
| 101 &byte_length); | 89 // so we don't need to write anything from here. |
| 102 if (result == ERROR_SUCCESS) { | 90 if (result.IsSuccess()) |
| 103 if (type != REG_SZ) { | 91 return; |
| 104 result = ERROR_NOT_SUPPORTED; | 92 |
| 105 } else if (byte_length == 0) { | 93 RegKey key; |
| 106 *value = L'\0'; | 94 DWORD value; |
| 107 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { | 95 if (OpenInstallStateKey(configuration, &key)) { |
| 108 if ((byte_length / sizeof(wchar_t)) < value_size) | 96 if (key.ReadDWValue(kInstallerResultRegistryValue, &value) |
| 109 value[byte_length / sizeof(wchar_t)] = L'\0'; | 97 != ERROR_SUCCESS || value == 0) { |
| 110 else | 98 key.WriteDWValue(kInstallerResultRegistryValue, |
| 111 result = ERROR_MORE_DATA; | 99 result.exit_code ? 1 /* FAILED_CUSTOM_ERROR */ |
| 100 : 0 /* SUCCESS */); | |
| 101 key.WriteDWValue(kInstallerErrorRegistryValue, result.exit_code); | |
| 102 key.WriteDWValue(kInstallerExtraCode1RegistryValue, result.windows_code); | |
| 112 } | 103 } |
| 104 key.Close(); | |
| 113 } | 105 } |
| 114 return result; | 106 #endif |
| 115 } | |
| 116 | |
| 117 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) { | |
| 118 return ::RegSetValueEx(key_, value_name, 0, REG_SZ, | |
| 119 reinterpret_cast<const BYTE*>(value), | |
| 120 (lstrlen(value) + 1) * sizeof(wchar_t)); | |
| 121 } | |
| 122 | |
| 123 void RegKey::Close() { | |
| 124 if (key_ != NULL) { | |
| 125 ::RegCloseKey(key_); | |
| 126 key_ = NULL; | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 // Helper function to read a value from registry. Returns true if value | |
| 131 // is read successfully and stored in parameter value. Returns false otherwise. | |
| 132 // |size| is measured in wchar_t units. | |
| 133 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | |
| 134 const wchar_t *value_name, wchar_t *value, | |
| 135 size_t size) { | |
| 136 RegKey key; | |
| 137 | |
| 138 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && | |
| 139 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | |
| 140 return true; | |
| 141 } | |
| 142 return false; | |
| 143 } | |
| 144 | |
| 145 // Opens the Google Update ClientState key for a product. This finds only | |
| 146 // registry entries for Chrome; it does not support the Chromium registry | |
| 147 // layout. | |
| 148 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | |
| 149 RegKey* key) { | |
| 150 PathString client_state_key; | |
| 151 return client_state_key.assign(kClientStateKeyBase) && | |
| 152 client_state_key.append(app_guid) && | |
| 153 (key->Open(root_key, | |
| 154 client_state_key.get(), | |
| 155 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); | |
| 156 } | 107 } |
| 157 | 108 |
| 158 // This function sets the flag in registry to indicate that Google Update | 109 // This function sets the flag in registry to indicate that Google Update |
| 159 // should try full installer next time. If the current installer works, this | 110 // should try full installer next time. If the current installer works, this |
| 160 // flag is cleared by setup.exe at the end of install. The flag will by default | 111 // flag is cleared by setup.exe at the end of install. |
| 161 // be written to HKCU, but if --system-level is included in the command line, | |
| 162 // it will be written to HKLM instead. | |
| 163 // TODO(grt): Write a unit test for this that uses registry virtualization. | |
| 164 void SetInstallerFlags(const Configuration& configuration) { | 112 void SetInstallerFlags(const Configuration& configuration) { |
| 165 RegKey key; | 113 RegKey key; |
| 166 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
| 167 const HKEY root_key = | |
| 168 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 169 // This is ignored if multi-install is true. | |
| 170 const wchar_t* app_guid = | |
| 171 configuration.has_chrome_frame() ? | |
| 172 google_update::kChromeFrameAppGuid : | |
| 173 configuration.chrome_app_guid(); | |
| 174 StackString<128> value; | 114 StackString<128> value; |
| 175 LONG ret = ERROR_SUCCESS; | 115 LONG ret = ERROR_SUCCESS; |
| 176 | 116 |
| 177 // When multi_install is true, we are potentially: | 117 if (!OpenInstallStateKey(configuration, &key)) |
| 178 // 1. Performing a multi-install of some product(s) on a clean machine. | 118 return; |
| 179 // Neither the product(s) nor the multi-installer will have a ClientState | |
| 180 // key in the registry, so there is nothing to be done. | |
| 181 // 2. Upgrading an existing multi-install. The multi-installer will have a | |
| 182 // ClientState key in the registry. Only it need be modified. | |
| 183 // 3. Migrating a single-install into a multi-install. The product will have | |
| 184 // a ClientState key in the registry. Only it need be modified. | |
| 185 // To handle all cases, we inspect the product's ClientState to see if it | |
| 186 // exists and its "ap" value does not contain "-multi". This is case 3, so we | |
| 187 // modify the product's ClientState. Otherwise, we check the | |
| 188 // multi-installer's ClientState and modify it if it exists. | |
| 189 if (configuration.is_multi_install()) { | |
| 190 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | |
| 191 // The product has a client state key. See if it's a single-install. | |
| 192 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | |
| 193 if (ret != ERROR_FILE_NOT_FOUND && | |
| 194 (ret != ERROR_SUCCESS || | |
| 195 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | |
| 196 // Error or case 2: modify the multi-installer's value. | |
| 197 key.Close(); | |
| 198 app_guid = google_update::kMultiInstallAppGuid; | |
| 199 } // else case 3: modify this value. | |
| 200 } else { | |
| 201 // case 1 or 2: modify the multi-installer's value. | |
| 202 key.Close(); | |
| 203 app_guid = google_update::kMultiInstallAppGuid; | |
| 204 } | |
| 205 } | |
| 206 | 119 |
| 207 if (!key.is_valid()) { | 120 ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity()); |
| 208 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | |
| 209 return; | |
| 210 | |
| 211 value.clear(); | |
| 212 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | |
| 213 } | |
| 214 | 121 |
| 215 // The conditions below are handling two cases: | 122 // The conditions below are handling two cases: |
| 216 // 1. When ap value is present, we want to add the required tag only if it is | 123 // 1. When ap value is present, we want to add the required tag only if it is |
| 217 // not present. | 124 // not present. |
| 218 // 2. When ap value is missing, we are going to create it with the required | 125 // 2. When ap value is missing, we are going to create it with the required |
| 219 // tag. | 126 // tag. |
| 220 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 127 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
| 221 if (ret == ERROR_FILE_NOT_FOUND) | 128 if (ret == ERROR_FILE_NOT_FOUND) |
| 222 value.clear(); | 129 value.clear(); |
| 223 | 130 |
| 224 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && | 131 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && |
| 225 value.append(kFullInstallerSuffix)) { | 132 value.append(kFullInstallerSuffix)) { |
| 226 key.WriteValue(kApRegistryValue, value.get()); | 133 key.WriteSZValue(kApRegistryValue, value.get()); |
| 227 } | 134 } |
| 228 } | 135 } |
| 229 } | 136 } |
| 230 | 137 |
| 231 // Gets the setup.exe path from Registry by looking at the value of Uninstall | 138 // Gets the setup.exe path from Registry by looking at the value of Uninstall |
| 232 // string. |size| is measured in wchar_t units. | 139 // string. |size| is measured in wchar_t units. |
| 233 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, | 140 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, |
| 234 const wchar_t* app_guid, | 141 const wchar_t* app_guid, |
| 235 const wchar_t* previous_version, | 142 const wchar_t* previous_version, |
| 236 wchar_t* path, | 143 wchar_t* path, |
| 237 size_t size) { | 144 size_t size) { |
| 238 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 145 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| 239 RegKey key; | 146 RegKey key; |
| 240 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) || | 147 if (!RegKey::OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key)) |
| 241 (key.ReadValue(kUninstallRegistryValue, path, size) != ERROR_SUCCESS)) { | 148 return ProcessExitCode(UNABLE_TO_FIND_REGISTRY_KEY); |
| 242 return UNABLE_TO_FIND_REGISTRY_KEY; | 149 DWORD result = key.ReadSZValue(kUninstallRegistryValue, path, size); |
| 243 } | 150 if (result != ERROR_SUCCESS) |
| 151 return ProcessExitCode(UNABLE_TO_FIND_REGISTRY_KEY, result); | |
| 244 | 152 |
| 245 // Check that the path to the existing installer includes the expected | 153 // Check that the path to the existing installer includes the expected |
| 246 // version number. It's not necessary for accuracy to verify before/after | 154 // version number. It's not necessary for accuracy to verify before/after |
| 247 // delimiters. | 155 // delimiters. |
| 248 if (!SearchStringI(path, previous_version)) | 156 if (!SearchStringI(path, previous_version)) |
| 249 return PATCH_NOT_FOR_INSTALLED_VERSION; | 157 return ProcessExitCode(PATCH_NOT_FOR_INSTALLED_VERSION); |
| 250 | 158 |
| 251 return SUCCESS_EXIT_CODE; | 159 return ProcessExitCode(SUCCESS_EXIT_CODE); |
| 252 } | 160 } |
| 253 | 161 |
| 254 // Gets the path to setup.exe of the previous version. The overall path is found | 162 // Gets the path to setup.exe of the previous version. The overall path is found |
| 255 // in the Uninstall string in the registry. A previous version number specified | 163 // in the Uninstall string in the registry. A previous version number specified |
| 256 // in |configuration| is used if available. |size| is measured in wchar_t units. | 164 // in |configuration| is used if available. |size| is measured in wchar_t units. |
| 257 ProcessExitCode GetPreviousSetupExePath(const Configuration& configuration, | 165 ProcessExitCode GetPreviousSetupExePath(const Configuration& configuration, |
| 258 wchar_t* path, | 166 wchar_t* path, |
| 259 size_t size) { | 167 size_t size) { |
| 260 bool system_level = configuration.is_system_level(); | 168 bool system_level = configuration.is_system_level(); |
| 261 const wchar_t* previous_version = configuration.previous_version(); | 169 const wchar_t* previous_version = configuration.previous_version(); |
| 262 ProcessExitCode exit_code = GENERIC_ERROR; | 170 ProcessExitCode exit_code = ProcessExitCode(GENERIC_ERROR); |
| 263 | 171 |
| 264 // If this is a multi install, first try looking in the binaries for the path. | 172 // If this is a multi install, first try looking in the binaries for the path. |
| 265 if (configuration.is_multi_install()) { | 173 if (configuration.is_multi_install()) { |
| 266 exit_code = GetSetupExePathForAppGuid( | 174 exit_code = GetSetupExePathForAppGuid( |
| 267 system_level, google_update::kMultiInstallAppGuid, previous_version, | 175 system_level, google_update::kMultiInstallAppGuid, previous_version, |
| 268 path, size); | 176 path, size); |
| 269 } | 177 } |
| 270 | 178 |
| 271 // Failing that, look in Chrome Frame's client state key if --chrome-frame was | 179 // Failing that, look in Chrome Frame's client state key if --chrome-frame was |
| 272 // specified. | 180 // specified. |
| 273 if (exit_code != SUCCESS_EXIT_CODE && configuration.has_chrome_frame()) { | 181 if (!exit_code.IsSuccess() && configuration.has_chrome_frame()) { |
| 274 exit_code = GetSetupExePathForAppGuid( | 182 exit_code = GetSetupExePathForAppGuid( |
| 275 system_level, google_update::kChromeFrameAppGuid, previous_version, | 183 system_level, google_update::kChromeFrameAppGuid, previous_version, |
| 276 path, size); | 184 path, size); |
| 277 } | 185 } |
| 278 | 186 |
| 279 // Make a last-ditch effort to look in the Chrome client state key. | 187 // Make a last-ditch effort to look in the Chrome client state key. |
| 280 if (exit_code != SUCCESS_EXIT_CODE) { | 188 if (!exit_code.IsSuccess()) { |
| 281 exit_code = GetSetupExePathForAppGuid( | 189 exit_code = GetSetupExePathForAppGuid( |
| 282 system_level, configuration.chrome_app_guid(), previous_version, | 190 system_level, configuration.chrome_app_guid(), previous_version, |
| 283 path, size); | 191 path, size); |
| 284 } | 192 } |
| 285 | 193 |
| 286 return exit_code; | 194 return exit_code; |
| 287 } | 195 } |
| 288 | 196 |
| 289 // Calls CreateProcess with good default parameters and waits for the process to | 197 // Calls CreateProcess with good default parameters and waits for the process to |
| 290 // terminate returning the process exit code. |exit_code|, if non-NULL, is | 198 // terminate returning the process exit code. |exit_code|, if non-NULL, is |
| 291 // populated with the process exit code. | 199 // populated with the process exit code. |
| 292 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { | 200 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { |
| 293 STARTUPINFOW si = {sizeof(si)}; | 201 STARTUPINFOW si = {sizeof(si)}; |
| 294 PROCESS_INFORMATION pi = {0}; | 202 PROCESS_INFORMATION pi = {0}; |
| 295 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, | 203 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, |
| 296 NULL, NULL, &si, &pi)) { | 204 NULL, NULL, &si, &pi)) { |
| 297 return COULD_NOT_CREATE_PROCESS; | 205 return ProcessExitCode(COULD_NOT_CREATE_PROCESS, ::GetLastError()); |
| 298 } | 206 } |
| 299 | 207 |
| 300 ::CloseHandle(pi.hThread); | 208 ::CloseHandle(pi.hThread); |
| 301 | 209 |
| 302 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 210 DWORD exit_code = SUCCESS_EXIT_CODE; |
| 303 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); | 211 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); |
| 304 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) | 212 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) { |
| 305 exit_code = WAIT_FOR_PROCESS_FAILED; | 213 // Note: We've assumed that WAIT_OBJCT_0 != wr means a failure. The call |
| 214 // could return a different object but since we never spawn more than one | |
| 215 // sub-process at a time that case should never happen. | |
| 216 return ProcessExitCode(WAIT_FOR_PROCESS_FAILED, ::GetLastError()); | |
| 217 } | |
| 306 | 218 |
| 307 ::CloseHandle(pi.hProcess); | 219 ::CloseHandle(pi.hProcess); |
| 308 | 220 |
| 309 return exit_code; | 221 return ProcessExitCode(exit_code); |
| 310 } | 222 } |
| 311 | 223 |
| 312 // Appends any command line params passed to mini_installer to the given buffer | 224 // Appends any command line params passed to mini_installer to the given buffer |
| 313 // so that they can be passed on to setup.exe. | 225 // so that they can be passed on to setup.exe. |
| 314 // |buffer| is unchanged in case of error. | 226 // |buffer| is unchanged in case of error. |
| 315 void AppendCommandLineFlags(const Configuration& configuration, | 227 void AppendCommandLineFlags(const Configuration& configuration, |
| 316 CommandString* buffer) { | 228 CommandString* buffer) { |
| 317 PathString full_exe_path; | 229 PathString full_exe_path; |
| 318 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(), | 230 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(), |
| 319 full_exe_path.capacity()); | 231 full_exe_path.capacity()); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 429 // uncompressed 'BN' resources are also extracted. This is generally the set of | 341 // uncompressed 'BN' resources are also extracted. This is generally the set of |
| 430 // DLLs/resources needed by setup.exe to run. | 342 // DLLs/resources needed by setup.exe to run. |
| 431 ProcessExitCode UnpackBinaryResources(const Configuration& configuration, | 343 ProcessExitCode UnpackBinaryResources(const Configuration& configuration, |
| 432 HMODULE module, const wchar_t* base_path, | 344 HMODULE module, const wchar_t* base_path, |
| 433 PathString* archive_path, | 345 PathString* archive_path, |
| 434 PathString* setup_path) { | 346 PathString* setup_path) { |
| 435 // Generate the setup.exe path where we patch/uncompress setup resource. | 347 // Generate the setup.exe path where we patch/uncompress setup resource. |
| 436 PathString setup_dest_path; | 348 PathString setup_dest_path; |
| 437 if (!setup_dest_path.assign(base_path) || | 349 if (!setup_dest_path.assign(base_path) || |
| 438 !setup_dest_path.append(kSetupExe)) | 350 !setup_dest_path.append(kSetupExe)) |
| 439 return PATH_STRING_OVERFLOW; | 351 return ProcessExitCode(PATH_STRING_OVERFLOW); |
| 440 | 352 |
| 441 // Prepare the input to OnResourceFound method that needs a location where | 353 // Prepare the input to OnResourceFound method that needs a location where |
| 442 // it will write all the resources. | 354 // it will write all the resources. |
| 443 Context context = { | 355 Context context = { |
| 444 base_path, | 356 base_path, |
| 445 archive_path, | 357 archive_path, |
| 446 setup_path, | 358 setup_path, |
| 447 }; | 359 }; |
| 448 | 360 |
| 449 // Get the resources of type 'B7' (7zip archive). | 361 // Get the resources of type 'B7' (7zip archive). |
| 450 // We need a chrome archive to do the installation. So if there | 362 // We need a chrome archive to do the installation. So if there |
| 451 // is a problem in fetching B7 resource, just return an error. | 363 // is a problem in fetching B7 resource, just return an error. |
| 452 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 364 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
| 453 reinterpret_cast<LONG_PTR>(&context)) || | 365 reinterpret_cast<LONG_PTR>(&context))) { |
| 454 archive_path->length() == 0) | 366 return ProcessExitCode(UNABLE_TO_EXTRACT_CHROME_ARCHIVE, ::GetLastError()); |
| 455 return UNABLE_TO_EXTRACT_CHROME_ARCHIVE; | 367 } |
| 368 if (archive_path->length() == 0) { | |
| 369 return ProcessExitCode(UNABLE_TO_EXTRACT_CHROME_ARCHIVE); | |
| 370 } | |
| 456 | 371 |
| 457 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 372 ProcessExitCode exit_code = ProcessExitCode(SUCCESS_EXIT_CODE); |
| 458 | 373 |
| 459 // If we found setup 'B7' resource (used for differential updates), handle | 374 // If we found setup 'B7' resource (used for differential updates), handle |
| 460 // it. Note that this is only for Chrome; Chromium installs are always | 375 // it. Note that this is only for Chrome; Chromium installs are always |
| 461 // "full" installs. | 376 // "full" installs. |
| 462 if (setup_path->length() > 0) { | 377 if (setup_path->length() > 0) { |
| 463 CommandString cmd_line; | 378 CommandString cmd_line; |
| 464 PathString exe_path; | 379 PathString exe_path; |
| 465 // Get the path to setup.exe first. | 380 // Get the path to setup.exe first. |
| 466 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), | 381 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), |
| 467 exe_path.capacity()); | 382 exe_path.capacity()); |
| 468 if (exit_code == SUCCESS_EXIT_CODE) { | 383 if (exit_code.IsSuccess()) { |
| 469 if (!cmd_line.append(exe_path.get()) || | 384 if (!cmd_line.append(exe_path.get()) || |
| 470 !cmd_line.append(L" --") || | 385 !cmd_line.append(L" --") || |
| 471 !cmd_line.append(kCmdUpdateSetupExe) || | 386 !cmd_line.append(kCmdUpdateSetupExe) || |
| 472 !cmd_line.append(L"=\"") || | 387 !cmd_line.append(L"=\"") || |
| 473 !cmd_line.append(setup_path->get()) || | 388 !cmd_line.append(setup_path->get()) || |
| 474 !cmd_line.append(L"\" --") || | 389 !cmd_line.append(L"\" --") || |
| 475 !cmd_line.append(kCmdNewSetupExe) || | 390 !cmd_line.append(kCmdNewSetupExe) || |
| 476 !cmd_line.append(L"=\"") || | 391 !cmd_line.append(L"=\"") || |
| 477 !cmd_line.append(setup_dest_path.get()) || | 392 !cmd_line.append(setup_dest_path.get()) || |
| 478 !cmd_line.append(L"\"")) { | 393 !cmd_line.append(L"\"")) { |
| 479 exit_code = COMMAND_STRING_OVERFLOW; | 394 exit_code = ProcessExitCode(COMMAND_STRING_OVERFLOW); |
| 480 } | 395 } |
| 481 } | 396 } |
| 482 | 397 |
| 483 // Get any command line option specified for mini_installer and pass them | 398 // Get any command line option specified for mini_installer and pass them |
| 484 // on to setup.exe. This is important since switches such as | 399 // on to setup.exe. This is important since switches such as |
| 485 // --multi-install and --chrome-frame affect where setup.exe will write | 400 // --multi-install and --chrome-frame affect where setup.exe will write |
| 486 // installer results for consumption by Google Update. | 401 // installer results for consumption by Google Update. |
| 487 AppendCommandLineFlags(configuration, &cmd_line); | 402 AppendCommandLineFlags(configuration, &cmd_line); |
| 488 | 403 |
| 489 if (exit_code == SUCCESS_EXIT_CODE) | 404 if (exit_code.IsSuccess()) |
| 490 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); | 405 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); |
| 491 | 406 |
| 492 if (exit_code != SUCCESS_EXIT_CODE) | 407 if (!exit_code.IsSuccess()) |
| 493 DeleteFile(setup_path->get()); | 408 DeleteFile(setup_path->get()); |
| 494 else if (!setup_path->assign(setup_dest_path.get())) | 409 else if (!setup_path->assign(setup_dest_path.get())) |
| 495 exit_code = PATH_STRING_OVERFLOW; | 410 exit_code = ProcessExitCode(PATH_STRING_OVERFLOW); |
| 496 | 411 |
| 497 return exit_code; | 412 return exit_code; |
| 498 } | 413 } |
| 499 | 414 |
| 500 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 415 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
| 501 // (compressed setup). | 416 // (compressed setup). |
| 502 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, | 417 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, |
| 503 reinterpret_cast<LONG_PTR>(&context)) && | 418 reinterpret_cast<LONG_PTR>(&context)) && |
| 504 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 419 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
| 505 return UNABLE_TO_EXTRACT_SETUP_B7; | 420 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_B7, ::GetLastError()); |
| 421 } | |
| 506 | 422 |
| 507 if (setup_path->length() > 0) { | 423 if (setup_path->length() > 0) { |
| 508 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' | 424 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' |
| 509 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. | 425 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. |
| 510 bool success = mini_installer::Expand(setup_path->get(), | 426 bool success = mini_installer::Expand(setup_path->get(), |
| 511 setup_dest_path.get()); | 427 setup_dest_path.get()); |
| 512 ::DeleteFile(setup_path->get()); | 428 ::DeleteFile(setup_path->get()); |
| 513 if (success) { | 429 if (success) { |
| 514 if (!setup_path->assign(setup_dest_path.get())) { | 430 if (!setup_path->assign(setup_dest_path.get())) { |
| 515 ::DeleteFile(setup_dest_path.get()); | 431 ::DeleteFile(setup_dest_path.get()); |
| 516 exit_code = PATH_STRING_OVERFLOW; | 432 exit_code = ProcessExitCode(PATH_STRING_OVERFLOW); |
| 517 } | 433 } |
| 518 } else { | 434 } else { |
| 519 exit_code = UNABLE_TO_EXTRACT_SETUP_EXE; | 435 exit_code = ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_EXE); |
| 520 } | 436 } |
| 521 | 437 |
| 522 #if defined(COMPONENT_BUILD) | 438 #if defined(COMPONENT_BUILD) |
| 523 // Extract the (uncompressed) modules required by setup.exe. | 439 // Extract the (uncompressed) modules required by setup.exe. |
| 524 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, | 440 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, |
| 525 reinterpret_cast<LONG_PTR>(base_path))) | 441 reinterpret_cast<LONG_PTR>(base_path))) { |
| 526 return UNABLE_TO_EXTRACT_SETUP; | 442 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); |
| 443 } | |
| 527 #endif | 444 #endif |
| 528 | 445 |
| 529 return exit_code; | 446 return exit_code; |
| 530 } | 447 } |
| 531 | 448 |
| 532 // setup.exe still not found. So finally check if it was sent as 'BN' | 449 // setup.exe still not found. So finally check if it was sent as 'BN' |
| 533 // (uncompressed setup). | 450 // (uncompressed setup). |
| 534 // TODO(tommi): We don't need BN anymore so let's remove it (and remove | 451 // TODO(tommi): We don't need BN anymore so let's remove it (and remove |
| 535 // it from create_installer_archive.py). | 452 // it from create_installer_archive.py). |
| 536 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, | 453 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, |
| 537 reinterpret_cast<LONG_PTR>(&context)) && | 454 reinterpret_cast<LONG_PTR>(&context)) && |
| 538 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 455 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
| 539 return UNABLE_TO_EXTRACT_SETUP_BN; | 456 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_BN, ::GetLastError()); |
| 457 } | |
| 540 | 458 |
| 541 if (setup_path->length() > 0) { | 459 if (setup_path->length() > 0) { |
| 542 if (setup_path->comparei(setup_dest_path.get()) != 0) { | 460 if (setup_path->comparei(setup_dest_path.get()) != 0) { |
| 543 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), | 461 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), |
| 544 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { | 462 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { |
| 545 ::DeleteFile(setup_path->get()); | 463 ::DeleteFile(setup_path->get()); |
| 546 setup_path->clear(); | 464 setup_path->clear(); |
| 547 } else if (!setup_path->assign(setup_dest_path.get())) { | 465 } else if (!setup_path->assign(setup_dest_path.get())) { |
| 548 ::DeleteFile(setup_dest_path.get()); | 466 ::DeleteFile(setup_dest_path.get()); |
| 549 } | 467 } |
| 550 } | 468 } |
| 551 } | 469 } |
| 552 | 470 |
| 553 if (setup_path->length() == 0) | 471 if (setup_path->length() == 0) |
| 554 exit_code = UNABLE_TO_EXTRACT_SETUP; | 472 exit_code = ProcessExitCode(UNABLE_TO_EXTRACT_SETUP); |
| 555 | 473 |
| 556 return exit_code; | 474 return exit_code; |
| 557 } | 475 } |
| 558 | 476 |
| 559 // Executes setup.exe, waits for it to finish and returns the exit code. | 477 // Executes setup.exe, waits for it to finish and returns the exit code. |
| 560 ProcessExitCode RunSetup(const Configuration& configuration, | 478 ProcessExitCode RunSetup(const Configuration& configuration, |
| 561 const wchar_t* archive_path, | 479 const wchar_t* archive_path, |
| 562 const wchar_t* setup_path) { | 480 const wchar_t* setup_path) { |
| 563 // There could be three full paths in the command line for setup.exe (path | 481 // There could be three full paths in the command line for setup.exe (path |
| 564 // to exe itself, path to archive and path to log file), so we declare | 482 // to exe itself, path to archive and path to log file), so we declare |
| 565 // total size as three + one additional to hold command line options. | 483 // total size as three + one additional to hold command line options. |
| 566 CommandString cmd_line; | 484 CommandString cmd_line; |
| 567 | 485 |
| 568 // Get the path to setup.exe first. | 486 // Get the path to setup.exe first. |
| 569 if (::lstrlen(setup_path) > 0) { | 487 if (::lstrlen(setup_path) > 0) { |
| 570 if (!cmd_line.assign(L"\"") || | 488 if (!cmd_line.assign(L"\"") || |
| 571 !cmd_line.append(setup_path) || | 489 !cmd_line.append(setup_path) || |
| 572 !cmd_line.append(L"\"")) | 490 !cmd_line.append(L"\"")) |
| 573 return COMMAND_STRING_OVERFLOW; | 491 return ProcessExitCode(COMMAND_STRING_OVERFLOW); |
| 574 } else { | 492 } else { |
| 575 ProcessExitCode exit_code = GetPreviousSetupExePath( | 493 ProcessExitCode exit_code = GetPreviousSetupExePath( |
| 576 configuration, cmd_line.get(), cmd_line.capacity()); | 494 configuration, cmd_line.get(), cmd_line.capacity()); |
| 577 if (exit_code != SUCCESS_EXIT_CODE) | 495 if (!exit_code.IsSuccess()) |
| 578 return exit_code; | 496 return exit_code; |
| 579 } | 497 } |
| 580 | 498 |
| 581 // Append the command line param for chrome archive file. | 499 // Append the command line param for chrome archive file. |
| 582 if (!cmd_line.append(L" --") || | 500 if (!cmd_line.append(L" --") || |
| 583 #if defined(COMPONENT_BUILD) | 501 #if defined(COMPONENT_BUILD) |
| 584 // For faster developer turnaround, the component build generates | 502 // For faster developer turnaround, the component build generates |
| 585 // uncompressed archives. | 503 // uncompressed archives. |
| 586 !cmd_line.append(kCmdUncompressedArchive) || | 504 !cmd_line.append(kCmdUncompressedArchive) || |
| 587 #else | 505 #else |
| 588 !cmd_line.append(kCmdInstallArchive) || | 506 !cmd_line.append(kCmdInstallArchive) || |
| 589 #endif | 507 #endif |
| 590 !cmd_line.append(L"=\"") || | 508 !cmd_line.append(L"=\"") || |
| 591 !cmd_line.append(archive_path) || | 509 !cmd_line.append(archive_path) || |
| 592 !cmd_line.append(L"\"")) | 510 !cmd_line.append(L"\"")) |
| 593 return COMMAND_STRING_OVERFLOW; | 511 return ProcessExitCode(COMMAND_STRING_OVERFLOW); |
| 594 | 512 |
| 595 // Append the command line param for chrome previous version. | 513 // Append the command line param for chrome previous version. |
| 596 if (configuration.previous_version() && | 514 if (configuration.previous_version() && |
| 597 (!cmd_line.append(L" --") || | 515 (!cmd_line.append(L" --") || |
| 598 !cmd_line.append(kCmdPreviousVersion) || | 516 !cmd_line.append(kCmdPreviousVersion) || |
| 599 !cmd_line.append(L"=\"") || | 517 !cmd_line.append(L"=\"") || |
| 600 !cmd_line.append(configuration.previous_version()) || | 518 !cmd_line.append(configuration.previous_version()) || |
| 601 !cmd_line.append(L"\""))) { | 519 !cmd_line.append(L"\""))) { |
| 602 return COMMAND_STRING_OVERFLOW; | 520 return ProcessExitCode(COMMAND_STRING_OVERFLOW); |
| 603 } | 521 } |
| 604 | 522 |
| 605 // Get any command line option specified for mini_installer and pass them | 523 // Get any command line option specified for mini_installer and pass them |
| 606 // on to setup.exe | 524 // on to setup.exe |
| 607 AppendCommandLineFlags(configuration, &cmd_line); | 525 AppendCommandLineFlags(configuration, &cmd_line); |
| 608 | 526 |
| 609 return RunProcessAndWait(NULL, cmd_line.get()); | 527 return RunProcessAndWait(NULL, cmd_line.get()); |
| 610 } | 528 } |
| 611 | 529 |
| 612 // Deletes given files and working dir. | 530 // Deletes given files and working dir. |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 803 // Checks the command line for specific mini installer flags. | 721 // Checks the command line for specific mini installer flags. |
| 804 // If the function returns true, the command line has been processed and all | 722 // If the function returns true, the command line has been processed and all |
| 805 // required actions taken. The installer must exit and return the returned | 723 // required actions taken. The installer must exit and return the returned |
| 806 // |exit_code|. | 724 // |exit_code|. |
| 807 bool ProcessNonInstallOperations(const Configuration& configuration, | 725 bool ProcessNonInstallOperations(const Configuration& configuration, |
| 808 ProcessExitCode* exit_code) { | 726 ProcessExitCode* exit_code) { |
| 809 switch (configuration.operation()) { | 727 switch (configuration.operation()) { |
| 810 case Configuration::CLEANUP: | 728 case Configuration::CLEANUP: |
| 811 // Cleanup has already taken place in DeleteOldChromeTempDirectories at | 729 // Cleanup has already taken place in DeleteOldChromeTempDirectories at |
| 812 // this point, so just tell our caller to exit early. | 730 // this point, so just tell our caller to exit early. |
| 813 *exit_code = SUCCESS_EXIT_CODE; | 731 *exit_code = ProcessExitCode(SUCCESS_EXIT_CODE); |
| 814 return true; | 732 return true; |
| 815 | 733 |
| 816 default: | 734 default: |
| 817 return false; | 735 return false; |
| 818 } | 736 } |
| 819 } | 737 } |
| 820 | 738 |
| 821 // Returns true if we should delete the temp files we create (default). | 739 // Returns true if we should delete the temp files we create (default). |
| 822 // Returns false iff the user has manually created a ChromeInstallerCleanup | 740 // Returns false iff the user has manually created a ChromeInstallerCleanup |
| 823 // string value in the registry under HKCU\\Software\\[Google|Chromium] | 741 // string value in the registry under HKCU\\Software\\[Google|Chromium] |
| 824 // and set its value to "0". That explicitly forbids the mini installer from | 742 // and set its value to "0". That explicitly forbids the mini installer from |
| 825 // deleting these files. | 743 // deleting these files. |
| 826 // Support for this has been publicly mentioned in troubleshooting tips so | 744 // Support for this has been publicly mentioned in troubleshooting tips so |
| 827 // we continue to support it. | 745 // we continue to support it. |
| 828 bool ShouldDeleteExtractedFiles() { | 746 bool ShouldDeleteExtractedFiles() { |
| 829 wchar_t value[2] = {0}; | 747 wchar_t value[2] = {0}; |
| 830 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 748 if (RegKey::ReadSZValue(HKEY_CURRENT_USER, kCleanupRegistryKey, |
| 831 kCleanupRegistryValue, value, _countof(value)) && | 749 kCleanupRegistryValue, value, _countof(value)) && |
| 832 value[0] == L'0') { | 750 value[0] == L'0') { |
| 833 return false; | 751 return false; |
| 834 } | 752 } |
| 835 | 753 |
| 836 return true; | 754 return true; |
| 837 } | 755 } |
| 838 | 756 |
| 839 // Main function. First gets a working dir, unpacks the resources and finally | 757 // Main function. First gets a working dir, unpacks the resources and finally |
| 840 // executes setup.exe to do the install/upgrade. | 758 // executes setup.exe to do the install/upgrade. |
| 841 ProcessExitCode WMain(HMODULE module) { | 759 ProcessExitCode WMain(HMODULE module) { |
| 842 // Always start with deleting potential leftovers from previous installations. | 760 // Always start with deleting potential leftovers from previous installations. |
| 843 // This can make the difference between success and failure. We've seen | 761 // This can make the difference between success and failure. We've seen |
| 844 // many installations out in the field fail due to out of disk space problems | 762 // many installations out in the field fail due to out of disk space problems |
| 845 // so this could buy us some space. | 763 // so this could buy us some space. |
| 846 DeleteOldChromeTempDirectories(); | 764 DeleteOldChromeTempDirectories(); |
| 847 | 765 |
| 848 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 766 ProcessExitCode exit_code = ProcessExitCode(SUCCESS_EXIT_CODE); |
| 849 | 767 |
| 850 // Parse configuration from the command line and resources. | 768 // Parse configuration from the command line and resources. |
| 851 Configuration configuration; | 769 Configuration configuration; |
| 852 if (!configuration.Initialize(module)) | 770 if (!configuration.Initialize(module)) |
| 853 return GENERIC_INITIALIZATION_FAILURE; | 771 return ProcessExitCode(GENERIC_INITIALIZATION_FAILURE); |
| 854 | 772 |
| 855 // If the --cleanup switch was specified on the command line, then that means | 773 // If the --cleanup switch was specified on the command line, then that means |
| 856 // we should only do the cleanup and then exit. | 774 // we should only do the cleanup and then exit. |
| 857 if (ProcessNonInstallOperations(configuration, &exit_code)) | 775 if (ProcessNonInstallOperations(configuration, &exit_code)) |
| 858 return exit_code; | 776 return exit_code; |
| 859 | 777 |
| 860 // First get a path where we can extract payload | 778 // First get a path where we can extract payload |
| 861 PathString base_path; | 779 PathString base_path; |
| 862 if (!GetWorkDir(module, &base_path)) | 780 if (!GetWorkDir(module, &base_path)) |
| 863 return UNABLE_TO_GET_WORK_DIRECTORY; | 781 return ProcessExitCode(UNABLE_TO_GET_WORK_DIRECTORY); |
| 864 | 782 |
| 865 #if defined(GOOGLE_CHROME_BUILD) | 783 #if defined(GOOGLE_CHROME_BUILD) |
| 866 // Set the magic suffix in registry to try full installer next time. We ignore | 784 // Set the magic suffix in registry to try full installer next time. We ignore |
| 867 // any errors here and we try to set the suffix for user level unless | 785 // any errors here and we try to set the suffix for user level unless |
| 868 // --system-level is on the command line in which case we set it for system | 786 // --system-level is on the command line in which case we set it for system |
| 869 // level instead. This only applies to the Google Chrome distribution. | 787 // level instead. This only applies to the Google Chrome distribution. |
| 870 SetInstallerFlags(configuration); | 788 SetInstallerFlags(configuration); |
| 871 #endif | 789 #endif |
| 872 | 790 |
| 873 PathString archive_path; | 791 PathString archive_path; |
| 874 PathString setup_path; | 792 PathString setup_path; |
| 875 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), | 793 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), |
| 876 &archive_path, &setup_path); | 794 &archive_path, &setup_path); |
| 877 | 795 |
| 878 // While unpacking the binaries, we paged in a whole bunch of memory that | 796 // While unpacking the binaries, we paged in a whole bunch of memory that |
| 879 // we don't need anymore. Let's give it back to the pool before running | 797 // we don't need anymore. Let's give it back to the pool before running |
| 880 // setup. | 798 // setup. |
| 881 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); | 799 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); |
| 882 | 800 |
| 883 if (exit_code == SUCCESS_EXIT_CODE) | 801 if (exit_code.IsSuccess()) |
| 884 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); | 802 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); |
| 885 | 803 |
| 886 if (ShouldDeleteExtractedFiles()) | 804 if (ShouldDeleteExtractedFiles()) |
| 887 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 805 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
| 888 | 806 |
| 807 WriteInstallResults(configuration, exit_code); | |
| 889 return exit_code; | 808 return exit_code; |
| 890 } | 809 } |
| 891 | 810 |
| 892 } // namespace mini_installer | 811 } // namespace mini_installer |
| 893 | 812 |
| 894 int MainEntryPoint() { | 813 int MainEntryPoint() { |
| 895 mini_installer::ProcessExitCode result = | 814 mini_installer::ProcessExitCode result = |
| 896 mini_installer::WMain(::GetModuleHandle(NULL)); | 815 mini_installer::WMain(::GetModuleHandle(NULL)); |
| 897 ::ExitProcess(result); | 816 |
| 817 ::ExitProcess(result.exit_code); | |
| 898 } | 818 } |
| 899 | 819 |
| 900 // VC Express editions don't come with the memset CRT obj file and linking to | 820 // VC Express editions don't come with the memset CRT obj file and linking to |
| 901 // the obj files between versions becomes a bit problematic. Therefore, | 821 // the obj files between versions becomes a bit problematic. Therefore, |
| 902 // simply implement memset. | 822 // simply implement memset. |
| 903 // | 823 // |
| 904 // This also avoids having to explicitly set the __sse2_available hack when | 824 // This also avoids having to explicitly set the __sse2_available hack when |
| 905 // linking with both the x64 and x86 obj files which is required when not | 825 // linking with both the x64 and x86 obj files which is required when not |
| 906 // linking with the std C lib in certain instances (including Chromium) with | 826 // linking with the std C lib in certain instances (including Chromium) with |
| 907 // MSVC. __sse2_available determines whether to use SSE2 intructions with | 827 // MSVC. __sse2_available determines whether to use SSE2 intructions with |
| 908 // std C lib routines, and is set by MSVC's std C lib implementation normally. | 828 // std C lib routines, and is set by MSVC's std C lib implementation normally. |
| 909 extern "C" { | 829 extern "C" { |
| 910 #pragma function(memset) | 830 #pragma function(memset) |
| 911 void* memset(void* dest, int c, size_t count) { | 831 void* memset(void* dest, int c, size_t count) { |
| 912 void* start = dest; | 832 void* start = dest; |
| 913 while (count--) { | 833 while (count--) { |
| 914 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 834 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
| 915 dest = reinterpret_cast<char*>(dest) + 1; | 835 dest = reinterpret_cast<char*>(dest) + 1; |
| 916 } | 836 } |
| 917 return start; | 837 return start; |
| 918 } | 838 } |
| 919 } // extern "C" | 839 } // extern "C" |
| OLD | NEW |