Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/product_install_details.h" | 5 #include "chrome/install_static/product_install_details.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <assert.h> | 8 #include <assert.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 | 11 |
| 12 #include "chrome/install_static/install_modes.h" | 12 #include "chrome/install_static/install_modes.h" |
| 13 #include "chrome/install_static/install_util.h" | 13 #include "chrome/install_static/install_util.h" |
| 14 #include "chrome/install_static/policy_path_parser.h" | |
| 14 #include "chrome_elf/nt_registry/nt_registry.h" | 15 #include "chrome_elf/nt_registry/nt_registry.h" |
| 15 | 16 |
| 16 namespace install_static { | 17 namespace install_static { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 | 20 |
| 20 // Returns the executable path for the current process. | 21 // Returns the executable path for the current process. |
| 21 std::wstring GetCurrentProcessExePath() { | 22 std::wstring GetCurrentProcessExePath() { |
| 22 std::wstring exe_path(MAX_PATH, L'\0'); | 23 std::wstring exe_path(MAX_PATH, L'\0'); |
| 23 DWORD length = ::GetModuleFileName(nullptr, &exe_path[0], exe_path.size()); | 24 DWORD length = ::GetModuleFileName(nullptr, &exe_path[0], exe_path.size()); |
| 24 if (!length) | 25 if (!length) |
| 25 return std::wstring(); | 26 return std::wstring(); |
| 26 exe_path.resize(length); | 27 exe_path.resize(length); |
| 27 return exe_path; | 28 return exe_path; |
| 28 } | 29 } |
| 29 | 30 |
| 30 const InstallConstants* FindInstallMode(const std::wstring& suffix) { | 31 const InstallConstants* FindInstallMode(const std::wstring& suffix) { |
| 31 // Search for a mode with the matching suffix. | 32 // Search for a mode with the matching suffix. |
| 32 for (int i = 0; i < NUM_INSTALL_MODES; ++i) { | 33 for (int i = 0; i < NUM_INSTALL_MODES; ++i) { |
| 33 const InstallConstants& mode = kInstallModes[i]; | 34 const InstallConstants& mode = kInstallModes[i]; |
| 34 if (!_wcsicmp(suffix.c_str(), mode.install_suffix)) | 35 if (!_wcsicmp(suffix.c_str(), mode.install_suffix)) |
| 35 return &mode; | 36 return &mode; |
| 36 } | 37 } |
| 37 // The first mode is always the default if all else fails. | 38 // The first mode is always the default if all else fails. |
| 38 return &kInstallModes[0]; | 39 return &kInstallModes[0]; |
| 39 } | 40 } |
| 40 | 41 |
| 42 // Retrieves a registry policy for the user data directory from the registry, if | |
| 43 // one is set. If there's none set in either HKLM or HKCU, |user_data_dir| will | |
| 44 // be unmodified. | |
| 45 void GetUserDataDirFromRegistryPolicyIfSet(std::wstring* user_data_dir, | |
| 46 const InstallDetails& details) { | |
| 47 assert(user_data_dir); | |
| 48 std::wstring policies_path = L"SOFTWARE\\Policies\\"; | |
| 49 AppendChromeInstallSubDirectory(&policies_path, false /* !include_suffix */, | |
| 50 details); | |
| 51 | |
| 52 std::wstring value; | |
| 53 | |
| 54 constexpr wchar_t kUserDataDirRegistryKeyName[] = L"UserDataDir"; | |
| 55 | |
| 56 // First, try HKLM. | |
| 57 if (nt::QueryRegValueSZ(nt::HKLM, nt::NONE, policies_path.c_str(), | |
| 58 kUserDataDirRegistryKeyName, &value)) { | |
|
grt (UTC plus 2)
2016/11/22 11:37:09
nit: indentation
scottmg
2016/11/22 17:16:07
Done.
| |
| 59 *user_data_dir = ExpandPathVariables(value); | |
|
grt (UTC plus 2)
2016/11/22 11:37:09
hmm. this is going to be called from within chrome
scottmg
2016/11/22 17:16:07
Yup, $#@#!
I was thinking it would be ok after ht
scottmg
2016/11/22 20:40:41
Wow, yeah, I suck. :( Sigh. This has to be initial
grt (UTC plus 2)
2016/11/22 21:06:58
Does this mean that the user data dir will be comp
| |
| 60 return; | |
| 61 } | |
| 62 | |
| 63 // Second, try HKCU. | |
| 64 if (nt::QueryRegValueSZ(nt::HKCU, nt::NONE, policies_path.c_str(), | |
| 65 kUserDataDirRegistryKeyName, &value)) { | |
| 66 *user_data_dir = ExpandPathVariables(value); | |
| 67 return; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 std::wstring MakeAbsoluteFilePath(const std::wstring& input) { | |
| 72 wchar_t file_path[MAX_PATH]; | |
| 73 if (!_wfullpath(file_path, input.c_str(), _countof(file_path))) | |
| 74 return std::wstring(); | |
| 75 return file_path; | |
| 76 } | |
| 77 | |
| 78 // The same as GetUserDataDirectory(), but directly queries the global command | |
| 79 // line object for the --user-data-dir flag. This is the more commonly used | |
| 80 // function, where GetUserDataDirectory() is used primiarily for testing. | |
| 81 bool GetUserDataDirectoryUsingProcessCommandLine( | |
| 82 const InstallDetails& details, | |
| 83 std::wstring* result, | |
| 84 std::wstring* invalid_supplied_directory) { | |
| 85 return GetUserDataDirectory( | |
| 86 GetSwitchValueFromCommandLine(::GetCommandLine(), kUserDataDirSwitch), | |
| 87 details, result, invalid_supplied_directory); | |
| 88 } | |
| 89 | |
| 41 } // namespace | 90 } // namespace |
| 42 | 91 |
| 43 void InitializeProductDetailsForPrimaryModule() { | 92 void InitializeProductDetailsForPrimaryModule() { |
| 44 InstallDetails::SetForProcess(MakeProductDetails(GetCurrentProcessExePath())); | 93 InstallDetails::SetForProcess(MakeProductDetails(GetCurrentProcessExePath())); |
| 45 } | 94 } |
| 46 | 95 |
| 47 bool IsPathParentOf(const wchar_t* parent, | 96 bool IsPathParentOf(const wchar_t* parent, |
| 48 size_t parent_len, | 97 size_t parent_len, |
| 49 const std::wstring& path) { | 98 const std::wstring& path) { |
| 50 // Ignore all terminating path separators in |parent|. | 99 // Ignore all terminating path separators in |parent|. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 | 169 |
| 121 bool IsMultiInstall(const InstallConstants& mode, bool system_level) { | 170 bool IsMultiInstall(const InstallConstants& mode, bool system_level) { |
| 122 assert(mode.supports_multi_install); | 171 assert(mode.supports_multi_install); |
| 123 std::wstring args; | 172 std::wstring args; |
| 124 return nt::QueryRegValueSZ(system_level ? nt::HKLM : nt::HKCU, nt::WOW6432, | 173 return nt::QueryRegValueSZ(system_level ? nt::HKLM : nt::HKCU, nt::WOW6432, |
| 125 GetClientStateKeyPath(mode.app_guid).c_str(), | 174 GetClientStateKeyPath(mode.app_guid).c_str(), |
| 126 L"UninstallArguments", &args) && | 175 L"UninstallArguments", &args) && |
| 127 args.find(L"--multi-install") != std::wstring::npos; | 176 args.find(L"--multi-install") != std::wstring::npos; |
| 128 } | 177 } |
| 129 | 178 |
| 179 bool GetDefaultUserDataDirectory(const InstallDetails& details, | |
| 180 std::wstring* result) { | |
| 181 // This environment variable should be set on Windows Vista and later | |
| 182 // (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx). | |
| 183 std::wstring user_data_dir = GetEnvironmentString16(L"LOCALAPPDATA"); | |
| 184 | |
| 185 if (user_data_dir.empty()) { | |
| 186 // LOCALAPPDATA was not set; fallback to the temporary files path. | |
| 187 DWORD size = ::GetTempPath(0, nullptr); | |
| 188 if (!size) | |
| 189 return false; | |
| 190 user_data_dir.resize(size + 1); | |
| 191 size = ::GetTempPath(size + 1, &user_data_dir[0]); | |
| 192 if (!size || size >= user_data_dir.size()) | |
| 193 return false; | |
| 194 user_data_dir.resize(size); | |
| 195 } | |
| 196 | |
| 197 result->swap(user_data_dir); | |
| 198 if ((*result)[result->length() - 1] != L'\\') | |
| 199 result->push_back(L'\\'); | |
| 200 AppendChromeInstallSubDirectory(result, true /* include_suffix */, details); | |
| 201 result->push_back(L'\\'); | |
| 202 constexpr wchar_t kUserDataDirname[] = L"User Data"; | |
|
grt (UTC plus 2)
2016/11/22 11:37:09
nit: inline the literal below?
scottmg
2016/11/22 17:16:07
Done.
| |
| 203 result->append(kUserDataDirname); | |
| 204 return true; | |
| 205 } | |
| 206 | |
| 207 bool GetUserDataDirectory(const std::wstring& user_data_dir_from_command_line, | |
| 208 const InstallDetails& details, | |
| 209 std::wstring* result, | |
| 210 std::wstring* invalid_supplied_directory) { | |
| 211 std::wstring user_data_dir = user_data_dir_from_command_line; | |
| 212 | |
| 213 GetUserDataDirFromRegistryPolicyIfSet(&user_data_dir, details); | |
| 214 | |
| 215 // On Windows, trailing separators leave Chrome in a bad state. See | |
| 216 // crbug.com/464616. | |
| 217 while (!user_data_dir.empty() && | |
| 218 (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) { | |
| 219 user_data_dir.pop_back(); | |
| 220 } | |
| 221 | |
| 222 bool got_valid_directory = | |
| 223 !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir); | |
| 224 if (!got_valid_directory) { | |
| 225 *invalid_supplied_directory = user_data_dir; | |
| 226 got_valid_directory = GetDefaultUserDataDirectory(details, &user_data_dir); | |
| 227 } | |
| 228 | |
| 229 // The Chrome implementation CHECKs() here in the browser process. We | |
| 230 // don't as this function is used to initialize crash reporting, so | |
| 231 // we would get no report of this failure. | |
| 232 assert(got_valid_directory); | |
| 233 if (!got_valid_directory) | |
| 234 return false; | |
| 235 | |
| 236 *result = MakeAbsoluteFilePath(user_data_dir); | |
| 237 return true; | |
| 238 } | |
| 239 | |
| 130 std::unique_ptr<PrimaryInstallDetails> MakeProductDetails( | 240 std::unique_ptr<PrimaryInstallDetails> MakeProductDetails( |
| 131 const std::wstring& exe_path) { | 241 const std::wstring& exe_path) { |
| 132 std::unique_ptr<PrimaryInstallDetails> details(new PrimaryInstallDetails()); | 242 std::unique_ptr<PrimaryInstallDetails> details(new PrimaryInstallDetails()); |
| 133 | 243 |
| 134 const InstallConstants* mode = FindInstallMode(GetInstallSuffix(exe_path)); | 244 const InstallConstants* mode = FindInstallMode(GetInstallSuffix(exe_path)); |
| 135 const bool system_level = | 245 const bool system_level = |
| 136 mode->supports_system_level && PathIsInProgramFiles(exe_path); | 246 mode->supports_system_level && PathIsInProgramFiles(exe_path); |
| 137 const bool multi_install = | 247 const bool multi_install = |
| 138 mode->supports_multi_install && IsMultiInstall(*mode, system_level); | 248 mode->supports_multi_install && IsMultiInstall(*mode, system_level); |
| 139 | 249 |
| 140 details->set_mode(mode); | 250 details->set_mode(mode); |
| 141 details->set_system_level(system_level); | 251 details->set_system_level(system_level); |
| 142 details->set_multi_install(multi_install); | 252 details->set_multi_install(multi_install); |
| 143 details->set_channel(DetermineChannel(*mode, system_level, multi_install)); | 253 details->set_channel(DetermineChannel(*mode, system_level, multi_install)); |
| 144 | 254 |
| 255 std::wstring user_data_dir, invalid_user_data_dir; | |
| 256 GetUserDataDirectoryUsingProcessCommandLine(*details, &user_data_dir, | |
|
grt (UTC plus 2)
2016/11/22 11:37:09
rather than passing a partially-constructed Instal
scottmg
2016/11/22 17:16:07
Done.
| |
| 257 &invalid_user_data_dir); | |
| 258 details->set_user_data_dir(user_data_dir); | |
| 259 if (!invalid_user_data_dir.empty()) | |
| 260 details->set_invalid_user_data_dir(invalid_user_data_dir); | |
| 261 | |
| 145 return details; | 262 return details; |
| 146 } | 263 } |
| 147 | 264 |
| 148 } // namespace install_static | 265 } // namespace install_static |
| OLD | NEW |