| 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 // |
| 11 // In order to be really small the app doesn't link against the CRT and | 11 // In order to be really small the app doesn't link against the CRT and |
| 12 // defines the following compiler/linker flags: | 12 // defines the following compiler/linker flags: |
| 13 // EnableIntrinsicFunctions="true" compiler: /Oi | 13 // EnableIntrinsicFunctions="true" compiler: /Oi |
| 14 // BasicRuntimeChecks="0" | 14 // BasicRuntimeChecks="0" |
| 15 // BufferSecurityCheck="false" compiler: /GS- | 15 // BufferSecurityCheck="false" compiler: /GS- |
| 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY | 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY |
| 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB | 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB |
| 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 | 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 |
| 19 // linker: /SAFESEH:NO | 19 // linker: /SAFESEH:NO |
| 20 | 20 |
| 21 // have the linker merge the sections, saving us ~500 bytes. | 21 // have the linker merge the sections, saving us ~500 bytes. |
| 22 #pragma comment(linker, "/MERGE:.rdata=.text") | 22 #pragma comment(linker, "/MERGE:.rdata=.text") |
| 23 | 23 |
| 24 #include <windows.h> | 24 #include <windows.h> |
| 25 #include <shellapi.h> | 25 #include <shellapi.h> |
| 26 | 26 |
| 27 #include "chrome/installer/mini_installer/appid.h" | 27 #include "chrome/installer/mini_installer/appid.h" |
| 28 #include "chrome/installer/mini_installer/configuration.h" | 28 #include "chrome/installer/mini_installer/configuration.h" |
| 29 #include "chrome/installer/mini_installer/decompress.h" | 29 #include "chrome/installer/mini_installer/decompress.h" |
| 30 #include "chrome/installer/mini_installer/mini_installer.h" | 30 #include "chrome/installer/mini_installer/exit_code.h" |
| 31 #include "chrome/installer/mini_installer/mini_installer_constants.h" |
| 31 #include "chrome/installer/mini_installer/mini_string.h" | 32 #include "chrome/installer/mini_installer/mini_string.h" |
| 32 #include "chrome/installer/mini_installer/pe_resource.h" | 33 #include "chrome/installer/mini_installer/pe_resource.h" |
| 33 | 34 |
| 34 namespace mini_installer { | 35 namespace mini_installer { |
| 35 | 36 |
| 37 typedef DWORD ProcessExitCode; |
| 36 typedef StackString<MAX_PATH> PathString; | 38 typedef StackString<MAX_PATH> PathString; |
| 37 typedef StackString<MAX_PATH * 4> CommandString; | 39 typedef StackString<MAX_PATH * 4> CommandString; |
| 38 | 40 |
| 39 // This structure passes data back and forth for the processing | 41 // This structure passes data back and forth for the processing |
| 40 // of resource callbacks. | 42 // of resource callbacks. |
| 41 struct Context { | 43 struct Context { |
| 42 // Input to the call back method. Specifies the dir to save resources. | 44 // Input to the call back method. Specifies the dir to save resources. |
| 43 const wchar_t* base_path; | 45 const wchar_t* base_path; |
| 44 // First output from call back method. Full path of Chrome archive. | 46 // First output from call back method. Full path of Chrome archive. |
| 45 PathString* chrome_resource_path; | 47 PathString* chrome_resource_path; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | 138 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { |
| 137 return true; | 139 return true; |
| 138 } | 140 } |
| 139 return false; | 141 return false; |
| 140 } | 142 } |
| 141 | 143 |
| 142 // Opens the Google Update ClientState key for a product. | 144 // Opens the Google Update ClientState key for a product. |
| 143 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | 145 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
| 144 RegKey* key) { | 146 RegKey* key) { |
| 145 PathString client_state_key; | 147 PathString client_state_key; |
| 146 return client_state_key.assign(kApRegistryKeyBase) && | 148 return client_state_key.assign(kClientStateKeyBase) && |
| 147 client_state_key.append(app_guid) && | 149 client_state_key.append(app_guid) && |
| 148 (key->Open(root_key, | 150 (key->Open(root_key, |
| 149 client_state_key.get(), | 151 client_state_key.get(), |
| 150 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); | 152 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); |
| 151 } | 153 } |
| 152 | 154 |
| 153 // This function sets the flag in registry to indicate that Google Update | 155 // This function sets the flag in registry to indicate that Google Update |
| 154 // should try full installer next time. If the current installer works, this | 156 // should try full installer next time. If the current installer works, this |
| 155 // flag is cleared by setup.exe at the end of install. The flag will by default | 157 // flag is cleared by setup.exe at the end of install. The flag will by default |
| 156 // be written to HKCU, but if --system-level is included in the command line, | 158 // be written to HKCU, but if --system-level is included in the command line, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 177 // ClientState key in the registry. Only it need be modified. | 179 // ClientState key in the registry. Only it need be modified. |
| 178 // 3. Migrating a single-install into a multi-install. The product will have | 180 // 3. Migrating a single-install into a multi-install. The product will have |
| 179 // a ClientState key in the registry. Only it need be modified. | 181 // a ClientState key in the registry. Only it need be modified. |
| 180 // To handle all cases, we inspect the product's ClientState to see if it | 182 // To handle all cases, we inspect the product's ClientState to see if it |
| 181 // exists and its "ap" value does not contain "-multi". This is case 3, so we | 183 // exists and its "ap" value does not contain "-multi". This is case 3, so we |
| 182 // modify the product's ClientState. Otherwise, we check the | 184 // modify the product's ClientState. Otherwise, we check the |
| 183 // multi-installer's ClientState and modify it if it exists. | 185 // multi-installer's ClientState and modify it if it exists. |
| 184 if (configuration.is_multi_install()) { | 186 if (configuration.is_multi_install()) { |
| 185 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | 187 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { |
| 186 // The product has a client state key. See if it's a single-install. | 188 // The product has a client state key. See if it's a single-install. |
| 187 ret = key.ReadValue(kApRegistryValueName, value.get(), value.capacity()); | 189 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); |
| 188 if (ret != ERROR_FILE_NOT_FOUND && | 190 if (ret != ERROR_FILE_NOT_FOUND && |
| 189 (ret != ERROR_SUCCESS || | 191 (ret != ERROR_SUCCESS || |
| 190 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | 192 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { |
| 191 // Error or case 2: modify the multi-installer's value. | 193 // Error or case 2: modify the multi-installer's value. |
| 192 key.Close(); | 194 key.Close(); |
| 193 app_guid = google_update::kMultiInstallAppGuid; | 195 app_guid = google_update::kMultiInstallAppGuid; |
| 194 } // else case 3: modify this value. | 196 } // else case 3: modify this value. |
| 195 } else { | 197 } else { |
| 196 // case 1 or 2: modify the multi-installer's value. | 198 // case 1 or 2: modify the multi-installer's value. |
| 197 key.Close(); | 199 key.Close(); |
| 198 app_guid = google_update::kMultiInstallAppGuid; | 200 app_guid = google_update::kMultiInstallAppGuid; |
| 199 } | 201 } |
| 200 } | 202 } |
| 201 | 203 |
| 202 if (!key.is_valid()) { | 204 if (!key.is_valid()) { |
| 203 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | 205 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) |
| 204 return; | 206 return; |
| 205 | 207 |
| 206 value.clear(); | 208 value.clear(); |
| 207 ret = key.ReadValue(kApRegistryValueName, value.get(), value.capacity()); | 209 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); |
| 208 } | 210 } |
| 209 | 211 |
| 210 // The conditions below are handling two cases: | 212 // The conditions below are handling two cases: |
| 211 // 1. When ap value is present, we want to add the required tag only if it is | 213 // 1. When ap value is present, we want to add the required tag only if it is |
| 212 // not present. | 214 // not present. |
| 213 // 2. When ap value is missing, we are going to create it with the required | 215 // 2. When ap value is missing, we are going to create it with the required |
| 214 // tag. | 216 // tag. |
| 215 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 217 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
| 216 if (ret == ERROR_FILE_NOT_FOUND) | 218 if (ret == ERROR_FILE_NOT_FOUND) |
| 217 value.clear(); | 219 value.clear(); |
| 218 | 220 |
| 219 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && | 221 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && |
| 220 value.append(kFullInstallerSuffix)) { | 222 value.append(kFullInstallerSuffix)) { |
| 221 key.WriteValue(kApRegistryValueName, value.get()); | 223 key.WriteValue(kApRegistryValue, value.get()); |
| 222 } | 224 } |
| 223 } | 225 } |
| 224 } | 226 } |
| 225 | 227 |
| 226 // Gets the setup.exe path from Registry by looking the value of Uninstall | 228 // Gets the setup.exe path from Registry by looking the value of Uninstall |
| 227 // string. |size| is measured in wchar_t units. | 229 // string. |size| is measured in wchar_t units. |
| 228 bool GetSetupExePathForGuidFromRegistry(bool system_level, | 230 bool GetSetupExePathForGuidFromRegistry(bool system_level, |
| 229 const wchar_t* app_guid, | 231 const wchar_t* app_guid, |
| 230 wchar_t* path, | 232 wchar_t* path, |
| 231 size_t size) { | 233 size_t size) { |
| 232 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 234 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| 233 RegKey key; | 235 RegKey key; |
| 234 return OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) && | 236 return OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) && |
| 235 (key.ReadValue(kUninstallRegistryValueName, path, size) == ERROR_SUCCESS); | 237 (key.ReadValue(kUninstallRegistryValue, path, size) == ERROR_SUCCESS); |
| 236 } | 238 } |
| 237 | 239 |
| 238 // Gets the setup.exe path from Registry by looking the value of Uninstall | 240 // Gets the setup.exe path from Registry by looking the value of Uninstall |
| 239 // string. |size| is measured in wchar_t units. | 241 // string. |size| is measured in wchar_t units. |
| 240 bool GetSetupExePathFromRegistry(const Configuration& configuration, | 242 bool GetSetupExePathFromRegistry(const Configuration& configuration, |
| 241 wchar_t* path, | 243 wchar_t* path, |
| 242 size_t size) { | 244 size_t size) { |
| 243 bool system_level = configuration.is_system_level(); | 245 bool system_level = configuration.is_system_level(); |
| 244 | 246 |
| 245 // If this is a multi install, first try looking in the binaries for the path. | 247 // If this is a multi install, first try looking in the binaries for the path. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 262 return true; | 264 return true; |
| 263 } | 265 } |
| 264 if (configuration.has_app_host() && GetSetupExePathForGuidFromRegistry( | 266 if (configuration.has_app_host() && GetSetupExePathForGuidFromRegistry( |
| 265 system_level, google_update::kChromeAppHostAppGuid, path, size)) { | 267 system_level, google_update::kChromeAppHostAppGuid, path, size)) { |
| 266 return true; | 268 return true; |
| 267 } | 269 } |
| 268 | 270 |
| 269 return false; | 271 return false; |
| 270 } | 272 } |
| 271 | 273 |
| 272 // Calls CreateProcess with good default parameters and waits for the process | 274 // Calls CreateProcess with good default parameters and waits for the process to |
| 273 // to terminate returning the process exit code. | 275 // terminate returning the process exit code. |exit_code|, if non-NULL, is |
| 276 // populated with the process exit code. |
| 274 bool RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline, | 277 bool RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline, |
| 275 int* exit_code) { | 278 ProcessExitCode* exit_code) { |
| 276 STARTUPINFOW si = {sizeof(si)}; | 279 STARTUPINFOW si = {sizeof(si)}; |
| 277 PROCESS_INFORMATION pi = {0}; | 280 PROCESS_INFORMATION pi = {0}; |
| 278 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, | 281 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, |
| 279 NULL, NULL, &si, &pi)) { | 282 NULL, NULL, &si, &pi)) { |
| 280 return false; | 283 return false; |
| 281 } | 284 } |
| 282 | 285 |
| 283 ::CloseHandle(pi.hThread); | 286 ::CloseHandle(pi.hThread); |
| 284 | 287 |
| 285 bool ret = true; | 288 bool ret = true; |
| 286 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); | 289 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); |
| 287 if (WAIT_OBJECT_0 != wr) { | 290 if (WAIT_OBJECT_0 != wr) { |
| 288 ret = false; | 291 ret = false; |
| 289 } else if (exit_code) { | 292 } else if (exit_code) { |
| 290 if (!::GetExitCodeProcess(pi.hProcess, | 293 if (!::GetExitCodeProcess(pi.hProcess, exit_code)) |
| 291 reinterpret_cast<DWORD*>(exit_code))) { | |
| 292 ret = false; | 294 ret = false; |
| 293 } | |
| 294 } | 295 } |
| 295 | 296 |
| 296 ::CloseHandle(pi.hProcess); | 297 ::CloseHandle(pi.hProcess); |
| 297 | 298 |
| 298 return ret; | 299 return ret; |
| 299 } | 300 } |
| 300 | 301 |
| 301 // Append any command line params passed to mini_installer to the given buffer | 302 // Append any command line params passed to mini_installer to the given buffer |
| 302 // so that they can be passed on to setup.exe. We do not return any error from | 303 // so that they can be passed on to setup.exe. We do not return any error from |
| 303 // this method and simply skip making any changes in case of error. | 304 // this method and simply skip making any changes in case of error. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 (resource.Size() > kMaxResourceSize)) { | 346 (resource.Size() > kMaxResourceSize)) { |
| 346 return FALSE; | 347 return FALSE; |
| 347 } | 348 } |
| 348 | 349 |
| 349 PathString full_path; | 350 PathString full_path; |
| 350 if (!full_path.assign(ctx->base_path) || | 351 if (!full_path.assign(ctx->base_path) || |
| 351 !full_path.append(name) || | 352 !full_path.append(name) || |
| 352 !resource.WriteToDisk(full_path.get())) | 353 !resource.WriteToDisk(full_path.get())) |
| 353 return FALSE; | 354 return FALSE; |
| 354 | 355 |
| 355 if (StrStartsWith(name, kChromePrefix)) { | 356 if (StrStartsWith(name, kChromeArchivePrefix)) { |
| 356 if (!ctx->chrome_resource_path->assign(full_path.get())) | 357 if (!ctx->chrome_resource_path->assign(full_path.get())) |
| 357 return FALSE; | 358 return FALSE; |
| 358 } else if (StrStartsWith(name, kSetupPrefix)) { | 359 } else if (StrStartsWith(name, kSetupPrefix)) { |
| 359 if (!ctx->setup_resource_path->assign(full_path.get())) | 360 if (!ctx->setup_resource_path->assign(full_path.get())) |
| 360 return FALSE; | 361 return FALSE; |
| 361 } else { | 362 } else { |
| 362 // Resources should either start with 'chrome' or 'setup'. We don't handle | 363 // Resources should either start with 'chrome' or 'setup'. We don't handle |
| 363 // anything else. | 364 // anything else. |
| 364 return FALSE; | 365 return FALSE; |
| 365 } | 366 } |
| 366 | 367 |
| 367 return TRUE; | 368 return TRUE; |
| 368 } | 369 } |
| 369 | 370 |
| 370 // Finds and writes to disk resources of various types. Returns false | 371 // Finds and writes to disk resources of various types. Returns false |
| 371 // if there is a problem in writing any resource to disk. setup.exe resource | 372 // if there is a problem in writing any resource to disk. setup.exe resource |
| 372 // can come in one of three possible forms: | 373 // can come in one of three possible forms: |
| 373 // - Resource type 'B7', compressed using LZMA (*.7z) | 374 // - Resource type 'B7', compressed using LZMA (*.7z) |
| 374 // - Resource type 'BL', compressed using LZ (*.ex_) | 375 // - Resource type 'BL', compressed using LZ (*.ex_) |
| 375 // - Resource type 'BN', uncompressed (*.exe) | 376 // - Resource type 'BN', uncompressed (*.exe) |
| 376 // If setup.exe is present in more than one form, the precedence order is | 377 // If setup.exe is present in more than one form, the precedence order is |
| 377 // BN < BL < B7 | 378 // BN < BL < B7 |
| 378 // For more details see chrome/tools/build/win/create_installer_archive.py. | 379 // For more details see chrome/tools/build/win/create_installer_archive.py. |
| 379 bool UnpackBinaryResources(const Configuration& configuration, HMODULE module, | 380 bool UnpackBinaryResources(const Configuration& configuration, HMODULE module, |
| 380 const wchar_t* base_path, PathString* archive_path, | 381 const wchar_t* base_path, PathString* archive_path, |
| 381 PathString* setup_path) { | 382 PathString* setup_path) { |
| 382 // Generate the setup.exe path where we patch/uncompress setup resource. | 383 // Generate the setup.exe path where we patch/uncompress setup resource. |
| 383 PathString setup_dest_path; | 384 PathString setup_dest_path; |
| 384 if (!setup_dest_path.assign(base_path) || | 385 if (!setup_dest_path.assign(base_path) || |
| 385 !setup_dest_path.append(kSetupName)) | 386 !setup_dest_path.append(kSetupExe)) |
| 386 return false; | 387 return false; |
| 387 | 388 |
| 388 // Prepare the input to OnResourceFound method that needs a location where | 389 // Prepare the input to OnResourceFound method that needs a location where |
| 389 // it will write all the resources. | 390 // it will write all the resources. |
| 390 Context context = { | 391 Context context = { |
| 391 base_path, | 392 base_path, |
| 392 archive_path, | 393 archive_path, |
| 393 setup_path, | 394 setup_path, |
| 394 }; | 395 }; |
| 395 | 396 |
| 396 // Get the resources of type 'B7' (7zip archive). | 397 // Get the resources of type 'B7' (7zip archive). |
| 397 // We need a chrome archive to do the installation. So if there | 398 // We need a chrome archive to do the installation. So if there |
| 398 // is a problem in fetching B7 resource, just return an error. | 399 // is a problem in fetching B7 resource, just return an error. |
| 399 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 400 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
| 400 reinterpret_cast<LONG_PTR>(&context)) || | 401 reinterpret_cast<LONG_PTR>(&context)) || |
| 401 archive_path->length() == 0) | 402 archive_path->length() == 0) |
| 402 return false; | 403 return false; |
| 403 | 404 |
| 404 // If we found setup 'B7' resource, handle it. | 405 // If we found setup 'B7' resource, handle it. |
| 405 if (setup_path->length() > 0) { | 406 if (setup_path->length() > 0) { |
| 406 CommandString cmd_line; | 407 CommandString cmd_line; |
| 407 // Get the path to setup.exe first. | 408 // Get the path to setup.exe first. |
| 408 bool success = true; | 409 bool success = true; |
| 409 if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), | 410 if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), |
| 410 cmd_line.capacity()) || | 411 cmd_line.capacity()) || |
| 412 !cmd_line.append(L" --") || |
| 411 !cmd_line.append(kCmdUpdateSetupExe) || | 413 !cmd_line.append(kCmdUpdateSetupExe) || |
| 412 !cmd_line.append(L"=\"") || | 414 !cmd_line.append(L"=\"") || |
| 413 !cmd_line.append(setup_path->get()) || | 415 !cmd_line.append(setup_path->get()) || |
| 414 !cmd_line.append(L"\"") || | 416 !cmd_line.append(L"\" --") || |
| 415 !cmd_line.append(kCmdNewSetupExe) || | 417 !cmd_line.append(kCmdNewSetupExe) || |
| 416 !cmd_line.append(L"=\"") || | 418 !cmd_line.append(L"=\"") || |
| 417 !cmd_line.append(setup_dest_path.get()) || | 419 !cmd_line.append(setup_dest_path.get()) || |
| 418 !cmd_line.append(L"\"")) { | 420 !cmd_line.append(L"\"")) { |
| 419 success = false; | 421 success = false; |
| 420 } | 422 } |
| 421 | 423 |
| 422 // Get any command line option specified for mini_installer and pass them | 424 // Get any command line option specified for mini_installer and pass them |
| 423 // on to setup.exe. This is important since switches such as | 425 // on to setup.exe. This is important since switches such as |
| 424 // --multi-install and --chrome-frame affect where setup.exe will write | 426 // --multi-install and --chrome-frame affect where setup.exe will write |
| 425 // installer results for consumption by Google Update. | 427 // installer results for consumption by Google Update. |
| 426 AppendCommandLineFlags(configuration, &cmd_line); | 428 AppendCommandLineFlags(configuration, &cmd_line); |
| 427 | 429 |
| 428 int exit_code = 0; | 430 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; |
| 429 if (success && | 431 if (success && |
| 430 (!RunProcessAndWait(NULL, cmd_line.get(), &exit_code) || | 432 (!RunProcessAndWait(NULL, cmd_line.get(), &exit_code) || |
| 431 exit_code != ERROR_SUCCESS)) { | 433 exit_code != SUCCESS_EXIT_CODE)) { |
| 432 success = false; | 434 success = false; |
| 433 } | 435 } |
| 434 | 436 |
| 435 if (!success) | 437 if (!success) |
| 436 DeleteFile(setup_path->get()); | 438 DeleteFile(setup_path->get()); |
| 437 | 439 |
| 438 return success && setup_path->assign(setup_dest_path.get()); | 440 return success && setup_path->assign(setup_dest_path.get()); |
| 439 } | 441 } |
| 440 | 442 |
| 441 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 443 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 ::DeleteFile(setup_dest_path.get()); | 482 ::DeleteFile(setup_dest_path.get()); |
| 481 } | 483 } |
| 482 } | 484 } |
| 483 } | 485 } |
| 484 | 486 |
| 485 return setup_path->length() > 0; | 487 return setup_path->length() > 0; |
| 486 } | 488 } |
| 487 | 489 |
| 488 // Executes setup.exe, waits for it to finish and returns the exit code. | 490 // Executes setup.exe, waits for it to finish and returns the exit code. |
| 489 bool RunSetup(const Configuration& configuration, const wchar_t* archive_path, | 491 bool RunSetup(const Configuration& configuration, const wchar_t* archive_path, |
| 490 const wchar_t* setup_path, int* exit_code) { | 492 const wchar_t* setup_path, ProcessExitCode* exit_code) { |
| 491 // There could be three full paths in the command line for setup.exe (path | 493 // There could be three full paths in the command line for setup.exe (path |
| 492 // to exe itself, path to archive and path to log file), so we declare | 494 // to exe itself, path to archive and path to log file), so we declare |
| 493 // total size as three + one additional to hold command line options. | 495 // total size as three + one additional to hold command line options. |
| 494 CommandString cmd_line; | 496 CommandString cmd_line; |
| 495 | 497 |
| 496 // Get the path to setup.exe first. | 498 // Get the path to setup.exe first. |
| 497 if (::lstrlen(setup_path) > 0) { | 499 if (::lstrlen(setup_path) > 0) { |
| 498 if (!cmd_line.assign(L"\"") || | 500 if (!cmd_line.assign(L"\"") || |
| 499 !cmd_line.append(setup_path) || | 501 !cmd_line.append(setup_path) || |
| 500 !cmd_line.append(L"\"")) | 502 !cmd_line.append(L"\"")) |
| 501 return false; | 503 return false; |
| 502 } else if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), | 504 } else if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), |
| 503 cmd_line.capacity())) { | 505 cmd_line.capacity())) { |
| 504 return false; | 506 return false; |
| 505 } | 507 } |
| 506 | 508 |
| 507 // Append the command line param for chrome archive file | 509 // Append the command line param for chrome archive file |
| 508 if (!cmd_line.append(kCmdInstallArchive) || | 510 if (!cmd_line.append(L" --") || |
| 511 !cmd_line.append(kCmdInstallArchive) || |
| 509 !cmd_line.append(L"=\"") || | 512 !cmd_line.append(L"=\"") || |
| 510 !cmd_line.append(archive_path) || | 513 !cmd_line.append(archive_path) || |
| 511 !cmd_line.append(L"\"")) | 514 !cmd_line.append(L"\"")) |
| 512 return false; | 515 return false; |
| 513 | 516 |
| 514 // Get any command line option specified for mini_installer and pass them | 517 // Get any command line option specified for mini_installer and pass them |
| 515 // on to setup.exe | 518 // on to setup.exe |
| 516 AppendCommandLineFlags(configuration, &cmd_line); | 519 AppendCommandLineFlags(configuration, &cmd_line); |
| 517 | 520 |
| 518 return RunProcessAndWait(NULL, cmd_line.get(), exit_code); | 521 return RunProcessAndWait(NULL, cmd_line.get(), exit_code); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 for (int i = 0; i < arraysize(kDirectoryPrefixes); ++i) { | 710 for (int i = 0; i < arraysize(kDirectoryPrefixes); ++i) { |
| 708 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); | 711 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); |
| 709 } | 712 } |
| 710 } | 713 } |
| 711 | 714 |
| 712 // Checks the command line for specific mini installer flags. | 715 // Checks the command line for specific mini installer flags. |
| 713 // If the function returns true, the command line has been processed and all | 716 // If the function returns true, the command line has been processed and all |
| 714 // required actions taken. The installer must exit and return the returned | 717 // required actions taken. The installer must exit and return the returned |
| 715 // |exit_code|. | 718 // |exit_code|. |
| 716 bool ProcessNonInstallOperations(const Configuration& configuration, | 719 bool ProcessNonInstallOperations(const Configuration& configuration, |
| 717 int* exit_code) { | 720 ProcessExitCode* exit_code) { |
| 718 bool ret = false; | 721 bool ret = false; |
| 719 | 722 |
| 720 switch (configuration.operation()) { | 723 switch (configuration.operation()) { |
| 721 case Configuration::CLEANUP: | 724 case Configuration::CLEANUP: |
| 722 // Cleanup has already taken place in DeleteOldChromeTempDirectories at | 725 // Cleanup has already taken place in DeleteOldChromeTempDirectories at |
| 723 // this point, so just tell our caller to exit early. | 726 // this point, so just tell our caller to exit early. |
| 724 *exit_code = 0; | 727 *exit_code = SUCCESS_EXIT_CODE; |
| 725 ret = true; | 728 ret = true; |
| 726 break; | 729 break; |
| 727 | 730 |
| 728 default: break; | 731 default: break; |
| 729 } | 732 } |
| 730 | 733 |
| 731 return ret; | 734 return ret; |
| 732 } | 735 } |
| 733 | 736 |
| 734 // Returns true if we should delete the temp files we create (default). | 737 // Returns true if we should delete the temp files we create (default). |
| 735 // Returns false iff the user has manually created a ChromeInstallerCleanup | 738 // Returns false iff the user has manually created a ChromeInstallerCleanup |
| 736 // string value in the registry under HKCU\\Software\\[Google|Chromium] | 739 // string value in the registry under HKCU\\Software\\[Google|Chromium] |
| 737 // and set its value to "0". That explicitly forbids the mini installer from | 740 // and set its value to "0". That explicitly forbids the mini installer from |
| 738 // deleting these files. | 741 // deleting these files. |
| 739 // Support for this has been publicly mentioned in troubleshooting tips so | 742 // Support for this has been publicly mentioned in troubleshooting tips so |
| 740 // we continue to support it. | 743 // we continue to support it. |
| 741 bool ShouldDeleteExtractedFiles() { | 744 bool ShouldDeleteExtractedFiles() { |
| 742 wchar_t value[2] = {0}; | 745 wchar_t value[2] = {0}; |
| 743 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 746 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
| 744 kCleanupRegistryValueName, value, | 747 kCleanupRegistryValue, value, arraysize(value)) && |
| 745 arraysize(value)) && | |
| 746 value[0] == L'0') { | 748 value[0] == L'0') { |
| 747 return false; | 749 return false; |
| 748 } | 750 } |
| 749 | 751 |
| 750 return true; | 752 return true; |
| 751 } | 753 } |
| 752 | 754 |
| 753 // Main function. First gets a working dir, unpacks the resources and finally | 755 // Main function. First gets a working dir, unpacks the resources and finally |
| 754 // executes setup.exe to do the install/upgrade. | 756 // executes setup.exe to do the install/upgrade. |
| 755 int WMain(HMODULE module) { | 757 ProcessExitCode WMain(HMODULE module) { |
| 756 #if defined(COMPONENT_BUILD) | 758 #if defined(COMPONENT_BUILD) |
| 757 if (::GetEnvironmentVariable(L"MINI_INSTALLER_TEST", NULL, 0) == 0) { | 759 if (::GetEnvironmentVariable(L"MINI_INSTALLER_TEST", NULL, 0) == 0) { |
| 758 static const wchar_t kComponentBuildIncompatibleMessage[] = | 760 static const wchar_t kComponentBuildIncompatibleMessage[] = |
| 759 L"mini_installer.exe is incompatible with the component build, please" | 761 L"mini_installer.exe is incompatible with the component build, please" |
| 760 L" run setup.exe with the same command line instead. See" | 762 L" run setup.exe with the same command line instead. See" |
| 761 L" http://crbug.com/127233#c17 for details."; | 763 L" http://crbug.com/127233#c17 for details."; |
| 762 ::MessageBox(NULL, kComponentBuildIncompatibleMessage, NULL, MB_ICONERROR); | 764 ::MessageBox(NULL, kComponentBuildIncompatibleMessage, NULL, MB_ICONERROR); |
| 763 return 1; | 765 return GENERIC_ERROR; |
| 764 } | 766 } |
| 765 #endif | 767 #endif |
| 766 | 768 |
| 767 // Always start with deleting potential leftovers from previous installations. | 769 // Always start with deleting potential leftovers from previous installations. |
| 768 // This can make the difference between success and failure. We've seen | 770 // This can make the difference between success and failure. We've seen |
| 769 // many installations out in the field fail due to out of disk space problems | 771 // many installations out in the field fail due to out of disk space problems |
| 770 // so this could buy us some space. | 772 // so this could buy us some space. |
| 771 DeleteOldChromeTempDirectories(); | 773 DeleteOldChromeTempDirectories(); |
| 772 | 774 |
| 773 // TODO(grt): Make the exit codes more granular so we know where the popular | 775 // TODO(grt): Make the exit codes more granular so we know where the popular |
| 774 // errors truly are. | 776 // errors truly are. |
| 775 int exit_code = 101; | 777 ProcessExitCode exit_code = GENERIC_INITIALIZATION_FAILURE; |
| 776 | 778 |
| 777 // Parse the command line. | 779 // Parse the command line. |
| 778 Configuration configuration; | 780 Configuration configuration; |
| 779 if (!configuration.Initialize()) | 781 if (!configuration.Initialize()) |
| 780 return exit_code; | 782 return exit_code; |
| 781 | 783 |
| 782 if (configuration.query_component_build()) { | 784 if (configuration.query_component_build()) { |
| 783 // Exit immediately with an exit code of 1 to indicate component build and 0 | 785 // Exit immediately with a generic success exit code (0) to indicate |
| 784 // to indicate static build. This is used by the tests in | 786 // component build and a generic failure exit code (1) to indicate static |
| 785 // /src/chrome/test/mini_installer/. | 787 // build. This is used by the tests in /src/chrome/test/mini_installer/. |
| 786 #if defined(COMPONENT_BUILD) | 788 #if defined(COMPONENT_BUILD) |
| 787 return 1; | 789 return SUCCESS_EXIT_CODE; |
| 788 #else | 790 #else |
| 789 return 0; | 791 return GENERIC_ERROR; |
| 790 #endif | 792 #endif |
| 791 } | 793 } |
| 792 | 794 |
| 793 // If the --cleanup switch was specified on the command line, then that means | 795 // If the --cleanup switch was specified on the command line, then that means |
| 794 // we should only do the cleanup and then exit. | 796 // we should only do the cleanup and then exit. |
| 795 if (ProcessNonInstallOperations(configuration, &exit_code)) | 797 if (ProcessNonInstallOperations(configuration, &exit_code)) |
| 796 return exit_code; | 798 return exit_code; |
| 797 | 799 |
| 798 // First get a path where we can extract payload | 800 // First get a path where we can extract payload |
| 799 PathString base_path; | 801 PathString base_path; |
| 800 if (!GetWorkDir(module, &base_path)) | 802 if (!GetWorkDir(module, &base_path)) |
| 801 return 101; | 803 return GENERIC_INITIALIZATION_FAILURE; |
| 802 | 804 |
| 803 #if defined(GOOGLE_CHROME_BUILD) | 805 #if defined(GOOGLE_CHROME_BUILD) |
| 804 // Set the magic suffix in registry to try full installer next time. We ignore | 806 // Set the magic suffix in registry to try full installer next time. We ignore |
| 805 // any errors here and we try to set the suffix for user level unless | 807 // any errors here and we try to set the suffix for user level unless |
| 806 // --system-level is on the command line in which case we set it for system | 808 // --system-level is on the command line in which case we set it for system |
| 807 // level instead. This only applies to the Google Chrome distribution. | 809 // level instead. This only applies to the Google Chrome distribution. |
| 808 SetInstallerFlags(configuration); | 810 SetInstallerFlags(configuration); |
| 809 #endif | 811 #endif |
| 810 | 812 |
| 811 PathString archive_path; | 813 PathString archive_path; |
| 812 PathString setup_path; | 814 PathString setup_path; |
| 813 if (!UnpackBinaryResources(configuration, module, base_path.get(), | 815 if (!UnpackBinaryResources(configuration, module, base_path.get(), |
| 814 &archive_path, &setup_path)) { | 816 &archive_path, &setup_path)) { |
| 815 exit_code = 102; | 817 exit_code = GENERIC_UNPACKING_FAILURE; |
| 816 } else { | 818 } else { |
| 817 // While unpacking the binaries, we paged in a whole bunch of memory that | 819 // While unpacking the binaries, we paged in a whole bunch of memory that |
| 818 // we don't need anymore. Let's give it back to the pool before running | 820 // we don't need anymore. Let's give it back to the pool before running |
| 819 // setup. | 821 // setup. |
| 820 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); | 822 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); |
| 821 if (!RunSetup(configuration, archive_path.get(), setup_path.get(), | 823 if (!RunSetup(configuration, archive_path.get(), setup_path.get(), |
| 822 &exit_code)) { | 824 &exit_code)) { |
| 823 exit_code = 103; | 825 exit_code = GENERIC_SETUP_FAILURE; |
| 824 } | 826 } |
| 825 } | 827 } |
| 826 | 828 |
| 827 if (ShouldDeleteExtractedFiles()) | 829 if (ShouldDeleteExtractedFiles()) |
| 828 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 830 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
| 829 | 831 |
| 830 return exit_code; | 832 return exit_code; |
| 831 } | 833 } |
| 832 | 834 |
| 833 } // namespace mini_installer | 835 } // namespace mini_installer |
| 834 | 836 |
| 835 int MainEntryPoint() { | 837 int MainEntryPoint() { |
| 836 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 838 mini_installer::ProcessExitCode result = |
| 839 mini_installer::WMain(::GetModuleHandle(NULL)); |
| 837 ::ExitProcess(result); | 840 ::ExitProcess(result); |
| 838 } | 841 } |
| 839 | 842 |
| 840 // VC Express editions don't come with the memset CRT obj file and linking to | 843 // VC Express editions don't come with the memset CRT obj file and linking to |
| 841 // the obj files between versions becomes a bit problematic. Therefore, | 844 // the obj files between versions becomes a bit problematic. Therefore, |
| 842 // simply implement memset. | 845 // simply implement memset. |
| 843 // | 846 // |
| 844 // This also avoids having to explicitly set the __sse2_available hack when | 847 // This also avoids having to explicitly set the __sse2_available hack when |
| 845 // linking with both the x64 and x86 obj files which is required when not | 848 // linking with both the x64 and x86 obj files which is required when not |
| 846 // linking with the std C lib in certain instances (including Chromium) with | 849 // linking with the std C lib in certain instances (including Chromium) with |
| 847 // MSVC. __sse2_available determines whether to use SSE2 intructions with | 850 // MSVC. __sse2_available determines whether to use SSE2 intructions with |
| 848 // std C lib routines, and is set by MSVC's std C lib implementation normally. | 851 // std C lib routines, and is set by MSVC's std C lib implementation normally. |
| 849 extern "C" { | 852 extern "C" { |
| 850 #pragma function(memset) | 853 #pragma function(memset) |
| 851 void* memset(void* dest, int c, size_t count) { | 854 void* memset(void* dest, int c, size_t count) { |
| 852 void* start = dest; | 855 void* start = dest; |
| 853 while (count--) { | 856 while (count--) { |
| 854 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 857 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
| 855 dest = reinterpret_cast<char*>(dest) + 1; | 858 dest = reinterpret_cast<char*>(dest) + 1; |
| 856 } | 859 } |
| 857 return start; | 860 return start; |
| 858 } | 861 } |
| 859 } // extern "C" | 862 } // extern "C" |
| OLD | NEW |