| 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 <stdlib.h> |
| 9 #include <string.h> | 10 #include <string.h> |
| 10 | 11 |
| 11 #include <algorithm> | 12 #include <algorithm> |
| 12 #include <memory> | 13 #include <memory> |
| 13 #include <sstream> | 14 #include <sstream> |
| 14 | 15 |
| 15 #include "chrome/install_static/install_details.h" | 16 #include "chrome/install_static/install_details.h" |
| 16 #include "chrome/install_static/install_modes.h" | 17 #include "chrome/install_static/install_modes.h" |
| 18 #include "chrome/install_static/policy_path_parser.h" |
| 19 #include "chrome/install_static/user_data_dir.h" |
| 17 #include "chrome_elf/nt_registry/nt_registry.h" | 20 #include "chrome_elf/nt_registry/nt_registry.h" |
| 18 | 21 |
| 19 namespace install_static { | 22 namespace install_static { |
| 20 | 23 |
| 21 ProcessType g_process_type = ProcessType::UNINITIALIZED; | 24 ProcessType g_process_type = ProcessType::UNINITIALIZED; |
| 22 | 25 |
| 23 const wchar_t kRegValueChromeStatsSample[] = L"UsageStatsInSample"; | 26 const wchar_t kRegValueChromeStatsSample[] = L"UsageStatsInSample"; |
| 24 | 27 |
| 25 // TODO(ananta) | 28 // TODO(ananta) |
| 26 // http://crbug.com/604923 | 29 // http://crbug.com/604923 |
| 27 // The constants defined in this file are also defined in chrome/installer and | 30 // The constants defined in this file are also defined in chrome/installer and |
| 28 // other places. we need to unify them. | 31 // other places. we need to unify them. |
| 29 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; | 32 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; |
| 30 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; | 33 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; |
| 31 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; | 34 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; |
| 32 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; | 35 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; |
| 33 | 36 |
| 34 const char kGpuProcess[] = "gpu-process"; | 37 const wchar_t kCrashpadHandler[] = L"crashpad-handler"; |
| 35 const char kPpapiPluginProcess[] = "ppapi"; | 38 const wchar_t kProcessType[] = L"type"; |
| 36 const char kRendererProcess[] = "renderer"; | 39 const wchar_t kUserDataDirSwitch[] = L"user-data-dir"; |
| 37 const char kUtilityProcess[] = "utility"; | 40 const wchar_t kUtilityProcess[] = L"utility"; |
| 38 const char kProcessType[] = "type"; | |
| 39 const char kCrashpadHandler[] = "crashpad-handler"; | |
| 40 | 41 |
| 41 namespace { | 42 namespace { |
| 42 | 43 |
| 43 // TODO(ananta) | 44 // TODO(ananta) |
| 44 // http://crbug.com/604923 | 45 // http://crbug.com/604923 |
| 45 // The constants defined in this file are also defined in chrome/installer and | 46 // The constants defined in this file are also defined in chrome/installer and |
| 46 // other places. we need to unify them. | 47 // other places. we need to unify them. |
| 47 // Chrome channel display names. | 48 // Chrome channel display names. |
| 48 constexpr wchar_t kChromeChannelDev[] = L"dev"; | 49 constexpr wchar_t kChromeChannelDev[] = L"dev"; |
| 49 constexpr wchar_t kChromeChannelBeta[] = L"beta"; | 50 constexpr wchar_t kChromeChannelBeta[] = L"beta"; |
| 50 constexpr wchar_t kChromeChannelStableExplicit[] = L"stable"; | 51 constexpr wchar_t kChromeChannelStableExplicit[] = L"stable"; |
| 51 | 52 |
| 52 // TODO(ananta) | 53 // TODO(ananta) |
| 53 // http://crbug.com/604923 | 54 // http://crbug.com/604923 |
| 54 // These constants are defined in the chrome/installer directory as well. We | 55 // These constants are defined in the chrome/installer directory as well. We |
| 55 // need to unify them. | 56 // need to unify them. |
| 56 constexpr wchar_t kRegValueAp[] = L"ap"; | 57 constexpr wchar_t kRegValueAp[] = L"ap"; |
| 57 constexpr wchar_t kRegValueUsageStats[] = L"usagestats"; | 58 constexpr wchar_t kRegValueUsageStats[] = L"usagestats"; |
| 58 constexpr wchar_t kMetricsReportingEnabled[] = L"MetricsReportingEnabled"; | 59 constexpr wchar_t kMetricsReportingEnabled[] = L"MetricsReportingEnabled"; |
| 59 | 60 |
| 60 constexpr wchar_t kUserDataDirname[] = L"User Data"; | |
| 61 constexpr wchar_t kBrowserCrashDumpMetricsSubKey[] = | 61 constexpr wchar_t kBrowserCrashDumpMetricsSubKey[] = |
| 62 L"\\BrowserCrashDumpAttempts"; | 62 L"\\BrowserCrashDumpAttempts"; |
| 63 | 63 |
| 64 void Trace(const wchar_t* format_string, ...) { | 64 void Trace(const wchar_t* format_string, ...) { |
| 65 static const int kMaxLogBufferSize = 1024; | 65 static const int kMaxLogBufferSize = 1024; |
| 66 static wchar_t buffer[kMaxLogBufferSize] = {}; | 66 static wchar_t buffer[kMaxLogBufferSize] = {}; |
| 67 | 67 |
| 68 va_list args = {}; | 68 va_list args = {}; |
| 69 | 69 |
| 70 va_start(args, format_string); | 70 va_start(args, format_string); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 uint32_t size = 0; | 144 uint32_t size = 0; |
| 145 BOOL r = ::VerQueryValueW(version_resource, sub_block, &value, &size); | 145 BOOL r = ::VerQueryValueW(version_resource, sub_block, &value, &size); |
| 146 if (r && value) { | 146 if (r && value) { |
| 147 value_str->assign(static_cast<wchar_t*>(value)); | 147 value_str->assign(static_cast<wchar_t*>(value)); |
| 148 return true; | 148 return true; |
| 149 } | 149 } |
| 150 } | 150 } |
| 151 return false; | 151 return false; |
| 152 } | 152 } |
| 153 | 153 |
| 154 bool RecursiveDirectoryCreate(const std::wstring& full_path) { | 154 bool DirectoryExists(const std::wstring& path) { |
| 155 // If the path exists, we've succeeded if it's a directory, failed otherwise. | 155 DWORD file_attributes = ::GetFileAttributes(path.c_str()); |
| 156 const wchar_t* full_path_str = full_path.c_str(); | 156 if (file_attributes == INVALID_FILE_ATTRIBUTES) |
| 157 DWORD file_attributes = ::GetFileAttributes(full_path_str); | |
| 158 if (file_attributes != INVALID_FILE_ATTRIBUTES) { | |
| 159 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | |
| 160 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); | |
| 161 return true; | |
| 162 } | |
| 163 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, | |
| 164 full_path_str); | |
| 165 return false; | 157 return false; |
| 166 } | 158 return (file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| 167 | |
| 168 // Invariant: Path does not exist as file or directory. | |
| 169 | |
| 170 // Attempt to create the parent recursively. This will immediately return | |
| 171 // true if it already exists, otherwise will create all required parent | |
| 172 // directories starting with the highest-level missing parent. | |
| 173 std::wstring parent_path; | |
| 174 std::size_t pos = full_path.find_last_of(L"/\\"); | |
| 175 if (pos != std::wstring::npos) { | |
| 176 parent_path = full_path.substr(0, pos); | |
| 177 if (!RecursiveDirectoryCreate(parent_path)) { | |
| 178 Trace(L"Failed to create one of the parent directories"); | |
| 179 return false; | |
| 180 } | |
| 181 } | |
| 182 if (!::CreateDirectory(full_path_str, nullptr)) { | |
| 183 DWORD error_code = ::GetLastError(); | |
| 184 if (error_code == ERROR_ALREADY_EXISTS) { | |
| 185 DWORD file_attributes = ::GetFileAttributes(full_path_str); | |
| 186 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && | |
| 187 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { | |
| 188 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we | |
| 189 // were racing with someone creating the same directory, or a file | |
| 190 // with the same path. If the directory exists, we lost the | |
| 191 // race to create the same directory. | |
| 192 return true; | |
| 193 } else { | |
| 194 Trace(L"Failed to create directory %ls, last error is %d\n", | |
| 195 full_path_str, error_code); | |
| 196 return false; | |
| 197 } | |
| 198 } | |
| 199 } | |
| 200 return true; | |
| 201 } | |
| 202 | |
| 203 // Appends "[kCompanyPathName\]kProductPathName[install_suffix]" to |path|, | |
| 204 // returning a reference to |path|. | |
| 205 std::wstring& AppendChromeInstallSubDirectory(std::wstring* path, | |
| 206 bool include_suffix) { | |
| 207 if (*kCompanyPathName) { | |
| 208 path->append(kCompanyPathName); | |
| 209 path->push_back(L'\\'); | |
| 210 } | |
| 211 path->append(kProductPathName, kProductPathNameLength); | |
| 212 if (!include_suffix) | |
| 213 return *path; | |
| 214 return path->append(InstallDetails::Get().install_suffix()); | |
| 215 } | 159 } |
| 216 | 160 |
| 217 std::wstring GetChromeInstallRegistryPath() { | 161 std::wstring GetChromeInstallRegistryPath() { |
| 218 std::wstring registry_path = L"Software\\"; | 162 std::wstring registry_path = L"Software\\"; |
| 219 return AppendChromeInstallSubDirectory(®istry_path, | 163 return AppendChromeInstallSubDirectory( |
| 220 true /* include_suffix */); | 164 InstallDetails::Get().mode(), true /* include_suffix */, ®istry_path); |
| 221 } | 165 } |
| 222 | 166 |
| 223 // Returns true if the |source| string matches the |pattern|. The pattern | 167 // Returns true if the |source| string matches the |pattern|. The pattern |
| 224 // may contain wildcards like '?' which matches one character or a '*' | 168 // may contain wildcards like '?' which matches one character or a '*' |
| 225 // which matches 0 or more characters. | 169 // which matches 0 or more characters. |
| 226 // Please note that pattern matches the whole string. If you want to find | 170 // Please note that pattern matches the whole string. If you want to find |
| 227 // something in the middle of the string then you need to specify the pattern | 171 // something in the middle of the string then you need to specify the pattern |
| 228 // as '*xyz*'. | 172 // as '*xyz*'. |
| 229 // |source_index| is the index of the current character being matched in | 173 // |source_index| is the index of the current character being matched in |
| 230 // |source|. | 174 // |source|. |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 KEY_SET_VALUE | KEY_WOW64_32KEY, &key_handle)) { | 361 KEY_SET_VALUE | KEY_WOW64_32KEY, &key_handle)) { |
| 418 return false; | 362 return false; |
| 419 } | 363 } |
| 420 | 364 |
| 421 bool success = nt::SetRegValueDWORD(key_handle, kRegValueChromeStatsSample, | 365 bool success = nt::SetRegValueDWORD(key_handle, kRegValueChromeStatsSample, |
| 422 in_sample ? 1 : 0); | 366 in_sample ? 1 : 0); |
| 423 nt::CloseRegKey(key_handle); | 367 nt::CloseRegKey(key_handle); |
| 424 return success; | 368 return success; |
| 425 } | 369 } |
| 426 | 370 |
| 371 // Appends "[kCompanyPathName\]kProductPathName[install_suffix]" to |path|, |
| 372 // returning a reference to |path|. |
| 373 std::wstring& AppendChromeInstallSubDirectory(const InstallConstants& mode, |
| 374 bool include_suffix, |
| 375 std::wstring* path) { |
| 376 if (*kCompanyPathName) { |
| 377 path->append(kCompanyPathName); |
| 378 path->push_back(L'\\'); |
| 379 } |
| 380 path->append(kProductPathName, kProductPathNameLength); |
| 381 if (!include_suffix) |
| 382 return *path; |
| 383 return path->append(mode.install_suffix); |
| 384 } |
| 385 |
| 427 bool ReportingIsEnforcedByPolicy(bool* crash_reporting_enabled) { | 386 bool ReportingIsEnforcedByPolicy(bool* crash_reporting_enabled) { |
| 428 std::wstring policies_path = L"SOFTWARE\\Policies\\"; | 387 std::wstring policies_path = L"SOFTWARE\\Policies\\"; |
| 429 AppendChromeInstallSubDirectory(&policies_path, false /* !include_suffix */); | 388 AppendChromeInstallSubDirectory(InstallDetails::Get().mode(), |
| 389 false /* !include_suffix */, &policies_path); |
| 430 DWORD value = 0; | 390 DWORD value = 0; |
| 431 | 391 |
| 432 // First, try HKLM. | 392 // First, try HKLM. |
| 433 if (nt::QueryRegValueDWORD(nt::HKLM, nt::NONE, policies_path.c_str(), | 393 if (nt::QueryRegValueDWORD(nt::HKLM, nt::NONE, policies_path.c_str(), |
| 434 kMetricsReportingEnabled, &value)) { | 394 kMetricsReportingEnabled, &value)) { |
| 435 *crash_reporting_enabled = (value != 0); | 395 *crash_reporting_enabled = (value != 0); |
| 436 return true; | 396 return true; |
| 437 } | 397 } |
| 438 | 398 |
| 439 // Second, try HKCU. | 399 // Second, try HKCU. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 466 } | 426 } |
| 467 | 427 |
| 468 g_process_type = ProcessType::BROWSER_PROCESS; | 428 g_process_type = ProcessType::BROWSER_PROCESS; |
| 469 } | 429 } |
| 470 | 430 |
| 471 bool IsNonBrowserProcess() { | 431 bool IsNonBrowserProcess() { |
| 472 assert(g_process_type != ProcessType::UNINITIALIZED); | 432 assert(g_process_type != ProcessType::UNINITIALIZED); |
| 473 return g_process_type == ProcessType::NON_BROWSER_PROCESS; | 433 return g_process_type == ProcessType::NON_BROWSER_PROCESS; |
| 474 } | 434 } |
| 475 | 435 |
| 476 bool GetDefaultUserDataDirectory(std::wstring* result) { | 436 std::wstring GetCrashDumpLocation() { |
| 477 // This environment variable should be set on Windows Vista and later | 437 // In order to be able to start crash handling very early and in chrome_elf, |
| 478 // (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx). | 438 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS) being |
| 479 std::wstring user_data_dir = GetEnvironmentString16(L"LOCALAPPDATA"); | 439 // available on Windows. See https://crbug.com/564398. |
| 480 | 440 std::wstring user_data_dir; |
| 481 if (user_data_dir.empty()) { | 441 bool ret = GetUserDataDirectory(&user_data_dir, nullptr); |
| 482 // LOCALAPPDATA was not set; fallback to the temporary files path. | 442 assert(ret); |
| 483 DWORD size = ::GetTempPath(0, nullptr); | 443 IgnoreUnused(ret); |
| 484 if (!size) | 444 return user_data_dir.append(L"\\Crashpad"); |
| 485 return false; | |
| 486 user_data_dir.resize(size + 1); | |
| 487 size = ::GetTempPath(size + 1, &user_data_dir[0]); | |
| 488 if (!size || size >= user_data_dir.size()) | |
| 489 return false; | |
| 490 user_data_dir.resize(size); | |
| 491 } | |
| 492 | |
| 493 result->swap(user_data_dir); | |
| 494 if ((*result)[result->length() - 1] != L'\\') | |
| 495 result->push_back(L'\\'); | |
| 496 AppendChromeInstallSubDirectory(result, true /* include_suffix */); | |
| 497 result->push_back(L'\\'); | |
| 498 result->append(kUserDataDirname); | |
| 499 return true; | |
| 500 } | |
| 501 | |
| 502 bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { | |
| 503 // In order to be able to start crash handling very early, we do not rely on | |
| 504 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on | |
| 505 // Windows. See https://crbug.com/564398. | |
| 506 if (!GetDefaultUserDataDirectory(crash_dir)) | |
| 507 return false; | |
| 508 | |
| 509 // We have to make sure the user data dir exists on first run. See | |
| 510 // http://crbug.com/591504. | |
| 511 if (!RecursiveDirectoryCreate(*crash_dir)) | |
| 512 return false; | |
| 513 crash_dir->append(L"\\Crashpad"); | |
| 514 return true; | |
| 515 } | 445 } |
| 516 | 446 |
| 517 std::string GetEnvironmentString(const std::string& variable_name) { | 447 std::string GetEnvironmentString(const std::string& variable_name) { |
| 518 return UTF16ToUTF8( | 448 return UTF16ToUTF8( |
| 519 GetEnvironmentString16(UTF8ToUTF16(variable_name).c_str())); | 449 GetEnvironmentString16(UTF8ToUTF16(variable_name).c_str())); |
| 520 } | 450 } |
| 521 | 451 |
| 522 std::wstring GetEnvironmentString16(const wchar_t* variable_name) { | 452 std::wstring GetEnvironmentString16(const wchar_t* variable_name) { |
| 523 DWORD value_length = ::GetEnvironmentVariableW(variable_name, nullptr, 0); | 453 DWORD value_length = ::GetEnvironmentVariableW(variable_name, nullptr, 0); |
| 524 if (!value_length) | 454 if (!value_length) |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 bool trim_spaces) { | 574 bool trim_spaces) { |
| 645 return TokenizeStringT<std::string>(str, delimiter, trim_spaces); | 575 return TokenizeStringT<std::string>(str, delimiter, trim_spaces); |
| 646 } | 576 } |
| 647 | 577 |
| 648 std::vector<std::wstring> TokenizeString16(const std::wstring& str, | 578 std::vector<std::wstring> TokenizeString16(const std::wstring& str, |
| 649 wchar_t delimiter, | 579 wchar_t delimiter, |
| 650 bool trim_spaces) { | 580 bool trim_spaces) { |
| 651 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); | 581 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); |
| 652 } | 582 } |
| 653 | 583 |
| 654 std::string GetSwitchValueFromCommandLine(const std::string& command_line, | 584 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, |
| 655 const std::string& switch_name) { | 585 const std::wstring& switch_name) { |
| 656 assert(!command_line.empty()); | 586 assert(!command_line.empty()); |
| 657 assert(!switch_name.empty()); | 587 assert(!switch_name.empty()); |
| 658 | 588 |
| 659 std::string command_line_copy = command_line; | 589 std::wstring command_line_copy = command_line; |
| 660 // Remove leading and trailing spaces. | 590 // Remove leading and trailing spaces. |
| 661 TrimT<std::string>(&command_line_copy); | 591 TrimT<std::wstring>(&command_line_copy); |
| 662 | 592 |
| 663 // Find the switch in the command line. If we don't find the switch, return | 593 // Find the switch in the command line. If we don't find the switch, return |
| 664 // an empty string. | 594 // an empty string. |
| 665 std::string switch_token = "--"; | 595 std::wstring switch_token = L"--"; |
| 666 switch_token += switch_name; | 596 switch_token += switch_name; |
| 667 switch_token += "="; | 597 switch_token += L"="; |
| 668 size_t switch_offset = command_line_copy.find(switch_token); | 598 size_t switch_offset = command_line_copy.find(switch_token); |
| 669 if (switch_offset == std::string::npos) | 599 if (switch_offset == std::string::npos) |
| 670 return std::string(); | 600 return std::wstring(); |
| 671 | 601 |
| 672 // The format is "--<switch name>=blah". Look for a space after the | 602 // The format is "--<switch name>=blah". Look for a space after the |
| 673 // "--<switch name>=" string. If we don't find a space assume that the switch | 603 // "--<switch name>=" string. If we don't find a space assume that the switch |
| 674 // value ends at the end of the command line. | 604 // value ends at the end of the command line. |
| 675 size_t switch_value_start_offset = switch_offset + switch_token.length(); | 605 size_t switch_value_start_offset = switch_offset + switch_token.length(); |
| 676 if (std::string(kWhiteSpaces).find( | 606 if (std::wstring(kWhiteSpaces16).find( |
| 677 command_line_copy[switch_value_start_offset]) != std::string::npos) { | 607 command_line_copy[switch_value_start_offset]) != std::wstring::npos) { |
| 678 switch_value_start_offset = command_line_copy.find_first_not_of( | 608 switch_value_start_offset = command_line_copy.find_first_not_of( |
| 679 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); | 609 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset); |
| 680 if (switch_value_start_offset == std::string::npos) | 610 if (switch_value_start_offset == std::wstring::npos) |
| 681 return std::string(); | 611 return std::wstring(); |
| 682 } | 612 } |
| 683 size_t switch_value_end_offset = | 613 size_t switch_value_end_offset = |
| 684 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), | 614 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(), |
| 685 switch_value_start_offset); | 615 switch_value_start_offset); |
| 686 if (switch_value_end_offset == std::string::npos) | 616 if (switch_value_end_offset == std::wstring::npos) |
| 687 switch_value_end_offset = command_line_copy.length(); | 617 switch_value_end_offset = command_line_copy.length(); |
| 688 | 618 |
| 689 std::string switch_value = command_line_copy.substr( | 619 std::wstring switch_value = command_line_copy.substr( |
| 690 switch_value_start_offset, | 620 switch_value_start_offset, |
| 691 switch_value_end_offset - (switch_offset + switch_token.length())); | 621 switch_value_end_offset - (switch_offset + switch_token.length())); |
| 692 TrimT<std::string>(&switch_value); | 622 TrimT<std::wstring>(&switch_value); |
| 693 return switch_value; | 623 return switch_value; |
| 694 } | 624 } |
| 695 | 625 |
| 626 bool RecursiveDirectoryCreate(const std::wstring& full_path) { |
| 627 // If the path exists, we've succeeded if it's a directory, failed otherwise. |
| 628 const wchar_t* full_path_str = full_path.c_str(); |
| 629 DWORD file_attributes = ::GetFileAttributes(full_path_str); |
| 630 if (file_attributes != INVALID_FILE_ATTRIBUTES) { |
| 631 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 632 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); |
| 633 return true; |
| 634 } |
| 635 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, |
| 636 full_path_str); |
| 637 return false; |
| 638 } |
| 639 |
| 640 // Invariant: Path does not exist as file or directory. |
| 641 |
| 642 // Attempt to create the parent recursively. This will immediately return |
| 643 // true if it already exists, otherwise will create all required parent |
| 644 // directories starting with the highest-level missing parent. |
| 645 std::wstring parent_path; |
| 646 std::size_t pos = full_path.find_last_of(L"/\\"); |
| 647 if (pos != std::wstring::npos) { |
| 648 parent_path = full_path.substr(0, pos); |
| 649 if (!RecursiveDirectoryCreate(parent_path)) { |
| 650 Trace(L"Failed to create one of the parent directories"); |
| 651 return false; |
| 652 } |
| 653 } |
| 654 if (!::CreateDirectory(full_path_str, nullptr)) { |
| 655 DWORD error_code = ::GetLastError(); |
| 656 if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path_str)) { |
| 657 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we |
| 658 // were racing with someone creating the same directory, or a file |
| 659 // with the same path. If the directory exists, we lost the |
| 660 // race to create the same directory. |
| 661 return true; |
| 662 } else { |
| 663 Trace(L"Failed to create directory %ls, last error is %d\n", |
| 664 full_path_str, error_code); |
| 665 return false; |
| 666 } |
| 667 } |
| 668 return true; |
| 669 } |
| 670 |
| 696 // This function takes these inputs rather than accessing the module's | 671 // This function takes these inputs rather than accessing the module's |
| 697 // InstallDetails instance since it is used to bootstrap InstallDetails. | 672 // InstallDetails instance since it is used to bootstrap InstallDetails. |
| 698 std::wstring DetermineChannel(const InstallConstants& mode, | 673 std::wstring DetermineChannel(const InstallConstants& mode, |
| 699 bool system_level, | 674 bool system_level, |
| 700 bool multi_install) { | 675 bool multi_install) { |
| 701 if (!kUseGoogleUpdateIntegration) | 676 if (!kUseGoogleUpdateIntegration) |
| 702 return std::wstring(); | 677 return std::wstring(); |
| 703 | 678 |
| 704 switch (mode.channel_strategy) { | 679 switch (mode.channel_strategy) { |
| 705 case ChannelStrategy::UNSUPPORTED: | 680 case ChannelStrategy::UNSUPPORTED: |
| 706 assert(false); | 681 assert(false); |
| 707 break; | 682 break; |
| 708 case ChannelStrategy::ADDITIONAL_PARAMETERS: | 683 case ChannelStrategy::ADDITIONAL_PARAMETERS: |
| 709 return ChannelFromAdditionalParameters(mode, system_level, multi_install); | 684 return ChannelFromAdditionalParameters(mode, system_level, multi_install); |
| 710 case ChannelStrategy::FIXED: | 685 case ChannelStrategy::FIXED: |
| 711 return mode.default_channel_name; | 686 return mode.default_channel_name; |
| 712 } | 687 } |
| 713 | 688 |
| 714 return std::wstring(); | 689 return std::wstring(); |
| 715 } | 690 } |
| 716 | 691 |
| 717 } // namespace install_static | 692 } // namespace install_static |
| OLD | NEW |