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 |