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