Chromium Code Reviews| Index: chrome/install_static/install_util.cc |
| diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc |
| index edec76d2e567b011248c619f0f601cedeb09bc7a..08d7187b313c27d476934eed1b488ac9cd058590 100644 |
| --- a/chrome/install_static/install_util.cc |
| +++ b/chrome/install_static/install_util.cc |
| @@ -4,9 +4,10 @@ |
| #include "chrome/install_static/install_util.h" |
| -#include <windows.h> |
| #include <assert.h> |
| +#include <stdlib.h> |
| #include <string.h> |
| +#include <windows.h> |
|
grt (UTC plus 2)
2016/11/21 10:29:54
nit: i think we generally include windows.h first
scottmg
2016/11/21 19:34:00
Done.
|
| #include <algorithm> |
| #include <memory> |
| @@ -14,6 +15,7 @@ |
| #include "chrome/install_static/install_details.h" |
| #include "chrome/install_static/install_modes.h" |
| +#include "chrome/install_static/policy_path_parser.h" |
| #include "chrome_elf/nt_registry/nt_registry.h" |
| namespace install_static { |
| @@ -31,12 +33,19 @@ const wchar_t kShowRestart[] = L"CHROME_CRASHED"; |
| const wchar_t kRestartInfo[] = L"CHROME_RESTART"; |
| const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; |
| -const char kGpuProcess[] = "gpu-process"; |
| -const char kPpapiPluginProcess[] = "ppapi"; |
| -const char kRendererProcess[] = "renderer"; |
| -const char kUtilityProcess[] = "utility"; |
| -const char kProcessType[] = "type"; |
| -const char kCrashpadHandler[] = "crashpad-handler"; |
| +const wchar_t kCrashpadHandler[] = L"crashpad-handler"; |
| +const wchar_t kProcessType[] = L"type"; |
| +const wchar_t kUserDataDirSwitch[] = L"user-data-dir"; |
| +const wchar_t kUtilityProcess[] = L"utility"; |
| + |
| +#if defined(GOOGLE_CHROME_BUILD) |
| +const wchar_t kRegistryChromePolicyKey[] = |
|
grt (UTC plus 2)
2016/11/21 10:29:54
please follow the strategy in ReportingIsEnforcedB
scottmg
2016/11/21 19:34:01
Done.
|
| + L"SOFTWARE\\Policies\\Google\\Chrome"; |
| +#else |
| +const wchar_t kRegistryChromePolicyKey[] = |
| + L"SOFTWARE\\Policies\\Chromium"; |
| +#endif |
| +const wchar_t kUserDataDirRegKey[] = L"UserDataDir"; |
| namespace { |
| @@ -151,6 +160,20 @@ bool GetValueFromVersionResource(const char* version_resource, |
| return false; |
| } |
| +std::wstring MakeAbsoluteFilePath(const std::wstring& input) { |
| + wchar_t file_path[MAX_PATH]; |
| + if (!_wfullpath(file_path, input.c_str(), _countof(file_path))) |
| + return std::wstring(); |
| + return file_path; |
| +} |
| + |
| +bool DirectoryExists(const std::wstring& path) { |
| + DWORD file_attributes = ::GetFileAttributes(path.c_str()); |
| + if (file_attributes == INVALID_FILE_ATTRIBUTES) |
| + return false; |
| + return (file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| +} |
| + |
| bool RecursiveDirectoryCreate(const std::wstring& full_path) { |
| // If the path exists, we've succeeded if it's a directory, failed otherwise. |
| const wchar_t* full_path_str = full_path.c_str(); |
| @@ -181,20 +204,16 @@ bool RecursiveDirectoryCreate(const std::wstring& full_path) { |
| } |
| if (!::CreateDirectory(full_path_str, nullptr)) { |
| DWORD error_code = ::GetLastError(); |
| - if (error_code == ERROR_ALREADY_EXISTS) { |
| - DWORD file_attributes = ::GetFileAttributes(full_path_str); |
| - if ((file_attributes != INVALID_FILE_ATTRIBUTES) && |
| - ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { |
| - // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we |
| - // were racing with someone creating the same directory, or a file |
| - // with the same path. If the directory exists, we lost the |
| - // race to create the same directory. |
| - return true; |
| - } else { |
| - Trace(L"Failed to create directory %ls, last error is %d\n", |
| - full_path_str, error_code); |
| - return false; |
| - } |
| + if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path_str)) { |
| + // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we |
| + // were racing with someone creating the same directory, or a file |
| + // with the same path. If the directory exists, we lost the |
| + // race to create the same directory. |
| + return true; |
| + } else { |
| + Trace(L"Failed to create directory %ls, last error is %d\n", |
| + full_path_str, error_code); |
| + return false; |
| } |
| } |
| return true; |
| @@ -359,6 +378,33 @@ std::wstring ChannelFromAdditionalParameters(const InstallConstants& mode, |
| return channel_name; |
| } |
| +// Checks if the key exists in the given hive and expands any string variables. |
| +bool LoadUserDataDirPolicyFromRegistry(nt::ROOT_KEY hive, |
| + const wchar_t* key_name, |
| + std::wstring* dir) { |
| + std::wstring value; |
| + bool result = false; |
| + HANDLE key; |
| + if (nt::OpenRegKey(hive, kRegistryChromePolicyKey, KEY_READ, &key, nullptr)) { |
|
grt (UTC plus 2)
2016/11/21 10:29:54
nit:
if (nt::QueryRegValueSZ(hive, nt::NONE, pol
scottmg
2016/11/21 19:34:01
Done.
|
| + if (nt::QueryRegValueSZ(key, key_name, &value)) { |
| + *dir = install_static::ExpandPathVariables(value); |
|
grt (UTC plus 2)
2016/11/21 10:29:54
nit: omit "install_static::"
scottmg
2016/11/21 19:34:00
Done.
|
| + result = true; |
| + } |
| + nt::CloseRegKey(key); |
| + } |
| + return result; |
| +} |
| + |
| +void CheckUserDataDirPolicy(std::wstring* user_data_dir) { |
|
grt (UTC plus 2)
2016/11/21 10:29:54
please document this. the caller assumes that |use
scottmg
2016/11/21 19:34:00
Done.
|
| + assert(user_data_dir); |
| + // Policy from the HKLM hive has precedence over HKCU. |
|
grt (UTC plus 2)
2016/11/21 10:29:54
i don't think it would be a bad thing for this to
scottmg
2016/11/21 19:34:01
Done.
|
| + if (!LoadUserDataDirPolicyFromRegistry(nt::HKLM, kUserDataDirRegKey, |
| + user_data_dir)) { |
| + LoadUserDataDirPolicyFromRegistry(nt::HKCU, kUserDataDirRegKey, |
| + user_data_dir); |
| + } |
| +} |
| + |
| } // namespace |
| bool IsSystemInstall() { |
| @@ -499,17 +545,52 @@ bool GetDefaultUserDataDirectory(std::wstring* result) { |
| return true; |
| } |
| -bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { |
| - // In order to be able to start crash handling very early, we do not rely on |
| - // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on |
| - // Windows. See https://crbug.com/564398. |
| - if (!GetDefaultUserDataDirectory(crash_dir)) |
| - return false; |
| +bool GetUserDataDirectory(const std::wstring& user_data_dir_from_command_line, |
|
grt (UTC plus 2)
2016/11/21 10:29:54
if i'm not mistaken, the only codepath for GetUser
scottmg
2016/11/21 19:34:00
Done. It's bit ugly to have to pass the partial In
|
| + std::wstring* result, |
| + std::wstring* invalid_supplied_directory) { |
| + std::wstring user_data_dir = user_data_dir_from_command_line; |
| + |
| + CheckUserDataDirPolicy(&user_data_dir); |
| + |
| + // On Windows, trailing separators leave Chrome in a bad state. See |
| + // crbug.com/464616. |
| + while (!user_data_dir.empty() && |
| + (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) { |
| + user_data_dir.pop_back(); |
| + } |
| + |
| + bool got_valid_directory = |
| + !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir); |
| + if (!got_valid_directory) { |
| + *invalid_supplied_directory = user_data_dir; |
| + got_valid_directory = GetDefaultUserDataDirectory(&user_data_dir); |
| + } |
| - // We have to make sure the user data dir exists on first run. See |
| - // http://crbug.com/591504. |
| - if (!RecursiveDirectoryCreate(*crash_dir)) |
| + // The Chrome implementation CHECKs() here in the browser process. We |
| + // don't as this function is used to initialize crash reporting, so |
| + // we would get no report of this failure. |
| + assert(got_valid_directory); |
| + if (!got_valid_directory) |
| return false; |
| + |
| + *result = MakeAbsoluteFilePath(user_data_dir); |
| + return true; |
| +} |
| + |
| +bool GetUserDataDirectoryUsingProcessCommandLine( |
| + std::wstring* result, |
| + std::wstring* invalid_supplied_directory) { |
| + return GetUserDataDirectory( |
| + GetSwitchValueFromCommandLine(::GetCommandLine(), |
| + install_static::kUserDataDirSwitch), |
|
grt (UTC plus 2)
2016/11/21 10:29:54
nit: omit "install_static::"
scottmg
2016/11/21 19:34:01
Done.
|
| + result, invalid_supplied_directory); |
| +} |
| + |
| +bool GetCrashDumpLocation(std::wstring* crash_dir) { |
| + // In order to be able to start crash handling very early and in chrome_elf, |
| + // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS) being |
| + // available on Windows. See https://crbug.com/564398. |
| + *crash_dir = install_static::InstallDetails::Get().user_data_dir(); |
|
grt (UTC plus 2)
2016/11/21 10:29:54
nit: omit "install_static::"
scottmg
2016/11/21 19:34:00
Done.
|
| crash_dir->append(L"\\Crashpad"); |
| return true; |
| } |
| @@ -651,45 +732,45 @@ std::vector<std::wstring> TokenizeString16(const std::wstring& str, |
| return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); |
| } |
| -std::string GetSwitchValueFromCommandLine(const std::string& command_line, |
| - const std::string& switch_name) { |
| +std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, |
| + const std::wstring& switch_name) { |
| assert(!command_line.empty()); |
| assert(!switch_name.empty()); |
| - std::string command_line_copy = command_line; |
| + std::wstring command_line_copy = command_line; |
| // Remove leading and trailing spaces. |
| - TrimT<std::string>(&command_line_copy); |
| + TrimT<std::wstring>(&command_line_copy); |
| // Find the switch in the command line. If we don't find the switch, return |
| // an empty string. |
| - std::string switch_token = "--"; |
| + std::wstring switch_token = L"--"; |
| switch_token += switch_name; |
| - switch_token += "="; |
| + switch_token += L"="; |
| size_t switch_offset = command_line_copy.find(switch_token); |
| if (switch_offset == std::string::npos) |
| - return std::string(); |
| + return std::wstring(); |
| // The format is "--<switch name>=blah". Look for a space after the |
| // "--<switch name>=" string. If we don't find a space assume that the switch |
| // value ends at the end of the command line. |
| size_t switch_value_start_offset = switch_offset + switch_token.length(); |
| - if (std::string(kWhiteSpaces).find( |
| - command_line_copy[switch_value_start_offset]) != std::string::npos) { |
| + if (std::wstring(kWhiteSpaces16).find( |
| + command_line_copy[switch_value_start_offset]) != std::wstring::npos) { |
| switch_value_start_offset = command_line_copy.find_first_not_of( |
| - GetWhiteSpacesForType<std::string>(), switch_value_start_offset); |
| - if (switch_value_start_offset == std::string::npos) |
| - return std::string(); |
| + GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset); |
| + if (switch_value_start_offset == std::wstring::npos) |
| + return std::wstring(); |
| } |
| size_t switch_value_end_offset = |
| - command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), |
| + command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(), |
| switch_value_start_offset); |
| - if (switch_value_end_offset == std::string::npos) |
| + if (switch_value_end_offset == std::wstring::npos) |
| switch_value_end_offset = command_line_copy.length(); |
| - std::string switch_value = command_line_copy.substr( |
| + std::wstring switch_value = command_line_copy.substr( |
| switch_value_start_offset, |
| switch_value_end_offset - (switch_offset + switch_token.length())); |
| - TrimT<std::string>(&switch_value); |
| + TrimT<std::wstring>(&switch_value); |
| return switch_value; |
| } |