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 |