Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #include "chrome/install_static/install_util.h" | 5 #include "chrome/install_static/install_util.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <assert.h> | 8 #include <assert.h> |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <iostream> | 10 #include <iostream> |
| 11 #include <iterator> | 11 #include <iterator> |
| 12 #include <memory> | 12 #include <memory> |
| 13 #include <sstream> | 13 #include <sstream> |
| 14 | 14 |
| 15 #include "chrome/install_static/policy_path_parser.h" | |
| 15 #include "chrome_elf/nt_registry/nt_registry.h" | 16 #include "chrome_elf/nt_registry/nt_registry.h" |
| 16 | 17 |
| 17 namespace install_static { | 18 namespace install_static { |
| 18 | 19 |
| 19 ProcessType g_process_type = ProcessType::UNINITIALIZED; | 20 ProcessType g_process_type = ProcessType::UNINITIALIZED; |
| 20 | 21 |
| 21 // TODO(ananta) | 22 // TODO(ananta) |
| 22 // http://crbug.com/604923 | 23 // http://crbug.com/604923 |
| 23 // The constants defined in this file are also defined in chrome/installer and | 24 // The constants defined in this file are also defined in chrome/installer and |
| 24 // other places. we need to unify them. | 25 // other places. we need to unify them. |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 54 const wchar_t kAppGuidGoogleChrome[] = | 55 const wchar_t kAppGuidGoogleChrome[] = |
| 55 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | 56 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
| 56 const wchar_t kAppGuidGoogleBinaries[] = | 57 const wchar_t kAppGuidGoogleBinaries[] = |
| 57 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; | 58 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; |
| 58 | 59 |
| 59 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; | 60 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; |
| 60 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; | 61 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; |
| 61 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; | 62 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; |
| 62 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; | 63 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; |
| 63 | 64 |
| 64 const char kGpuProcess[] = "gpu-process"; | 65 const wchar_t kCrashpadHandler[] = L"crashpad-handler"; |
| 65 const char kPpapiPluginProcess[] = "ppapi"; | 66 const wchar_t kProcessType[] = L"type"; |
| 66 const char kRendererProcess[] = "renderer"; | 67 const wchar_t kUserDataDirSwitch[] = L"user-data-dir"; |
| 67 const char kUtilityProcess[] = "utility"; | 68 const wchar_t kUtilityProcess[] = L"utility"; |
| 68 const char kProcessType[] = "type"; | 69 |
| 69 const char kCrashpadHandler[] = "crashpad-handler"; | 70 #if defined(GOOGLE_CHROME_BUILD) |
| 71 const wchar_t kRegistryChromePolicyKey[] = | |
| 72 L"SOFTWARE\\Policies\\Google\\Chrome"; | |
| 73 #else | |
| 74 const wchar_t kRegistryChromePolicyKey[] = | |
| 75 L"SOFTWARE\\Policies\\Chromium"; | |
| 76 #endif | |
| 77 const wchar_t kUserDataDirRegKey[] = L"UserDataDir"; | |
| 70 | 78 |
| 71 namespace { | 79 namespace { |
| 72 | 80 |
| 73 // TODO(ananta) | 81 // TODO(ananta) |
| 74 // http://crbug.com/604923 | 82 // http://crbug.com/604923 |
| 75 // These constants are defined in the chrome/installer directory as well. We | 83 // These constants are defined in the chrome/installer directory as well. We |
| 76 // need to unify them. | 84 // need to unify them. |
| 77 #if defined(GOOGLE_CHROME_BUILD) | 85 #if defined(GOOGLE_CHROME_BUILD) |
| 78 const wchar_t kSxSSuffix[] = L" SxS"; | 86 const wchar_t kSxSSuffix[] = L" SxS"; |
| 79 const wchar_t kGoogleChromeInstallSubDir1[] = L"Google"; | 87 const wchar_t kGoogleChromeInstallSubDir1[] = L"Google"; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 } | 187 } |
| 180 | 188 |
| 181 // Returns the executable path for the current process. | 189 // Returns the executable path for the current process. |
| 182 std::wstring GetCurrentProcessExePath() { | 190 std::wstring GetCurrentProcessExePath() { |
| 183 wchar_t exe_path[MAX_PATH]; | 191 wchar_t exe_path[MAX_PATH]; |
| 184 if (::GetModuleFileName(nullptr, exe_path, MAX_PATH) == 0) | 192 if (::GetModuleFileName(nullptr, exe_path, MAX_PATH) == 0) |
| 185 return std::wstring(); | 193 return std::wstring(); |
| 186 return exe_path; | 194 return exe_path; |
| 187 } | 195 } |
| 188 | 196 |
| 197 std::wstring MakeAbsoluteFilePath(const std::wstring& input) { | |
| 198 wchar_t file_path[MAX_PATH]; | |
| 199 if (!_wfullpath(file_path, input.c_str(), MAX_PATH)) | |
| 200 return std::wstring(); | |
| 201 return file_path; | |
| 202 } | |
| 203 | |
| 204 bool DirectoryExists(const std::wstring& path) { | |
| 205 DWORD file_attributes = ::GetFileAttributes(path.c_str()); | |
| 206 if (file_attributes != INVALID_FILE_ATTRIBUTES) | |
| 207 return (file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 189 bool RecursiveDirectoryCreate(const std::wstring& full_path) { | 211 bool RecursiveDirectoryCreate(const std::wstring& full_path) { |
| 190 // If the path exists, we've succeeded if it's a directory, failed otherwise. | 212 // If the path exists, we've succeeded if it's a directory, failed otherwise. |
| 191 const wchar_t* full_path_str = full_path.c_str(); | 213 const wchar_t* full_path_str = full_path.c_str(); |
| 192 DWORD file_attributes = ::GetFileAttributes(full_path_str); | 214 DWORD file_attributes = ::GetFileAttributes(full_path_str); |
| 193 if (file_attributes != INVALID_FILE_ATTRIBUTES) { | 215 if (file_attributes != INVALID_FILE_ATTRIBUTES) { |
| 194 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 216 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 195 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); | 217 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); |
| 196 return true; | 218 return true; |
| 197 } | 219 } |
| 198 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, | 220 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 209 std::size_t pos = full_path.find_last_of(L"/\\"); | 231 std::size_t pos = full_path.find_last_of(L"/\\"); |
| 210 if (pos != std::wstring::npos) { | 232 if (pos != std::wstring::npos) { |
| 211 parent_path = full_path.substr(0, pos); | 233 parent_path = full_path.substr(0, pos); |
| 212 if (!RecursiveDirectoryCreate(parent_path)) { | 234 if (!RecursiveDirectoryCreate(parent_path)) { |
| 213 Trace(L"Failed to create one of the parent directories"); | 235 Trace(L"Failed to create one of the parent directories"); |
| 214 return false; | 236 return false; |
| 215 } | 237 } |
| 216 } | 238 } |
| 217 if (!::CreateDirectory(full_path_str, nullptr)) { | 239 if (!::CreateDirectory(full_path_str, nullptr)) { |
| 218 DWORD error_code = ::GetLastError(); | 240 DWORD error_code = ::GetLastError(); |
| 219 if (error_code == ERROR_ALREADY_EXISTS) { | 241 if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path_str)) { |
| 220 DWORD file_attributes = ::GetFileAttributes(full_path_str); | 242 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we |
| 221 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && | 243 // were racing with someone creating the same directory, or a file |
|
scottmg
2016/11/15 23:23:15
The "else" was at the wrong level (no error was re
| |
| 222 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { | 244 // with the same path. If the directory exists, we lost the |
| 223 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we | 245 // race to create the same directory. |
| 224 // were racing with someone creating the same directory, or a file | 246 return true; |
| 225 // with the same path. If the directory exists, we lost the | 247 } else { |
| 226 // race to create the same directory. | 248 Trace(L"Failed to create directory %ls, last error is %d\n", |
| 227 return true; | 249 full_path_str, error_code); |
| 228 } else { | 250 return false; |
| 229 Trace(L"Failed to create directory %ls, last error is %d\n", | |
| 230 full_path_str, error_code); | |
| 231 return false; | |
| 232 } | |
| 233 } | 251 } |
| 234 } | 252 } |
| 235 return true; | 253 return true; |
| 236 } | 254 } |
| 237 | 255 |
| 238 std::wstring GetChromeInstallRegistryPath() { | 256 std::wstring GetChromeInstallRegistryPath() { |
| 239 std::wstring registry_path = L"Software\\"; | 257 std::wstring registry_path = L"Software\\"; |
| 240 registry_path += GetChromeInstallSubDirectory(); | 258 registry_path += GetChromeInstallSubDirectory(); |
| 241 return registry_path; | 259 return registry_path; |
| 242 } | 260 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 std::vector<StringType> tokens; | 387 std::vector<StringType> tokens; |
| 370 std::basic_istringstream<typename StringType::value_type> buffer(str); | 388 std::basic_istringstream<typename StringType::value_type> buffer(str); |
| 371 for (StringType token; std::getline(buffer, token, delimiter);) { | 389 for (StringType token; std::getline(buffer, token, delimiter);) { |
| 372 if (trim_spaces) | 390 if (trim_spaces) |
| 373 TrimT<StringType>(&token); | 391 TrimT<StringType>(&token); |
| 374 tokens.push_back(token); | 392 tokens.push_back(token); |
| 375 } | 393 } |
| 376 return tokens; | 394 return tokens; |
| 377 } | 395 } |
| 378 | 396 |
| 397 // Checks if the key exists in the given hive and expands any string variables. | |
| 398 bool LoadUserDataDirPolicyFromRegistry(nt::ROOT_KEY hive, | |
| 399 const wchar_t* key_name, | |
| 400 std::wstring* dir) { | |
| 401 std::wstring value; | |
| 402 bool result = false; | |
| 403 HANDLE key; | |
| 404 if (nt::OpenRegKey(hive, kRegistryChromePolicyKey, KEY_READ, &key, nullptr)) { | |
| 405 if (nt::QueryRegValueSZ(key, key_name, &value)) { | |
| 406 *dir = install_static::ExpandPathVariables(value); | |
| 407 result = true; | |
| 408 } | |
| 409 nt::CloseRegKey(key); | |
| 410 } | |
| 411 return result; | |
| 412 } | |
| 413 | |
| 414 void CheckUserDataDirPolicy(std::wstring* user_data_dir) { | |
| 415 assert(user_data_dir); | |
| 416 // Policy from the HKLM hive has precedence over HKCU. | |
| 417 if (!LoadUserDataDirPolicyFromRegistry(nt::HKLM, kUserDataDirRegKey, | |
| 418 user_data_dir)) { | |
| 419 LoadUserDataDirPolicyFromRegistry(nt::HKCU, kUserDataDirRegKey, | |
| 420 user_data_dir); | |
| 421 } | |
| 422 } | |
| 423 | |
| 379 } // namespace | 424 } // namespace |
| 380 | 425 |
| 381 bool IsSxSChrome(const wchar_t* exe_path) { | 426 bool IsSxSChrome(const wchar_t* exe_path) { |
| 382 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr; | 427 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr; |
| 383 } | 428 } |
| 384 | 429 |
| 385 bool IsSystemInstall(const wchar_t* exe_path) { | 430 bool IsSystemInstall(const wchar_t* exe_path) { |
| 386 wchar_t program_dir[MAX_PATH] = {}; | 431 wchar_t program_dir[MAX_PATH] = {}; |
| 387 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); | 432 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); |
| 388 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) { | 433 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 | 569 |
| 525 *result = user_data_dir_path.get(); | 570 *result = user_data_dir_path.get(); |
| 526 if ((*result)[result->length() - 1] != L'\\') | 571 if ((*result)[result->length() - 1] != L'\\') |
| 527 result->append(L"\\"); | 572 result->append(L"\\"); |
| 528 result->append(install_sub_directory); | 573 result->append(install_sub_directory); |
| 529 result->append(L"\\"); | 574 result->append(L"\\"); |
| 530 result->append(kUserDataDirname); | 575 result->append(kUserDataDirname); |
| 531 return true; | 576 return true; |
| 532 } | 577 } |
| 533 | 578 |
| 534 bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { | 579 bool GetUserDataDirectory(const std::wstring& user_data_dir_from_command_line, |
| 535 // In order to be able to start crash handling very early, we do not rely on | 580 std::wstring* result) { |
| 536 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on | 581 // WARNING! This has to mirror the logic in chrome/app/chrome_main_delegate.cc |
| 537 // Windows. See https://crbug.com/564398. | 582 // in InitializeUserDataDir(). This function derives the path in the same way, |
| 538 if (!GetDefaultUserDataDirectory(crash_dir)) | 583 // but without using base, nor reporting on failure as the Chrome |
| 584 // implementation does. | |
| 585 std::wstring user_data_dir = user_data_dir_from_command_line; | |
| 586 | |
| 587 CheckUserDataDirPolicy(&user_data_dir); | |
| 588 | |
| 589 // On Windows, trailing separators leave Chrome in a bad state. See | |
| 590 // crbug.com/464616. | |
| 591 while (!user_data_dir.empty() && | |
| 592 (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) { | |
| 593 user_data_dir.pop_back(); | |
| 594 } | |
| 595 | |
| 596 bool have_valid_directory = | |
| 597 !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir); | |
| 598 | |
| 599 if (!have_valid_directory) { | |
| 600 if (!GetDefaultUserDataDirectory(&user_data_dir)) { | |
| 601 // The Chrome implementation CHECKs() here in the browser process. We | |
| 602 // don't as this function is used to initialize crash reporting, so | |
| 603 // we would get no report of this failure. | |
| 604 assert(false); | |
| 605 return false; | |
| 606 } | |
| 607 } | |
| 608 | |
| 609 *result = MakeAbsoluteFilePath(user_data_dir); | |
| 610 return true; | |
| 611 } | |
| 612 | |
| 613 bool GetUserDataDirectoryUsingProcessCommandLine(std::wstring* result) { | |
| 614 return GetUserDataDirectory( | |
| 615 GetSwitchValueFromCommandLine(::GetCommandLine(), | |
| 616 install_static::kUserDataDirSwitch), | |
| 617 result); | |
| 618 } | |
| 619 | |
| 620 bool GetCrashDumpLocation(std::wstring* crash_dir) { | |
| 621 // In order to be able to start crash handling very early and in chrome_elf, | |
| 622 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS) | |
| 623 // being | |
| 624 // available on Windows. See https://crbug.com/564398. | |
| 625 if (!GetUserDataDirectoryUsingProcessCommandLine(crash_dir)) { | |
| 539 return false; | 626 return false; |
| 627 } | |
| 540 | 628 |
| 541 // We have to make sure the user data dir exists on first run. See | 629 // We have to make sure the user data dir exists on first run. See |
| 542 // http://crbug.com/591504. | 630 // http://crbug.com/591504. |
| 543 if (!RecursiveDirectoryCreate(crash_dir->c_str())) | 631 if (!RecursiveDirectoryCreate(crash_dir->c_str())) |
| 544 return false; | 632 return false; |
| 545 crash_dir->append(L"\\Crashpad"); | 633 crash_dir->append(L"\\Crashpad"); |
| 546 return true; | 634 return true; |
| 547 } | 635 } |
| 548 | 636 |
| 549 std::string GetEnvironmentString(const std::string& variable_name) { | 637 std::string GetEnvironmentString(const std::string& variable_name) { |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 *result = -1; | 925 *result = -1; |
| 838 return true; | 926 return true; |
| 839 } | 927 } |
| 840 } | 928 } |
| 841 } | 929 } |
| 842 // Here it means that both versions are equal. | 930 // Here it means that both versions are equal. |
| 843 *result = 0; | 931 *result = 0; |
| 844 return true; | 932 return true; |
| 845 } | 933 } |
| 846 | 934 |
| 847 std::string GetSwitchValueFromCommandLine(const std::string& command_line, | 935 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, |
| 848 const std::string& switch_name) { | 936 const std::wstring& switch_name) { |
| 849 assert(!command_line.empty()); | 937 assert(!command_line.empty()); |
| 850 assert(!switch_name.empty()); | 938 assert(!switch_name.empty()); |
| 851 | 939 |
| 852 std::string command_line_copy = command_line; | 940 std::wstring command_line_copy = command_line; |
| 853 // Remove leading and trailing spaces. | 941 // Remove leading and trailing spaces. |
| 854 TrimT<std::string>(&command_line_copy); | 942 TrimT<std::wstring>(&command_line_copy); |
| 855 | 943 |
| 856 // Find the switch in the command line. If we don't find the switch, return | 944 // Find the switch in the command line. If we don't find the switch, return |
| 857 // an empty string. | 945 // an empty string. |
| 858 std::string switch_token = "--"; | 946 std::wstring switch_token = L"--"; |
| 859 switch_token += switch_name; | 947 switch_token += switch_name; |
| 860 switch_token += "="; | 948 switch_token += L"="; |
| 861 size_t switch_offset = command_line_copy.find(switch_token); | 949 size_t switch_offset = command_line_copy.find(switch_token); |
| 862 if (switch_offset == std::string::npos) | 950 if (switch_offset == std::string::npos) |
| 863 return std::string(); | 951 return std::wstring(); |
| 864 | 952 |
| 865 // The format is "--<switch name>=blah". Look for a space after the | 953 // The format is "--<switch name>=blah". Look for a space after the |
| 866 // "--<switch name>=" string. If we don't find a space assume that the switch | 954 // "--<switch name>=" string. If we don't find a space assume that the switch |
| 867 // value ends at the end of the command line. | 955 // value ends at the end of the command line. |
| 868 size_t switch_value_start_offset = switch_offset + switch_token.length(); | 956 size_t switch_value_start_offset = switch_offset + switch_token.length(); |
| 869 if (std::string(kWhiteSpaces).find( | 957 if (std::wstring(kWhiteSpaces16).find( |
| 870 command_line_copy[switch_value_start_offset]) != std::string::npos) { | 958 command_line_copy[switch_value_start_offset]) != std::wstring::npos) { |
| 871 switch_value_start_offset = command_line_copy.find_first_not_of( | 959 switch_value_start_offset = command_line_copy.find_first_not_of( |
| 872 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); | 960 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset); |
| 873 if (switch_value_start_offset == std::string::npos) | 961 if (switch_value_start_offset == std::wstring::npos) |
| 874 return std::string(); | 962 return std::wstring(); |
| 875 } | 963 } |
| 876 size_t switch_value_end_offset = | 964 size_t switch_value_end_offset = |
| 877 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), | 965 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(), |
| 878 switch_value_start_offset); | 966 switch_value_start_offset); |
| 879 if (switch_value_end_offset == std::string::npos) | 967 if (switch_value_end_offset == std::wstring::npos) |
| 880 switch_value_end_offset = command_line_copy.length(); | 968 switch_value_end_offset = command_line_copy.length(); |
| 881 | 969 |
| 882 std::string switch_value = command_line_copy.substr( | 970 std::wstring switch_value = command_line_copy.substr( |
| 883 switch_value_start_offset, | 971 switch_value_start_offset, |
| 884 switch_value_end_offset - (switch_offset + switch_token.length())); | 972 switch_value_end_offset - (switch_offset + switch_token.length())); |
| 885 TrimT<std::string>(&switch_value); | 973 TrimT<std::wstring>(&switch_value); |
| 886 return switch_value; | 974 return switch_value; |
| 887 } | 975 } |
| 888 | 976 |
| 889 } // namespace install_static | 977 } // namespace install_static |
| OLD | NEW |