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

Unified Diff: chrome/installer/setup/setup_util.cc

Issue 1327793004: Delete Chrome state in registry on uninstall when the user profile is being deleted. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/installer/setup/setup_util.h ('k') | chrome/installer/setup/setup_util_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/installer/setup/setup_util.cc
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 0565488cc33bd1ba9913fbf74dc578d8ea2dec38..af474401c9709d9dbd29faca40c870ee59937a4a 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -8,12 +8,17 @@
#include <windows.h>
+#include <algorithm>
+#include <iterator>
+#include <set>
+
#include "base/command_line.h"
#include "base/cpu.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
@@ -478,6 +483,152 @@ base::string16 GetRegistrationDataCommandKey(
return cmd_key;
}
+void DeleteRegistryKeyPartial(
+ HKEY root,
+ const base::string16& path,
+ const std::vector<base::string16>& keys_to_preserve) {
+ // Downcase the list of keys to preserve (all must be ASCII strings).
+ std::set<base::string16> lowered_keys_to_preserve;
+ std::transform(
+ keys_to_preserve.begin(), keys_to_preserve.end(),
+ std::inserter(lowered_keys_to_preserve, lowered_keys_to_preserve.begin()),
+ [](const base::string16& str) {
+ DCHECK(!str.empty());
+ DCHECK(base::IsStringASCII(str));
+ return base::ToLowerASCII(str);
+ });
+ base::win::RegKey key;
+ LONG result = key.Open(root, path.c_str(), (KEY_ENUMERATE_SUB_KEYS |
+ KEY_QUERY_VALUE | KEY_SET_VALUE));
+ if (result != ERROR_SUCCESS) {
+ LOG_IF(ERROR, result != ERROR_FILE_NOT_FOUND) << "Failed to open " << path
+ << "; result = " << result;
+ return;
+ }
+
+ // Repeatedly iterate over all subkeys deleting those that should not be
+ // preserved until only those remain. Multiple passes are needed since
+ // deleting one key may change the enumeration order of all remaining keys.
+
+ // Subkeys or values to be skipped on subsequent passes.
+ std::set<base::string16> to_skip;
+ DWORD index = 0;
+ const size_t kMaxKeyNameLength = 256; // MSDN says 255; +1 for terminator.
+ base::string16 name(kMaxKeyNameLength, base::char16());
+ bool did_delete = false; // True if at least one item was deleted.
+ while (true) {
+ DWORD name_length = base::saturated_cast<DWORD>(name.capacity());
+ name.resize(name_length);
+ result = ::RegEnumKeyEx(key.Handle(), index, &name[0], &name_length,
+ 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
+ if (result == ERROR_MORE_DATA) {
+ // Unexpected, but perhaps the max key name length was raised. MSDN
+ // doesn't clearly say that name_length will contain the necessary
+ // length in this case, so double the buffer and try again.
+ name.reserve(name.capacity() * 2);
+ continue;
+ }
+ if (result == ERROR_NO_MORE_ITEMS) {
+ if (!did_delete)
+ break; // All subkeys were deleted. The job is done.
+ // Otherwise, loop again.
+ did_delete = false;
+ index = 0;
+ continue;
+ }
+ if (result != ERROR_SUCCESS)
+ break;
+ // Shrink the string to the actual length of the name.
+ name.resize(name_length);
+
+ // Skip over this key if it couldn't be deleted on a previous iteration.
+ if (to_skip.count(name)) {
+ ++index;
+ continue;
+ }
+
+ // Skip over this key if it is one of the keys to preserve.
+ if (base::IsStringASCII(name) &&
+ lowered_keys_to_preserve.count(base::ToLowerASCII(name))) {
+ // Add the true name of the key to the list of keys to skip for subsequent
+ // iterations.
+ to_skip.insert(name);
+ ++index;
+ continue;
+ }
+
+ // Delete this key.
+ result = key.DeleteKey(name.c_str());
+ if (result != ERROR_SUCCESS) {
+ LOG(ERROR) << "Failed to delete subkey " << name << " under path "
+ << path;
+ // Skip over this key on subsequent iterations.
+ to_skip.insert(name);
robertshield 2015/09/03 20:23:33 Hrmm, needing to preserve a list of items to skip
+ ++index;
+ continue;
+ }
+ did_delete = true;
+ }
+
+ // Delete the key if it no longer has any subkeys.
+ 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
+ result = key.DeleteEmptyKey(L"");
+ LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to delete empty key "
+ << path << "; result: " << result;
+ return;
+ }
+
+ // Delete all values since subkeys are being preserved.
+ to_skip.clear();
+ did_delete = false;
+ index = 0;
+ while (true) {
+ DWORD name_length = base::saturated_cast<int16_t>(name.capacity());
+ name.resize(name_length);
+ result = ::RegEnumValue(key.Handle(), index, &name[0], &name_length,
+ nullptr, nullptr, nullptr, nullptr);
+ if (result == ERROR_MORE_DATA) {
+ if (name_length <
+ static_cast<DWORD>(std::numeric_limits<int16_t>::max())) {
+ // Double the space to hold the value name and try again.
+ name.reserve(name.capacity() * 2);
+ continue;
+ }
+ // Otherwise, the max has been exceeded. Nothing more to be done.
+ break;
+ }
+ if (result == ERROR_NO_MORE_ITEMS) {
+ if (!did_delete)
+ break; // All values were deleted. The job is done.
+ // Otherwise, loop again.
+ did_delete = false;
+ index = 0;
+ continue;
+ }
+ if (result != ERROR_SUCCESS)
+ break;
+ // Shrink the string to the actual length of the name.
+ name.resize(name_length);
+
+ // Skip over this value if it couldn't be deleted on a previous iteration.
+ if (to_skip.count(name)) {
+ ++index;
+ continue;
+ }
+
+ // Delete this value.
+ result = key.DeleteValue(name.c_str());
+ if (result != ERROR_SUCCESS) {
+ LOG(ERROR) << "Failed to delete value " << name << " in key " << path;
+ // Skip over this value on subsequent iterations.
+ to_skip.insert(name);
+ ++index;
+ continue;
+ }
+ did_delete = true;
+ }
+}
+
ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name)
: is_enabled_(false) {
HANDLE temp_handle;
« no previous file with comments | « chrome/installer/setup/setup_util.h ('k') | chrome/installer/setup/setup_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698