| 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 |