Chromium Code Reviews| 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 -fail. Chop off the latter | |
|
robertshield
2011/01/06 20:41:29
-fail -> -full
grt (UTC plus 2)
2011/01/06 20:44:09
Nice catch. Done.
| |
| 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 |