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 |