OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 appropiate flags. | 9 // 2) run the real installer (setup.exe) with appropiate flags. |
10 // | 10 // |
(...skipping 11 matching lines...) Expand all Loading... |
22 // object files that exist in $(VCInstallDir)\crt\src which are memset.obj and | 22 // object files that exist in $(VCInstallDir)\crt\src which are memset.obj and |
23 // P4_memset.obj. These two object files rely on the existence of a static | 23 // P4_memset.obj. These two object files rely on the existence of a static |
24 // variable named __sse2_available which indicates the presence of intel sse2 | 24 // variable named __sse2_available which indicates the presence of intel sse2 |
25 // extensions. We define it to false which causes a slower but safe code for | 25 // extensions. We define it to false which causes a slower but safe code for |
26 // memcpy and memset intrinsics. | 26 // memcpy and memset intrinsics. |
27 | 27 |
28 // having the linker merge the sections is saving us ~500 bytes. | 28 // having the linker merge the sections is saving us ~500 bytes. |
29 #pragma comment(linker, "/MERGE:.rdata=.text") | 29 #pragma comment(linker, "/MERGE:.rdata=.text") |
30 | 30 |
31 #include <windows.h> | 31 #include <windows.h> |
| 32 #include <Shellapi.h> |
32 #include <shlwapi.h> | 33 #include <shlwapi.h> |
33 #include <stdlib.h> | 34 #include <stdlib.h> |
34 | 35 |
35 #include "chrome/installer/mini_installer/mini_installer.h" | 36 #include "chrome/installer/mini_installer/mini_installer.h" |
36 #include "chrome/installer/mini_installer/pe_resource.h" | 37 #include "chrome/installer/mini_installer/pe_resource.h" |
37 | 38 |
38 // Required linker symbol. See remarks above. | 39 // Required linker symbol. See remarks above. |
39 extern "C" unsigned int __sse2_available = 0; | 40 extern "C" unsigned int __sse2_available = 0; |
40 | 41 |
41 namespace mini_installer { | 42 namespace mini_installer { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 bool SafeStrCopy(wchar_t* dest, const wchar_t* src, size_t dest_size) { | 84 bool SafeStrCopy(wchar_t* dest, const wchar_t* src, size_t dest_size) { |
84 for (size_t length = 0; length < dest_size; ++dest, ++src, ++length) { | 85 for (size_t length = 0; length < dest_size; ++dest, ++src, ++length) { |
85 *dest = *src; | 86 *dest = *src; |
86 if (L'\0' == *src) { | 87 if (L'\0' == *src) { |
87 return true; | 88 return true; |
88 } | 89 } |
89 } | 90 } |
90 return false; | 91 return false; |
91 } | 92 } |
92 | 93 |
| 94 // Function to check if a string (specified by str) ends with another string |
| 95 // (specified by end_str). |
| 96 bool StrEndsWith(wchar_t *str, wchar_t *end_str) { |
| 97 if (str == NULL || end_str == NULL || lstrlen(str) < lstrlen(end_str)) |
| 98 return false; |
| 99 |
| 100 for (int i = lstrlen(str) - 1, j = lstrlen(end_str) - 1; j >= 0; --i, --j) { |
| 101 if (str[i] != end_str[j]) |
| 102 return false; |
| 103 } |
| 104 |
| 105 return true; |
| 106 } |
93 | 107 |
94 // Helper function to read a value from registry. Returns true if value | 108 // Helper function to read a value from registry. Returns true if value |
95 // is read successfully and stored in parameter value. Returns false otherwise. | 109 // is read successfully and stored in parameter value. Returns false otherwise. |
96 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 110 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
97 const wchar_t *value_name, wchar_t *value, | 111 const wchar_t *value_name, wchar_t *value, |
98 size_t size) { | 112 size_t size) { |
99 HKEY key; | 113 HKEY key; |
100 | 114 |
101 if ((::RegOpenKeyEx(root_key, sub_key, NULL, | 115 if ((::RegOpenKeyEx(root_key, sub_key, NULL, |
102 KEY_READ, &key) == ERROR_SUCCESS) && | 116 KEY_READ, &key) == ERROR_SUCCESS) && |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 if (::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { | 261 if (::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
248 return false; | 262 return false; |
249 } | 263 } |
250 } else if (0 == ::lstrcmpiW(name, kSetupName)) { | 264 } else if (0 == ::lstrcmpiW(name, kSetupName)) { |
251 *unpacked_setup = true; | 265 *unpacked_setup = true; |
252 } | 266 } |
253 | 267 |
254 return true; | 268 return true; |
255 } | 269 } |
256 | 270 |
| 271 // Append any command line params passed to mini_installer to the given buffer |
| 272 // so that they can be passed on to setup.exe. We do not return any error from |
| 273 // this method and simply skip making any changes in case of error. |
| 274 void AppendCommandLineFlags(wchar_t* buffer, int size) { |
| 275 int args_num; |
| 276 wchar_t** args = ::CommandLineToArgvW(::GetCommandLine(), &args_num); |
| 277 if (args_num <= 0) |
| 278 return; |
| 279 |
| 280 wchar_t full_exe_path[MAX_PATH]; |
| 281 int len = ::GetModuleFileNameW(NULL, full_exe_path, MAX_PATH); |
| 282 if (len <= 0 && len >= MAX_PATH) |
| 283 return; |
| 284 |
| 285 wchar_t* exe_name = GetNameFromPathExt(full_exe_path, len); |
| 286 if (exe_name == NULL) |
| 287 return; |
| 288 |
| 289 int start = 1; |
| 290 if (args_num > 0 && !StrEndsWith(args[0], exe_name)) |
| 291 start = 0; |
| 292 |
| 293 for (int i = start; i < args_num; ++i) { |
| 294 if (size < lstrlen(args[i]) + 1) |
| 295 break; |
| 296 |
| 297 ::lstrcat(buffer, L" "); |
| 298 ::lstrcat(buffer, args[i]); |
| 299 size = size - (lstrlen(args[i]) + 1); |
| 300 } |
| 301 LocalFree(args); |
| 302 } |
257 | 303 |
258 // Executes setup.exe, waits for it to finish and returns the exit code. | 304 // Executes setup.exe, waits for it to finish and returns the exit code. |
259 bool RunSetup(bool have_upacked_setup, const wchar_t* base_path, | 305 bool RunSetup(bool have_upacked_setup, const wchar_t* base_path, |
260 const wchar_t* archive_name, int* exit_code) { | 306 const wchar_t* archive_name, int* exit_code) { |
261 wchar_t cmd_line[MAX_PATH * 2]; | 307 // There could be three full paths in the command line for setup.exe (path |
262 wchar_t cmd_args[MAX_PATH * 2]; | 308 // to exe itself, path to archive and path to log file), so we declare |
| 309 // total size as three + one additional to hold command line options. |
| 310 wchar_t cmd_line[MAX_PATH * 4]; |
263 | 311 |
264 if (!SafeStrCopy(cmd_args, L" --install-archive=\"", _countof(cmd_args)) || | 312 // Get the path to setup.exe first. |
265 !::lstrcat(cmd_args, base_path) || | |
266 !::lstrcat(cmd_args, archive_name) || | |
267 !::lstrcat(cmd_args, L"\"")) { | |
268 return false; | |
269 } | |
270 | |
271 if (have_upacked_setup) { | 313 if (have_upacked_setup) { |
272 if (!SafeStrCopy(cmd_line, L"\"", _countof(cmd_line)) || | 314 if (!SafeStrCopy(cmd_line, L"\"", _countof(cmd_line)) || |
273 !::lstrcat(cmd_line, base_path) || | 315 !::lstrcat(cmd_line, base_path) || |
274 !::lstrcat(cmd_line, kSetupName) || | 316 !::lstrcat(cmd_line, kSetupName) || |
275 !::lstrcat(cmd_line, L"\"")) { | 317 !::lstrcat(cmd_line, L"\"")) { |
276 return false; | 318 return false; |
277 } | 319 } |
278 } else { | 320 } else { |
279 if (!GetSetupExePathFromRegistry(cmd_line, sizeof(cmd_line))) { | 321 if (!GetSetupExePathFromRegistry(cmd_line, sizeof(cmd_line))) { |
280 return false; | 322 return false; |
281 } | 323 } |
282 } | 324 } |
283 | 325 |
284 return (::lstrcat(cmd_line, cmd_args) && | 326 // Append the command line param for chrome archive file |
285 RunProcessAndWait(NULL, cmd_line, exit_code)); | 327 if (!::lstrcat(cmd_line, L" --install-archive=\"") || |
| 328 !::lstrcat(cmd_line, base_path) || |
| 329 !::lstrcat(cmd_line, archive_name) || |
| 330 !::lstrcat(cmd_line, L"\"")) { |
| 331 return false; |
| 332 } |
| 333 |
| 334 // Get any command line option specified for mini_installer and pass them |
| 335 // on to setup.exe |
| 336 AppendCommandLineFlags(cmd_line, _countof(cmd_line) - lstrlen(cmd_line)); |
| 337 |
| 338 return (RunProcessAndWait(NULL, cmd_line, exit_code)); |
286 } | 339 } |
287 | 340 |
288 | 341 |
289 void DeleteExtractedFiles(const wchar_t* base_path, | 342 void DeleteExtractedFiles(const wchar_t* base_path, |
290 const wchar_t* archive_name) { | 343 const wchar_t* archive_name) { |
291 wchar_t file_path[MAX_PATH]; | 344 wchar_t file_path[MAX_PATH]; |
292 // Delete setup.exe. | 345 // Delete setup.exe. |
293 SafeStrCopy(file_path, base_path, MAX_PATH); | 346 SafeStrCopy(file_path, base_path, MAX_PATH); |
294 ::lstrcat(file_path, kSetupName); | 347 ::lstrcat(file_path, kSetupName); |
295 ::DeleteFile(file_path); | 348 ::DeleteFile(file_path); |
(...skipping 12 matching lines...) Expand all Loading... |
308 DWORD len = ::GetTempPath(MAX_PATH, base_path); | 361 DWORD len = ::GetTempPath(MAX_PATH, base_path); |
309 if (len >= MAX_PATH || len <= 0) { | 362 if (len >= MAX_PATH || len <= 0) { |
310 // Problem in getting TEMP path so just use current directory as base path | 363 // Problem in getting TEMP path so just use current directory as base path |
311 len = ::GetModuleFileNameW(module, base_path, MAX_PATH); | 364 len = ::GetModuleFileNameW(module, base_path, MAX_PATH); |
312 if (len >= MAX_PATH || len <= 0) | 365 if (len >= MAX_PATH || len <= 0) |
313 return false; // Can't even get current directory? Return with error. | 366 return false; // Can't even get current directory? Return with error. |
314 wchar_t* name = GetNameFromPathExt(base_path, len); | 367 wchar_t* name = GetNameFromPathExt(base_path, len); |
315 *name = L'\0'; | 368 *name = L'\0'; |
316 } | 369 } |
317 | 370 |
318 wchar_t temp_name[MAX_PATH + 1]; | 371 wchar_t temp_name[MAX_PATH]; |
319 if (!GetTempFileName(base_path, L"CR_", 0, temp_name)) | 372 if (!GetTempFileName(base_path, L"CR_", 0, temp_name)) |
320 return false; // Didn't get any temp name to use. Return error. | 373 return false; // Didn't get any temp name to use. Return error. |
321 len = GetLongPathName(temp_name, work_dir, MAX_PATH); | 374 len = GetLongPathName(temp_name, work_dir, MAX_PATH); |
322 if (len > MAX_PATH + 1 || len == 0) | 375 if (len >= MAX_PATH || len <= 0) |
323 return false; // Couldn't get full path to temp dir. Return error. | 376 return false; // Couldn't get full path to temp dir. Return error. |
324 | 377 |
325 // GetTempFileName creates the file as well so delete it before creating | 378 // GetTempFileName creates the file as well so delete it before creating |
326 // the directory in its place. | 379 // the directory in its place. |
327 if (!::DeleteFile(work_dir) || !::CreateDirectory(work_dir, NULL)) | 380 if (!::DeleteFile(work_dir) || !::CreateDirectory(work_dir, NULL)) |
328 return false; // What's the use of temp dir if we can not create it? | 381 return false; // What's the use of temp dir if we can not create it? |
329 ::lstrcat(work_dir, L"\\"); | 382 ::lstrcat(work_dir, L"\\"); |
330 return true; | 383 return true; |
331 } | 384 } |
332 | 385 |
333 int WMain(HMODULE module) { | 386 int WMain(HMODULE module) { |
334 // First get a path where we can extract payload | 387 // First get a path where we can extract payload |
335 wchar_t base_path[MAX_PATH]; | 388 wchar_t base_path[MAX_PATH]; |
336 if (!GetWorkDir(module, base_path)) | 389 if (!GetWorkDir(module, base_path)) |
337 return 1; | 390 return 101; |
338 | 391 |
339 wchar_t archive_name[MAX_PATH]; | 392 wchar_t archive_name[MAX_PATH]; // len(archive_name) < MAX_PATH-len(base_path) |
340 bool have_upacked_setup; | 393 bool have_upacked_setup; |
341 if (!UnpackBinaryResources(module, base_path, | 394 if (!UnpackBinaryResources(module, base_path, |
342 &have_upacked_setup, archive_name)) { | 395 &have_upacked_setup, archive_name)) { |
343 return 1; | 396 return 102; |
344 } | 397 } |
345 | 398 |
346 int setup_exit_code = 2; | 399 int setup_exit_code = 103; |
347 if (!RunSetup(have_upacked_setup, base_path, | 400 if (!RunSetup(have_upacked_setup, base_path, |
348 archive_name, &setup_exit_code)) { | 401 archive_name, &setup_exit_code)) { |
349 return setup_exit_code; | 402 return setup_exit_code; |
350 } | 403 } |
351 | 404 |
352 wchar_t value[4]; | 405 wchar_t value[4]; |
353 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 406 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
354 kCleanupRegistryValueName, value, 4)) || | 407 kCleanupRegistryValueName, value, 4)) || |
355 (value[0] != L'0')) { | 408 (value[0] != L'0')) { |
356 DeleteExtractedFiles(base_path, archive_name); | 409 DeleteExtractedFiles(base_path, archive_name); |
357 } | 410 } |
358 | 411 |
359 return setup_exit_code; | 412 return setup_exit_code; |
360 } | 413 } |
361 } // namespace mini_installer | 414 } // namespace mini_installer |
362 | 415 |
363 | 416 |
364 int MainEntryPoint() { | 417 int MainEntryPoint() { |
365 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 418 int result = mini_installer::WMain(::GetModuleHandle(NULL)); |
366 ::ExitProcess(result); | 419 ::ExitProcess(result); |
367 } | 420 } |
368 | 421 |
OLD | NEW |