Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(440)

Side by Side Diff: chrome/installer/mini_installer/mini_installer.cc

Issue 6005016: Add -multifail to the Google Update "ap" value if --multi-install is present ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/installer/mini_installer/mini_installer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/installer/mini_installer/mini_installer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698