OLD | NEW |
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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 // mini_installer.exe is the first exe that is run when chrome is being | 5 // mini_installer.exe is the first exe that is run when chrome is being |
6 // installed or upgraded. It is designed to be extremely small (~5KB with no | 6 // installed or upgraded. It is designed to be extremely small (~5KB with no |
7 // extra resources linked) and it has two main jobs: | 7 // extra resources linked) and it has two main jobs: |
8 // 1) unpack the resources (possibly decompressing some) | 8 // 1) unpack the resources (possibly decompressing some) |
9 // 2) run the real installer (setup.exe) with appropiate flags. | 9 // 2) run the real installer (setup.exe) with appropiate flags. |
10 // | 10 // |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 // return Windows last-error codes a la the Win32 registry API. | 60 // return Windows last-error codes a la the Win32 registry API. |
61 class RegKey { | 61 class RegKey { |
62 public: | 62 public: |
63 RegKey() : key_(NULL) { } | 63 RegKey() : key_(NULL) { } |
64 ~RegKey() { Close(); } | 64 ~RegKey() { Close(); } |
65 | 65 |
66 // Opens the key named |sub_key| with given |access| rights. Returns | 66 // Opens the key named |sub_key| with given |access| rights. Returns |
67 // ERROR_SUCCESS or some other error. | 67 // ERROR_SUCCESS or some other error. |
68 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); | 68 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); |
69 | 69 |
70 // Returns true if the is open. | 70 // Returns true if a key is open. |
71 bool IsOpen() const { return key_ != NULL; } | 71 bool is_valid() const { return key_ != NULL; } |
72 | 72 |
73 // Read a REG_SZ value from the registry into the memory indicated by |value| | 73 // Read a REG_SZ value from the registry into the memory indicated by |value| |
74 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, | 74 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, |
75 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is | 75 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is |
76 // guaranteed to be null-terminated on success. | 76 // guaranteed to be null-terminated on success. |
77 LONG ReadValue(const wchar_t* value_name, | 77 LONG ReadValue(const wchar_t* value_name, |
78 wchar_t* value, | 78 wchar_t* value, |
79 size_t value_size) const; | 79 size_t value_size) const; |
80 | 80 |
81 // Write a REG_SZ value to the registry. |value| must be null-terminated. | 81 // Write a REG_SZ value to the registry. |value| must be null-terminated. |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 } | 171 } |
172 | 172 |
173 // Safer replacement for lstrcat function. | 173 // Safer replacement for lstrcat function. |
174 bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src) { | 174 bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src) { |
175 int str_len = ::lstrlen(dest); | 175 int str_len = ::lstrlen(dest); |
176 return SafeStrCopy(dest + str_len, dest_size - str_len, src); | 176 return SafeStrCopy(dest + str_len, dest_size - str_len, src); |
177 } | 177 } |
178 | 178 |
179 // Function to check if a string (specified by str) ends with another string | 179 // Function to check if a string (specified by str) ends with another string |
180 // (specified by end_str). | 180 // (specified by end_str). |
181 bool StrEndsWith(const wchar_t *str, const wchar_t *end_str) { | 181 bool StrEndsWith(const wchar_t* str, const wchar_t* end_str) { |
182 if (str == NULL || end_str == NULL) | 182 if (str == NULL || end_str == NULL) |
183 return false; | 183 return false; |
184 | 184 |
185 for (int i = lstrlen(str) - 1, j = lstrlen(end_str) - 1; j >= 0; --i, --j) { | 185 for (int i = lstrlen(str) - 1, j = lstrlen(end_str) - 1; j >= 0; --i, --j) { |
186 if (i < 0 || !EqualASCIICharI(str[i], end_str[j])) | 186 if (i < 0 || !EqualASCIICharI(str[i], end_str[j])) |
187 return false; | 187 return false; |
188 } | 188 } |
189 | 189 |
190 return true; | 190 return true; |
191 } | 191 } |
192 | 192 |
193 // Function to check if a string (specified by str) starts with another string | 193 // Function to check if a string (specified by str) starts with another string |
194 // (specified by start_str). | 194 // (specified by start_str). |
195 bool StrStartsWith(const wchar_t *str, const wchar_t *start_str) { | 195 bool StrStartsWith(const wchar_t* str, const wchar_t* start_str) { |
196 if (str == NULL || start_str == NULL) | 196 if (str == NULL || start_str == NULL) |
197 return false; | 197 return false; |
198 | 198 |
199 for (int i = 0; start_str[i] != L'\0'; ++i) { | 199 for (int i = 0; start_str[i] != L'\0'; ++i) { |
200 if (!EqualASCIICharI(str[i], start_str[i])) | 200 if (!EqualASCIICharI(str[i], start_str[i])) |
201 return false; | 201 return false; |
202 } | 202 } |
203 | 203 |
204 return true; | 204 return true; |
205 } | 205 } |
206 | 206 |
| 207 // Searches for |tag| within |str|. Returns true if |tag| is found and is |
| 208 // immediately followed by '-' or is at the end of the string. If |position| |
| 209 // is non-NULL, the location of the tag is returned in |*position| on success. |
| 210 bool FindTagInStr(const wchar_t* str, |
| 211 const wchar_t* tag, |
| 212 const wchar_t** position) { |
| 213 int tag_length = ::lstrlen(tag); |
| 214 const wchar_t* scan = str; |
| 215 for (const wchar_t* tag_start = StrStrI(scan, tag); tag_start != NULL; |
| 216 tag_start = StrStrI(scan, tag)) { |
| 217 scan = tag_start + tag_length; |
| 218 if (*scan == L'-' || *scan == L'\0') { |
| 219 if (position != NULL) |
| 220 *position = tag_start; |
| 221 return true; |
| 222 } |
| 223 } |
| 224 return false; |
| 225 } |
| 226 |
207 // Helper function to read a value from registry. Returns true if value | 227 // Helper function to read a value from registry. Returns true if value |
208 // is read successfully and stored in parameter value. Returns false otherwise. | 228 // is read successfully and stored in parameter value. Returns false otherwise. |
209 // |size| is measured in wchar_t units. | 229 // |size| is measured in wchar_t units. |
210 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 230 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
211 const wchar_t *value_name, wchar_t *value, | 231 const wchar_t *value_name, wchar_t *value, |
212 size_t size) { | 232 size_t size) { |
213 RegKey key; | 233 RegKey key; |
214 | 234 |
215 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && | 235 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && |
216 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | 236 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { |
217 return true; | 237 return true; |
218 } | 238 } |
219 return false; | 239 return false; |
220 } | 240 } |
221 | 241 |
222 // Opens the Google Update ClientState key for a product. | 242 // Opens the Google Update ClientState key for a product. |
223 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | 243 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
224 RegKey* key) { | 244 RegKey* key) { |
225 wchar_t client_state_key[128]; | 245 wchar_t client_state_key[128]; |
226 | 246 |
227 return SafeStrCopy(client_state_key, _countof(client_state_key), | 247 return SafeStrCopy(client_state_key, _countof(client_state_key), |
228 kApRegistryKeyBase) && | 248 kApRegistryKeyBase) && |
229 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) && | 249 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) && |
230 (key->Open(root_key, client_state_key, access) == ERROR_SUCCESS); | 250 (key->Open(root_key, client_state_key, access) == ERROR_SUCCESS); |
231 } | 251 } |
232 | 252 |
233 // TODO(grt): Write a unit test for this that uses registry virtualization. | 253 // TODO(grt): Write a unit test for this that uses registry virtualization. |
234 void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) { | 254 void SetInstallerFlagsHelper(int args_num, const wchar_t* const* args) { |
235 bool multi_install = false; | 255 bool multi_install = false; |
236 RegKey key; | 256 RegKey key; |
237 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | 257 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; |
238 const wchar_t* app_guid = google_update::kAppGuid; | 258 const wchar_t* app_guid = google_update::kAppGuid; |
239 HKEY root_key = HKEY_CURRENT_USER; | 259 HKEY root_key = HKEY_CURRENT_USER; |
240 wchar_t value[128]; | 260 wchar_t value[128]; |
241 LONG ret; | 261 LONG ret; |
242 | 262 |
243 for (int i = 1; i < args_num; ++i) { | 263 for (int i = 1; i < args_num; ++i) { |
244 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) | 264 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) |
(...skipping 16 matching lines...) Expand all Loading... |
261 // a ClientState key in the registry. Only it need be modified. | 281 // a ClientState key in the registry. Only it need be modified. |
262 // To handle all cases, we inspect the product's ClientState to see if it | 282 // To handle all cases, we inspect the product's ClientState to see if it |
263 // exists and its "ap" value does not contain "-multi". This is case 3, so we | 283 // exists and its "ap" value does not contain "-multi". This is case 3, so we |
264 // modify the product's ClientState. Otherwise, we check the | 284 // modify the product's ClientState. Otherwise, we check the |
265 // multi-installer's ClientState and modify it if it exists. | 285 // multi-installer's ClientState and modify it if it exists. |
266 if (multi_install) { | 286 if (multi_install) { |
267 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | 287 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { |
268 // The app is installed. See if it's a single-install. | 288 // The app is installed. See if it's a single-install. |
269 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); | 289 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); |
270 if (ret != ERROR_FILE_NOT_FOUND && | 290 if (ret != ERROR_FILE_NOT_FOUND && |
271 (ret != ERROR_SUCCESS || StrStr(value, kMultiInstallTag) != NULL)) { | 291 (ret != ERROR_SUCCESS || |
272 // Error or case 2: add "-full" to the multi-installer's value. | 292 FindTagInStr(value, kMultiInstallTag, NULL))) { |
| 293 // Error or case 2: modify the multi-installer's value. |
273 key.Close(); | 294 key.Close(); |
274 app_guid = google_update::kMultiInstallAppGuid; | 295 app_guid = google_update::kMultiInstallAppGuid; |
275 } // else case 3: add "-full" to this value. | 296 } // else case 3: modify this value. |
276 } else { | 297 } else { |
277 // case 1 or 2: add "-full" to the multi-installer's value. | 298 // case 1 or 2: modify the multi-installer's value. |
278 key.Close(); | 299 key.Close(); |
279 app_guid = google_update::kMultiInstallAppGuid; | 300 app_guid = google_update::kMultiInstallAppGuid; |
280 } | 301 } |
281 } | 302 } |
282 | 303 |
283 if (!key.IsOpen()) { | 304 if (!key.is_valid()) { |
284 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | 305 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) |
285 return; | 306 return; |
286 | 307 |
287 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); | 308 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); |
288 } | 309 } |
289 | 310 |
290 // The conditions below are handling two cases: | 311 // The conditions below are handling two cases: |
291 // 1. When ap key is present, we want to make sure it doesn't already end | 312 // 1. When ap key is present, we want to add the required tags only if they |
292 // in -full and then append -full to it. | 313 // are not present. |
293 // 2. When ap key is missing, we are going to create it with value -full. | 314 // 2. When ap key is missing, we are going to create it with the required |
| 315 // tags. |
294 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 316 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
295 if (ret == ERROR_FILE_NOT_FOUND) | 317 if (ret == ERROR_FILE_NOT_FOUND) |
296 value[0] = L'\0'; | 318 value[0] = L'\0'; |
297 | 319 |
298 if (!StrEndsWith(value, kFullInstallerSuffix) && | 320 bool success = true; |
| 321 |
| 322 if (multi_install && |
| 323 !FindTagInStr(value, kMultifailInstallerSuffix, NULL)) { |
| 324 // We want -multifail to immediately precede -full. Chop off the latter |
| 325 // if it's already present so that we can simply do two appends. |
| 326 if (StrEndsWith(value, kFullInstallerSuffix)) { |
| 327 int suffix_len = ::lstrlen(kFullInstallerSuffix); |
| 328 int value_len = ::lstrlen(value); |
| 329 value[value_len - suffix_len] = L'\0'; |
| 330 } |
| 331 success = SafeStrCat(value, _countof(value), kMultifailInstallerSuffix); |
| 332 } |
| 333 if (success && !StrEndsWith(value, kFullInstallerSuffix) && |
299 (SafeStrCat(value, _countof(value), kFullInstallerSuffix))) | 334 (SafeStrCat(value, _countof(value), kFullInstallerSuffix))) |
300 key.WriteValue(kApRegistryValueName, value); | 335 key.WriteValue(kApRegistryValueName, value); |
301 } | 336 } |
302 } | 337 } |
303 | 338 |
304 // This function sets the flag in registry to indicate that Google Update | 339 // This function sets the flag in registry to indicate that Google Update |
305 // should try full installer next time. If the current installer works, this | 340 // should try full installer next time. If the current installer works, this |
306 // flag is cleared by setup.exe at the end of install. The flag will by default | 341 // flag is cleared by setup.exe at the end of install. The flag will by default |
307 // be written to HKCU, but if --system-level is included in the command line, | 342 // be written to HKCU, but if --system-level is included in the command line, |
308 // it will be written to HKLM instead. | 343 // it will be written to HKLM instead. |
309 void SetFullInstallerFlag() { | 344 void SetInstallerFlags() { |
310 int args_num; | 345 int args_num; |
311 wchar_t* cmd_line = ::GetCommandLine(); | 346 wchar_t* cmd_line = ::GetCommandLine(); |
312 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); | 347 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); |
313 | 348 |
314 SetFullInstallerFlagHelper(args_num, args); | 349 SetInstallerFlagsHelper(args_num, args); |
315 | 350 |
316 ::LocalFree(args); | 351 ::LocalFree(args); |
317 } | 352 } |
318 | 353 |
319 // Gets the setup.exe path from Registry by looking the value of Uninstall | 354 // Gets the setup.exe path from Registry by looking the value of Uninstall |
320 // string, strips the arguments for uninstall and returns only the full path | 355 // string, strips the arguments for uninstall and returns only the full path |
321 // to setup.exe. |size| is measured in wchar_t units. | 356 // to setup.exe. |size| is measured in wchar_t units. |
322 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { | 357 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { |
323 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, | 358 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, |
324 kUninstallRegistryValueName, path, size)) { | 359 kUninstallRegistryValueName, path, size)) { |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 // First get a path where we can extract payload | 677 // First get a path where we can extract payload |
643 wchar_t base_path[MAX_PATH]; | 678 wchar_t base_path[MAX_PATH]; |
644 if (!GetWorkDir(module, base_path)) | 679 if (!GetWorkDir(module, base_path)) |
645 return 101; | 680 return 101; |
646 | 681 |
647 #if defined(GOOGLE_CHROME_BUILD) | 682 #if defined(GOOGLE_CHROME_BUILD) |
648 // Set the magic suffix in registry to try full installer next time. We ignore | 683 // Set the magic suffix in registry to try full installer next time. We ignore |
649 // any errors here and we try to set the suffix for user level unless | 684 // any errors here and we try to set the suffix for user level unless |
650 // --system-level is on the command line in which case we set it for system | 685 // --system-level is on the command line in which case we set it for system |
651 // level instead. This only applies to the Google Chrome distribution. | 686 // level instead. This only applies to the Google Chrome distribution. |
652 // TODO(grt): also add -multifail if --multi-install. | 687 SetInstallerFlags(); |
653 SetFullInstallerFlag(); | |
654 #endif | 688 #endif |
655 | 689 |
656 wchar_t archive_path[MAX_PATH] = {0}; | 690 wchar_t archive_path[MAX_PATH] = {0}; |
657 wchar_t setup_path[MAX_PATH] = {0}; | 691 wchar_t setup_path[MAX_PATH] = {0}; |
658 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, | 692 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, |
659 setup_path, MAX_PATH)) | 693 setup_path, MAX_PATH)) |
660 return 102; | 694 return 102; |
661 | 695 |
662 int exit_code = 103; | 696 int exit_code = 103; |
663 if (!RunSetup(archive_path, setup_path, &exit_code)) | 697 if (!RunSetup(archive_path, setup_path, &exit_code)) |
664 return exit_code; | 698 return exit_code; |
665 | 699 |
666 wchar_t value[2]; | 700 wchar_t value[2]; |
667 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 701 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
668 kCleanupRegistryValueName, value, | 702 kCleanupRegistryValueName, value, |
669 _countof(value))) || | 703 _countof(value))) || |
670 (value[0] != L'0')) | 704 (value[0] != L'0')) |
671 DeleteExtractedFiles(base_path, archive_path, setup_path); | 705 DeleteExtractedFiles(base_path, archive_path, setup_path); |
672 | 706 |
673 return exit_code; | 707 return exit_code; |
674 } | 708 } |
| 709 |
675 } // namespace mini_installer | 710 } // namespace mini_installer |
676 | 711 |
677 | 712 |
678 int MainEntryPoint() { | 713 int MainEntryPoint() { |
679 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 714 int result = mini_installer::WMain(::GetModuleHandle(NULL)); |
680 ::ExitProcess(result); | 715 ::ExitProcess(result); |
681 } | 716 } |
OLD | NEW |