summaryrefslogtreecommitdiffstats
path: root/chromium/base/win/registry.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/win/registry.cc')
-rw-r--r--chromium/base/win/registry.cc189
1 files changed, 172 insertions, 17 deletions
diff --git a/chromium/base/win/registry.cc b/chromium/base/win/registry.cc
index 8bfe4329711..a6cb9ae89f7 100644
--- a/chromium/base/win/registry.cc
+++ b/chromium/base/win/registry.cc
@@ -10,8 +10,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
-
-#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
+#include "base/win/windows_version.h"
namespace base {
namespace win {
@@ -30,23 +29,29 @@ inline DWORD to_wchar_size(DWORD byte_size) {
return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
}
+// Mask to pull WOW64 access flags out of REGSAM access.
+const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
+
} // namespace
// RegKey ----------------------------------------------------------------------
RegKey::RegKey()
: key_(NULL),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
}
RegKey::RegKey(HKEY key)
: key_(key),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
}
RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
: key_(NULL),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
Create(rootkey, subkey, access);
@@ -54,6 +59,7 @@ RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
Open(rootkey, subkey, access);
} else {
DCHECK(!subkey);
+ wow64access_ = access & kWow64AccessMask;
}
}
@@ -69,43 +75,77 @@ LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
DCHECK(rootkey && subkey && access && disposition);
- Close();
-
+ HKEY subhkey = NULL;
LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
- REG_OPTION_NON_VOLATILE, access, NULL, &key_,
+ REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
disposition);
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subhkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
+
return result;
}
LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
DCHECK(name && access);
+ // After the application has accessed an alternate registry view using one of
+ // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+ // (create, delete, or open) on child registry keys must explicitly use the
+ // same flag. Otherwise, there can be unexpected behavior.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+ if ((access & kWow64AccessMask) != wow64access_) {
+ NOTREACHED();
+ return ERROR_INVALID_PARAMETER;
+ }
HKEY subkey = NULL;
LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
access, NULL, &subkey, NULL);
- Close();
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
- key_ = subkey;
return result;
}
LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DCHECK(rootkey && subkey && access);
- Close();
+ HKEY subhkey = NULL;
+
+ LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subhkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
- LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
return result;
}
LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
DCHECK(relative_key_name && access);
+ // After the application has accessed an alternate registry view using one of
+ // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+ // (create, delete, or open) on child registry keys must explicitly use the
+ // same flag. Otherwise, there can be unexpected behavior.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+ if ((access & kWow64AccessMask) != wow64access_) {
+ NOTREACHED();
+ return ERROR_INVALID_PARAMETER;
+ }
HKEY subkey = NULL;
LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
// We have to close the current opened key before replacing it with the new
// one.
- Close();
-
- key_ = subkey;
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
return result;
}
@@ -114,9 +154,11 @@ void RegKey::Close() {
if (key_) {
::RegCloseKey(key_);
key_ = NULL;
+ wow64access_ = 0;
}
}
+// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
void RegKey::Set(HKEY key) {
if (key_ != key) {
Close();
@@ -125,6 +167,7 @@ void RegKey::Set(HKEY key) {
}
HKEY RegKey::Take() {
+ DCHECK(wow64access_ == 0);
StopWatching();
HKEY key = key_;
key_ = NULL;
@@ -155,8 +198,43 @@ LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
LONG RegKey::DeleteKey(const wchar_t* name) {
DCHECK(key_);
DCHECK(name);
- LONG result = SHDeleteKey(key_, name);
- return result;
+ HKEY subkey = NULL;
+
+ // Verify the key exists before attempting delete to replicate previous
+ // behavior.
+ LONG result =
+ RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
+ if (result != ERROR_SUCCESS)
+ return result;
+ RegCloseKey(subkey);
+
+ return RegDelRecurse(key_, std::wstring(name), wow64access_);
+}
+
+LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
+ DCHECK(key_);
+ DCHECK(name);
+
+ HKEY target_key = NULL;
+ LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
+ &target_key);
+
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ DWORD count = 0;
+ result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
+ NULL, NULL, NULL, NULL);
+
+ RegCloseKey(target_key);
+
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ if (count == 0)
+ return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
+
+ return ERROR_DIR_NOT_EMPTY;
}
LONG RegKey::DeleteValue(const wchar_t* value_name) {
@@ -329,6 +407,83 @@ LONG RegKey::StopWatching() {
return result;
}
+// static
+LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
+ const wchar_t* lpSubKey,
+ REGSAM samDesired,
+ DWORD Reserved) {
+ typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
+
+ RegDeleteKeyExPtr reg_delete_key_ex_func =
+ reinterpret_cast<RegDeleteKeyExPtr>(
+ GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
+
+ if (reg_delete_key_ex_func)
+ return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
+
+ // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
+ return RegDeleteKey(hKey, lpSubKey);
+}
+
+// static
+LONG RegKey::RegDelRecurse(HKEY root_key,
+ const std::wstring& name,
+ REGSAM access) {
+ // First, see if the key can be deleted without having to recurse.
+ LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+ if (result == ERROR_SUCCESS)
+ return result;
+
+ HKEY target_key = NULL;
+ result = RegOpenKeyEx(
+ root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
+
+ if (result == ERROR_FILE_NOT_FOUND)
+ return ERROR_SUCCESS;
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ std::wstring subkey_name(name);
+
+ // Check for an ending slash and add one if it is missing.
+ if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
+ subkey_name += L"\\";
+
+ // Enumerate the keys
+ result = ERROR_SUCCESS;
+ const DWORD kMaxKeyNameLength = MAX_PATH;
+ const size_t base_key_length = subkey_name.length();
+ std::wstring key_name;
+ while (result == ERROR_SUCCESS) {
+ DWORD key_size = kMaxKeyNameLength;
+ result = RegEnumKeyEx(target_key,
+ 0,
+ WriteInto(&key_name, kMaxKeyNameLength),
+ &key_size,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (result != ERROR_SUCCESS)
+ break;
+
+ key_name.resize(key_size);
+ subkey_name.resize(base_key_length);
+ subkey_name += key_name;
+
+ if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
+ break;
+ }
+
+ RegCloseKey(target_key);
+
+ // Try again to delete the key.
+ result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+
+ return result;
+}
+
// RegistryValueIterator ------------------------------------------------------
RegistryValueIterator::RegistryValueIterator(HKEY root_key,