summaryrefslogtreecommitdiffstats
path: root/chrome/installer/setup/setup_util.cc
diff options
context:
space:
mode:
authorgrt <grt@chromium.org>2015-09-07 06:36:12 -0700
committerCommit bot <commit-bot@chromium.org>2015-09-07 13:36:52 +0000
commit2aa3a005efb9d2f3eddbe0ca36166e8e8626624e (patch)
tree404c1f583bdd8aa8209fdc4fd34c436220d191a5 /chrome/installer/setup/setup_util.cc
parent04b61f2ae86f36aac40caeba0166705ac4ef4523 (diff)
downloadchromium_src-2aa3a005efb9d2f3eddbe0ca36166e8e8626624e.zip
chromium_src-2aa3a005efb9d2f3eddbe0ca36166e8e8626624e.tar.gz
chromium_src-2aa3a005efb9d2f3eddbe0ca36166e8e8626624e.tar.bz2
Delete Chrome state in registry on uninstall when the user profile is being deleted.
BUG=none R=robertshield@chromium.org Review URL: https://codereview.chromium.org/1327793004 Cr-Commit-Position: refs/heads/master@{#347631}
Diffstat (limited to 'chrome/installer/setup/setup_util.cc')
-rw-r--r--chrome/installer/setup/setup_util.cc151
1 files changed, 151 insertions, 0 deletions
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 0565488..af47440 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);
+ 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);
+ ++index;
+ continue;
+ }
+ did_delete = true;
+ }
+
+ // Delete the key if it no longer has any subkeys.
+ if (to_skip.empty()) {
+ 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;