Chromium Code Reviews| 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 |