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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 49 // First output from call back method. Full path of Chrome archive. | 49 // First output from call back method. Full path of Chrome archive. |
| 50 wchar_t* chrome_resource_path; | 50 wchar_t* chrome_resource_path; |
| 51 // Size of chrome_resource_path buffer | 51 // Size of chrome_resource_path buffer |
| 52 size_t chrome_resource_path_size; | 52 size_t chrome_resource_path_size; |
| 53 // Second output from call back method. Full path of Setup archive/exe. | 53 // Second output from call back method. Full path of Setup archive/exe. |
| 54 wchar_t* setup_resource_path; | 54 wchar_t* setup_resource_path; |
| 55 // Size of setup_resource_path buffer | 55 // Size of setup_resource_path buffer |
| 56 size_t setup_resource_path_size; | 56 size_t setup_resource_path_size; |
| 57 }; | 57 }; |
| 58 | 58 |
| 59 // A helper class used to manipulate the Windows registry. Typically, members | |
| 60 // return Windows last-error codes a la the Win32 registry API. | |
| 61 class RegKey { | |
| 62 public: | |
| 63 RegKey() : key_(NULL) { } | |
| 64 ~RegKey() { Close(); } | |
| 65 | |
| 66 // Opens the key named |sub_key| with given |access| rights. Returns | |
| 67 // ERROR_SUCCESS or some other error. | |
| 68 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); | |
| 69 | |
| 70 // Returns true if the is open. | |
| 71 bool IsOpen() const { return key_ != NULL; } | |
| 72 | |
| 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, | |
| 75 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is | |
| 76 // guaranteed to be null-terminated on success. | |
| 77 LONG ReadValue(const wchar_t* value_name, | |
| 78 wchar_t* value, | |
| 79 size_t value_size) const; | |
|
tommi (sloooow) - chröme
2010/12/16 17:52:47
ah how I wish chrome's regkey would return the act
| |
| 80 | |
| 81 // Write a REG_SZ value to the registry. |value| must be null-terminated. | |
| 82 // Returns ERROR_SUCCESS or an error code. | |
| 83 LONG WriteValue(const wchar_t* value_name, const wchar_t* value); | |
| 84 | |
| 85 // Closes the key if it was open. | |
| 86 void Close(); | |
| 87 | |
| 88 private: | |
| 89 RegKey(const RegKey&); | |
| 90 RegKey& operator=(const RegKey&); | |
| 91 | |
| 92 HKEY key_; | |
| 93 }; // class RegKey | |
| 94 | |
| 95 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) { | |
| 96 Close(); | |
| 97 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_); | |
| 98 } | |
| 99 | |
| 100 LONG RegKey::ReadValue(const wchar_t* value_name, | |
| 101 wchar_t* value, | |
| 102 size_t value_size) const { | |
| 103 DWORD type; | |
| 104 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); | |
| 105 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, | |
| 106 reinterpret_cast<BYTE*>(value), | |
| 107 &byte_length); | |
| 108 if (result == ERROR_SUCCESS) { | |
| 109 if (type != REG_SZ) { | |
| 110 result = ERROR_NOT_SUPPORTED; | |
| 111 } else if (byte_length == 0) { | |
| 112 *value = L'\0'; | |
| 113 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { | |
| 114 if ((byte_length / sizeof(wchar_t)) < value_size) | |
| 115 value[byte_length / sizeof(wchar_t)] = L'\0'; | |
| 116 else | |
| 117 result = ERROR_MORE_DATA; | |
| 118 } | |
| 119 } | |
| 120 return result; | |
| 121 } | |
| 122 | |
| 123 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) { | |
| 124 return ::RegSetValueEx(key_, value_name, 0, REG_SZ, | |
| 125 reinterpret_cast<const BYTE*>(value), | |
| 126 (lstrlen(value) + 1) * sizeof(wchar_t)); | |
| 127 } | |
| 128 | |
| 129 void RegKey::Close() { | |
| 130 if (key_ != NULL) { | |
| 131 ::RegCloseKey(key_); | |
| 132 key_ = NULL; | |
| 133 } | |
| 134 } | |
| 135 | |
| 59 // Returns true if the given two ASCII characters are same (ignoring case). | 136 // Returns true if the given two ASCII characters are same (ignoring case). |
| 60 bool EqualASCIICharI(wchar_t a, wchar_t b) { | 137 bool EqualASCIICharI(wchar_t a, wchar_t b) { |
| 61 if (a >= L'A' && a <= L'Z') | 138 if (a >= L'A' && a <= L'Z') |
| 62 a = a + (L'a' - L'A'); | 139 a = a + (L'a' - L'A'); |
| 63 if (b >= L'A' && b <= L'Z') | 140 if (b >= L'A' && b <= L'Z') |
| 64 b = b + (L'a' - L'A'); | 141 b = b + (L'a' - L'A'); |
| 65 return (a == b); | 142 return (a == b); |
| 66 } | 143 } |
| 67 | 144 |
| 68 // Takes the path to file and returns a pointer to the filename component. For | 145 // Takes the path to file and returns a pointer to the filename component. For |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 for (int i = 0; start_str[i] != L'\0'; ++i) { | 199 for (int i = 0; start_str[i] != L'\0'; ++i) { |
| 123 if (!EqualASCIICharI(str[i], start_str[i])) | 200 if (!EqualASCIICharI(str[i], start_str[i])) |
| 124 return false; | 201 return false; |
| 125 } | 202 } |
| 126 | 203 |
| 127 return true; | 204 return true; |
| 128 } | 205 } |
| 129 | 206 |
| 130 // Helper function to read a value from registry. Returns true if value | 207 // Helper function to read a value from registry. Returns true if value |
| 131 // is read successfully and stored in parameter value. Returns false otherwise. | 208 // is read successfully and stored in parameter value. Returns false otherwise. |
| 209 // |size| is measured in wchar_t units. | |
| 132 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 210 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
| 133 const wchar_t *value_name, wchar_t *value, | 211 const wchar_t *value_name, wchar_t *value, |
| 134 size_t size) { | 212 size_t size) { |
| 135 HKEY key; | 213 RegKey key; |
| 136 if ((::RegOpenKeyEx(root_key, sub_key, NULL, | 214 |
| 137 KEY_READ, &key) == ERROR_SUCCESS) && | 215 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && |
| 138 (::RegQueryValueEx(key, value_name, NULL, NULL, | 216 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { |
| 139 reinterpret_cast<LPBYTE>(value), | |
| 140 reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) { | |
| 141 ::RegCloseKey(key); | |
| 142 return true; | 217 return true; |
| 143 } | 218 } |
| 144 return false; | 219 return false; |
| 145 } | 220 } |
| 146 | 221 |
| 147 // This function sets the flag in registry to indicate that Google Update | 222 // Opens the Google Update ClientState key for a product. |
| 148 // should try full installer next time. If the current installer works, this | 223 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
| 149 // flag is cleared by setup.exe at the end of install. The flag will by default | 224 RegKey* key) { |
| 150 // be written to HKCU, but if --system-level is included in the command line, | 225 wchar_t client_state_key[128]; |
| 151 // it will be written to HKLM instead. | 226 |
| 152 void SetFullInstallerFlag() { | 227 return SafeStrCopy(client_state_key, _countof(client_state_key), |
| 153 HKEY key; | 228 kApRegistryKeyBase) && |
| 154 wchar_t ap_registry_key[128]; | 229 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) && |
| 230 (key->Open(root_key, client_state_key, access) == ERROR_SUCCESS); | |
| 231 } | |
| 232 | |
| 233 // TODO(grt): Write a unit test for this that uses registry virtualization. | |
| 234 void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) { | |
| 235 bool multi_install = false; | |
| 236 RegKey key; | |
| 237 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
| 155 const wchar_t* app_guid = google_update::kAppGuid; | 238 const wchar_t* app_guid = google_update::kAppGuid; |
| 156 HKEY root_key = HKEY_CURRENT_USER; | 239 HKEY root_key = HKEY_CURRENT_USER; |
| 240 wchar_t value[128]; | |
| 241 LONG ret; | |
| 157 | 242 |
| 158 int args_num; | |
| 159 wchar_t* cmd_line = ::GetCommandLine(); | |
| 160 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); | |
| 161 for (int i = 1; i < args_num; ++i) { | 243 for (int i = 1; i < args_num; ++i) { |
| 162 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) | 244 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) |
| 163 app_guid = google_update::kSxSAppGuid; | 245 app_guid = google_update::kSxSAppGuid; |
| 164 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) | 246 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) |
| 165 app_guid = google_update::kChromeFrameAppGuid; | 247 app_guid = google_update::kChromeFrameAppGuid; |
| 248 else if (0 == ::lstrcmpi(args[i], L"--multi-install")) | |
| 249 multi_install = true; | |
| 166 else if (0 == ::lstrcmpi(args[i], L"--system-level")) | 250 else if (0 == ::lstrcmpi(args[i], L"--system-level")) |
| 167 root_key = HKEY_LOCAL_MACHINE; | 251 root_key = HKEY_LOCAL_MACHINE; |
| 168 } | 252 } |
| 169 | 253 |
| 170 if (!SafeStrCopy(ap_registry_key, _countof(ap_registry_key), | 254 // When multi_install is true, we are potentially: |
| 171 kApRegistryKeyBase) || | 255 // 1. Performing a multi-install of some product(s) on a clean machine. |
| 172 !SafeStrCat(ap_registry_key, _countof(ap_registry_key), | 256 // Neither the product(s) nor the multi-installer will have a ClientState |
| 173 app_guid)) { | 257 // key in the registry, so there is nothing to be done. |
| 174 return; | 258 // 2. Upgrading an existing multi-install. The multi-installer will have a |
| 259 // ClientState key in the registry. Only it need be modified. | |
| 260 // 3. Migrating a single-install into a multi-install. The product will have | |
| 261 // 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 | |
| 263 // 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 | |
| 265 // multi-installer's ClientState and modify it if it exists. | |
| 266 if (multi_install) { | |
| 267 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | |
| 268 // The app is installed. See if it's a single-install. | |
| 269 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); | |
| 270 if (ret != ERROR_FILE_NOT_FOUND && | |
| 271 (ret != ERROR_SUCCESS || StrStr(value, kMultiInstallTag) != NULL)) { | |
| 272 // Error or case 2: add "-full" to the multi-installer's value. | |
| 273 key.Close(); | |
| 274 app_guid = google_update::kMultiInstallAppGuid; | |
| 275 } // else case 3: add "-full" to this value. | |
| 276 } else { | |
| 277 // case 1 or 2: add "-full" to the multi-installer's value. | |
| 278 key.Close(); | |
| 279 app_guid = google_update::kMultiInstallAppGuid; | |
| 280 } | |
| 175 } | 281 } |
| 176 if (::RegOpenKeyEx(root_key, ap_registry_key, NULL, | |
| 177 KEY_READ | KEY_SET_VALUE, &key) != ERROR_SUCCESS) | |
| 178 return; | |
| 179 | 282 |
| 180 wchar_t value[128]; | 283 if (!key.IsOpen()) { |
| 181 size_t size = _countof(value); | 284 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) |
| 182 size_t buf_size = size; | 285 return; |
| 183 LONG ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL, | 286 |
| 184 reinterpret_cast<LPBYTE>(value), | 287 ret = key.ReadValue(kApRegistryValueName, value, _countof(value)); |
| 185 reinterpret_cast<LPDWORD>(&size)); | 288 } |
| 186 | 289 |
| 187 // The conditions below are handling two cases: | 290 // The conditions below are handling two cases: |
| 188 // 1. When ap key is present, we want to make sure it doesn't already end | 291 // 1. When ap key is present, we want to make sure it doesn't already end |
| 189 // in -full and then append -full to it. | 292 // in -full and then append -full to it. |
| 190 // 2. When ap key is missing, we are going to create it with value -full. | 293 // 2. When ap key is missing, we are going to create it with value -full. |
| 191 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 294 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
| 192 if (ret == ERROR_FILE_NOT_FOUND) | 295 if (ret == ERROR_FILE_NOT_FOUND) |
| 193 value[0] = L'\0'; | 296 value[0] = L'\0'; |
| 194 | 297 |
| 195 if (!StrEndsWith(value, kFullInstallerSuffix) && | 298 if (!StrEndsWith(value, kFullInstallerSuffix) && |
| 196 (SafeStrCat(value, buf_size, kFullInstallerSuffix))) | 299 (SafeStrCat(value, _countof(value), kFullInstallerSuffix))) |
| 197 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ, | 300 key.WriteValue(kApRegistryValueName, value); |
| 198 reinterpret_cast<LPBYTE>(value), | |
| 199 lstrlen(value) * sizeof(wchar_t)); | |
| 200 } | 301 } |
| 302 } | |
| 201 | 303 |
| 202 ::RegCloseKey(key); | 304 // 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 | |
| 306 // 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, | |
| 308 // it will be written to HKLM instead. | |
| 309 void SetFullInstallerFlag() { | |
| 310 int args_num; | |
| 311 wchar_t* cmd_line = ::GetCommandLine(); | |
| 312 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); | |
| 313 | |
| 314 SetFullInstallerFlagHelper(args_num, args); | |
| 315 | |
| 316 ::LocalFree(args); | |
| 203 } | 317 } |
| 204 | 318 |
| 205 // Gets the setup.exe path from Registry by looking the value of Uninstall | 319 // Gets the setup.exe path from Registry by looking the value of Uninstall |
| 206 // string, strips the arguments for uninstall and returns only the full path | 320 // string, strips the arguments for uninstall and returns only the full path |
| 207 // to setup.exe. | 321 // to setup.exe. |size| is measured in wchar_t units. |
| 208 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { | 322 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { |
| 209 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, | 323 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, |
| 210 kUninstallRegistryValueName, path, size)) { | 324 kUninstallRegistryValueName, path, size)) { |
| 211 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, | 325 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, |
| 212 kUninstallRegistryValueName, path, size)) { | 326 kUninstallRegistryValueName, path, size)) { |
| 213 return false; | 327 return false; |
| 214 } | 328 } |
| 215 } | 329 } |
| 216 wchar_t *tmp = StrStr(path, L" --"); | 330 wchar_t *tmp = StrStr(path, L" --"); |
| 217 if (tmp) { | 331 if (tmp) { |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 wchar_t archive_path[MAX_PATH] = {0}; | 655 wchar_t archive_path[MAX_PATH] = {0}; |
| 542 wchar_t setup_path[MAX_PATH] = {0}; | 656 wchar_t setup_path[MAX_PATH] = {0}; |
| 543 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, | 657 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, |
| 544 setup_path, MAX_PATH)) | 658 setup_path, MAX_PATH)) |
| 545 return 102; | 659 return 102; |
| 546 | 660 |
| 547 int exit_code = 103; | 661 int exit_code = 103; |
| 548 if (!RunSetup(archive_path, setup_path, &exit_code)) | 662 if (!RunSetup(archive_path, setup_path, &exit_code)) |
| 549 return exit_code; | 663 return exit_code; |
| 550 | 664 |
| 551 wchar_t value[4]; | 665 wchar_t value[2]; |
| 552 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 666 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
| 553 kCleanupRegistryValueName, value, 4)) || | 667 kCleanupRegistryValueName, value, |
| 668 _countof(value))) || | |
| 554 (value[0] != L'0')) | 669 (value[0] != L'0')) |
| 555 DeleteExtractedFiles(base_path, archive_path, setup_path); | 670 DeleteExtractedFiles(base_path, archive_path, setup_path); |
| 556 | 671 |
| 557 return exit_code; | 672 return exit_code; |
| 558 } | 673 } |
| 559 } // namespace mini_installer | 674 } // namespace mini_installer |
| 560 | 675 |
| 561 | 676 |
| 562 int MainEntryPoint() { | 677 int MainEntryPoint() { |
| 563 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 678 int result = mini_installer::WMain(::GetModuleHandle(NULL)); |
| 564 ::ExitProcess(result); | 679 ::ExitProcess(result); |
| 565 } | 680 } |
| OLD | NEW |