OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // This file declares util functions for setup project. | 5 // This file declares util functions for setup project. |
6 | 6 |
7 #include "chrome/installer/setup/setup_util.h" | 7 #include "chrome/installer/setup/setup_util.h" |
8 | 8 |
9 #include <windows.h> | 9 #include <windows.h> |
10 | 10 |
11 #include <algorithm> | |
12 #include <iterator> | |
13 #include <set> | |
14 | |
11 #include "base/command_line.h" | 15 #include "base/command_line.h" |
12 #include "base/cpu.h" | 16 #include "base/cpu.h" |
13 #include "base/files/file_enumerator.h" | 17 #include "base/files/file_enumerator.h" |
14 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
15 #include "base/files/file_util.h" | 19 #include "base/files/file_util.h" |
16 #include "base/logging.h" | 20 #include "base/logging.h" |
21 #include "base/numerics/safe_conversions.h" | |
17 #include "base/process/kill.h" | 22 #include "base/process/kill.h" |
18 #include "base/process/launch.h" | 23 #include "base/process/launch.h" |
19 #include "base/process/process_handle.h" | 24 #include "base/process/process_handle.h" |
20 #include "base/strings/string_util.h" | 25 #include "base/strings/string_util.h" |
21 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
22 #include "base/version.h" | 27 #include "base/version.h" |
23 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
24 #include "base/win/windows_version.h" | 29 #include "base/win/windows_version.h" |
25 #include "chrome/installer/setup/setup_constants.h" | 30 #include "chrome/installer/setup/setup_constants.h" |
26 #include "chrome/installer/util/app_registration_data.h" | 31 #include "chrome/installer/util/app_registration_data.h" |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 const AppRegistrationData& reg_data, | 476 const AppRegistrationData& reg_data, |
472 const wchar_t* name) { | 477 const wchar_t* name) { |
473 base::string16 cmd_key(reg_data.GetVersionKey()); | 478 base::string16 cmd_key(reg_data.GetVersionKey()); |
474 cmd_key.append(1, base::FilePath::kSeparators[0]) | 479 cmd_key.append(1, base::FilePath::kSeparators[0]) |
475 .append(google_update::kRegCommandsKey) | 480 .append(google_update::kRegCommandsKey) |
476 .append(1, base::FilePath::kSeparators[0]) | 481 .append(1, base::FilePath::kSeparators[0]) |
477 .append(name); | 482 .append(name); |
478 return cmd_key; | 483 return cmd_key; |
479 } | 484 } |
480 | 485 |
486 void DeleteRegistryKeyPartial( | |
487 HKEY root, | |
488 const base::string16& path, | |
489 const std::vector<base::string16>& keys_to_preserve) { | |
490 // Downcase the list of keys to preserve (all must be ASCII strings). | |
491 std::set<base::string16> lowered_keys_to_preserve; | |
492 std::transform( | |
493 keys_to_preserve.begin(), keys_to_preserve.end(), | |
494 std::inserter(lowered_keys_to_preserve, lowered_keys_to_preserve.begin()), | |
495 [](const base::string16& str) { | |
496 DCHECK(!str.empty()); | |
497 DCHECK(base::IsStringASCII(str)); | |
498 return base::ToLowerASCII(str); | |
499 }); | |
500 base::win::RegKey key; | |
501 LONG result = key.Open(root, path.c_str(), (KEY_ENUMERATE_SUB_KEYS | | |
502 KEY_QUERY_VALUE | KEY_SET_VALUE)); | |
503 if (result != ERROR_SUCCESS) { | |
504 LOG_IF(ERROR, result != ERROR_FILE_NOT_FOUND) << "Failed to open " << path | |
505 << "; result = " << result; | |
506 return; | |
507 } | |
508 | |
509 // Repeatedly iterate over all subkeys deleting those that should not be | |
510 // preserved until only those remain. Multiple passes are needed since | |
511 // deleting one key may change the enumeration order of all remaining keys. | |
512 | |
513 // Subkeys or values to be skipped on subsequent passes. | |
514 std::set<base::string16> to_skip; | |
515 DWORD index = 0; | |
516 const size_t kMaxKeyNameLength = 256; // MSDN says 255; +1 for terminator. | |
517 base::string16 name(kMaxKeyNameLength, base::char16()); | |
518 bool did_delete = false; // True if at least one item was deleted. | |
519 while (true) { | |
520 DWORD name_length = base::saturated_cast<DWORD>(name.capacity()); | |
521 name.resize(name_length); | |
522 result = ::RegEnumKeyEx(key.Handle(), index, &name[0], &name_length, | |
523 nullptr, nullptr, nullptr, nullptr); | |
robertshield
2015/09/03 20:23:33
This may work, but the thing that gives me pause i
grt (UTC plus 2)
2015/09/04 02:22:47
That sentence is saying "hey, the enumeration orde
| |
524 if (result == ERROR_MORE_DATA) { | |
525 // Unexpected, but perhaps the max key name length was raised. MSDN | |
526 // doesn't clearly say that name_length will contain the necessary | |
527 // length in this case, so double the buffer and try again. | |
528 name.reserve(name.capacity() * 2); | |
529 continue; | |
530 } | |
531 if (result == ERROR_NO_MORE_ITEMS) { | |
532 if (!did_delete) | |
533 break; // All subkeys were deleted. The job is done. | |
534 // Otherwise, loop again. | |
535 did_delete = false; | |
536 index = 0; | |
537 continue; | |
538 } | |
539 if (result != ERROR_SUCCESS) | |
540 break; | |
541 // Shrink the string to the actual length of the name. | |
542 name.resize(name_length); | |
543 | |
544 // Skip over this key if it couldn't be deleted on a previous iteration. | |
545 if (to_skip.count(name)) { | |
546 ++index; | |
547 continue; | |
548 } | |
549 | |
550 // Skip over this key if it is one of the keys to preserve. | |
551 if (base::IsStringASCII(name) && | |
552 lowered_keys_to_preserve.count(base::ToLowerASCII(name))) { | |
553 // Add the true name of the key to the list of keys to skip for subsequent | |
554 // iterations. | |
555 to_skip.insert(name); | |
556 ++index; | |
557 continue; | |
558 } | |
559 | |
560 // Delete this key. | |
561 result = key.DeleteKey(name.c_str()); | |
562 if (result != ERROR_SUCCESS) { | |
563 LOG(ERROR) << "Failed to delete subkey " << name << " under path " | |
564 << path; | |
565 // Skip over this key on subsequent iterations. | |
566 to_skip.insert(name); | |
robertshield
2015/09/03 20:23:33
Hrmm, needing to preserve a list of items to skip
| |
567 ++index; | |
568 continue; | |
569 } | |
570 did_delete = true; | |
571 } | |
572 | |
573 // Delete the key if it no longer has any subkeys. | |
574 if (to_skip.empty()) { | |
robertshield
2015/09/03 20:23:34
doesn't DeleteEmptyKey already check whether the k
grt (UTC plus 2)
2015/09/04 02:22:48
Yes, though there's no need to call it if you know
| |
575 result = key.DeleteEmptyKey(L""); | |
576 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to delete empty key " | |
577 << path << "; result: " << result; | |
578 return; | |
579 } | |
580 | |
581 // Delete all values since subkeys are being preserved. | |
582 to_skip.clear(); | |
583 did_delete = false; | |
584 index = 0; | |
585 while (true) { | |
586 DWORD name_length = base::saturated_cast<int16_t>(name.capacity()); | |
587 name.resize(name_length); | |
588 result = ::RegEnumValue(key.Handle(), index, &name[0], &name_length, | |
589 nullptr, nullptr, nullptr, nullptr); | |
590 if (result == ERROR_MORE_DATA) { | |
591 if (name_length < | |
592 static_cast<DWORD>(std::numeric_limits<int16_t>::max())) { | |
593 // Double the space to hold the value name and try again. | |
594 name.reserve(name.capacity() * 2); | |
595 continue; | |
596 } | |
597 // Otherwise, the max has been exceeded. Nothing more to be done. | |
598 break; | |
599 } | |
600 if (result == ERROR_NO_MORE_ITEMS) { | |
601 if (!did_delete) | |
602 break; // All values were deleted. The job is done. | |
603 // Otherwise, loop again. | |
604 did_delete = false; | |
605 index = 0; | |
606 continue; | |
607 } | |
608 if (result != ERROR_SUCCESS) | |
609 break; | |
610 // Shrink the string to the actual length of the name. | |
611 name.resize(name_length); | |
612 | |
613 // Skip over this value if it couldn't be deleted on a previous iteration. | |
614 if (to_skip.count(name)) { | |
615 ++index; | |
616 continue; | |
617 } | |
618 | |
619 // Delete this value. | |
620 result = key.DeleteValue(name.c_str()); | |
621 if (result != ERROR_SUCCESS) { | |
622 LOG(ERROR) << "Failed to delete value " << name << " in key " << path; | |
623 // Skip over this value on subsequent iterations. | |
624 to_skip.insert(name); | |
625 ++index; | |
626 continue; | |
627 } | |
628 did_delete = true; | |
629 } | |
630 } | |
631 | |
481 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) | 632 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) |
482 : is_enabled_(false) { | 633 : is_enabled_(false) { |
483 HANDLE temp_handle; | 634 HANDLE temp_handle; |
484 if (!::OpenProcessToken(::GetCurrentProcess(), | 635 if (!::OpenProcessToken(::GetCurrentProcess(), |
485 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, | 636 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
486 &temp_handle)) { | 637 &temp_handle)) { |
487 return; | 638 return; |
488 } | 639 } |
489 token_.Set(temp_handle); | 640 token_.Set(temp_handle); |
490 | 641 |
(...skipping 22 matching lines...) Expand all Loading... | |
513 } | 664 } |
514 | 665 |
515 ScopedTokenPrivilege::~ScopedTokenPrivilege() { | 666 ScopedTokenPrivilege::~ScopedTokenPrivilege() { |
516 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { | 667 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { |
517 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, | 668 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, |
518 sizeof(TOKEN_PRIVILEGES), NULL, NULL); | 669 sizeof(TOKEN_PRIVILEGES), NULL, NULL); |
519 } | 670 } |
520 } | 671 } |
521 | 672 |
522 } // namespace installer | 673 } // namespace installer |
OLD | NEW |