[PATCH 1/2] advapi32: Foundation for HKCR merge (try 2)
George Stephanos
gaf.stephanos at gmail.com
Thu Jan 23 18:05:38 CST 2014
---
dlls/advapi32/registry.c | 255 ++++++++++++++++++++++++++++++++++++++++-
dlls/advapi32/tests/registry.c | 6 +-
2 files changed, 256 insertions(+), 5 deletions(-)
diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index f278951..851f414 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -65,7 +65,7 @@ static const WCHAR name_DYN_DATA[] =
static const WCHAR * const root_key_names[] =
{
- name_CLASSES_ROOT,
+ NULL, /* HKEY_CLASSES_ROOT is dynamic */
NULL, /* HKEY_CURRENT_USER is determined dynamically */
name_LOCAL_MACHINE,
name_USERS,
@@ -79,6 +79,34 @@ static const WCHAR * const root_key_names[] =
static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
static BOOL hkcu_cache_disabled;
+typedef struct {
+ BOOL init;
+ HKEY hklm;
+} opened_hkcr_t;
+
+/* ############################### */
+
+static CRITICAL_SECTION hkcr_handles_cs;
+static CRITICAL_SECTION_DEBUG hkcr_handles_cs_debug =
+{
+ 0, 0, &hkcr_handles_cs,
+ { &hkcr_handles_cs_debug.ProcessLocksList, &hkcr_handles_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": hkcr_handles_cs") }
+};
+static CRITICAL_SECTION hkcr_handles_cs = { &hkcr_handles_cs_debug, -1, 0, 0, 0, 0 };
+
+/* ############################### */
+
+static opened_hkcr_t *hkcr_handles;
+static UINT nb_hkcr_handles;
+
+static UINT *hkcr_handles_free;
+static UINT nb_hkcr_handles_free;
+
+#define SPECIAL_HKEY_MASK 0x80000003
+#define HKCR_FLAG 2
+#define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
+
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
/* check if value type needs string conversion (Ansi<->Unicode) */
@@ -231,13 +259,148 @@ static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *a
return status;
}
+static opened_hkcr_t *get_opened_hkcr( HKEY hkey )
+{
+ UINT_PTR idx = (UINT_PTR)hkey >> 2;
+ opened_hkcr_t *ret = NULL;
+
+ if (!IS_HKCR(hkey)) return NULL;
+
+ EnterCriticalSection(&hkcr_handles_cs);
+ if (idx < nb_hkcr_handles && hkcr_handles[idx].init) ret = &hkcr_handles[idx];
+ LeaveCriticalSection(&hkcr_handles_cs);
+
+ return ret;
+}
+
+static LSTATUS create_hkcr_struct( HKEY *hkey, opened_hkcr_t **hkcr )
+{
+ UINT_PTR handle, i;
+ LSTATUS ret = ERROR_SUCCESS;
+
+ EnterCriticalSection( &hkcr_handles_cs );
+
+ if (!nb_hkcr_handles_free)
+ {
+ opened_hkcr_t *new_array;
+ UINT *new_array_free;
+
+ if (hkcr_handles)
+ {
+ new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, hkcr_handles,
+ (nb_hkcr_handles * 2) * sizeof(*new_array) );
+ new_array_free = HeapReAlloc( GetProcessHeap(), 0, hkcr_handles_free,
+ (nb_hkcr_handles * 2) * sizeof(*new_array_free) );
+ }
+ else
+ {
+ new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(*new_array) );
+ new_array_free = HeapAlloc( GetProcessHeap(), 0, 16 * sizeof(*new_array_free) );
+ }
+
+ if (!new_array || !new_array_free)
+ {
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+
+ hkcr_handles = new_array;
+ hkcr_handles_free = new_array_free;
+
+ nb_hkcr_handles = !nb_hkcr_handles ? 16 : nb_hkcr_handles * 2;
+
+ for (i = nb_hkcr_handles == 16 ? 0 : nb_hkcr_handles/2; i < nb_hkcr_handles; i++)
+ hkcr_handles_free[nb_hkcr_handles_free++] = i;
+ }
+
+ handle = hkcr_handles_free[--nb_hkcr_handles_free];
+ memset( &hkcr_handles[handle], 0, sizeof(opened_hkcr_t) );
+ hkcr_handles[handle].init = TRUE;
+ *hkcr = &hkcr_handles[handle];
+ *hkey = (HKEY)( handle << 2 | HKCR_FLAG );
+
+end:
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return ret;
+}
+
+static HKEY resolve_hkcr( HKEY hkey )
+{
+ HKEY ret;
+ opened_hkcr_t *hkcr;
+
+ hkcr = get_opened_hkcr(hkey);
+ if (!hkcr) return NULL;
+
+ EnterCriticalSection( &hkcr_handles_cs );
+ ret = hkcr->hklm;
+ LeaveCriticalSection( &hkcr_handles_cs );
+
+ return ret;
+}
+
+static LSTATUS WINAPI create_hkcr( HKEY hkey, const WCHAR *name, WCHAR *class,
+ DWORD options, REGSAM samDesired,
+ SECURITY_ATTRIBUTES *sa, HKEY *retkey, DWORD *dispos )
+{
+ HKEY hklm;
+ opened_hkcr_t *hkcr = NULL;
+ LSTATUS res;
+ *retkey = 0;
+
+ if (hkey != HKEY_LOCAL_MACHINE) hkey = resolve_hkcr( hkey );
+ res = RegCreateKeyExW( hkey, name, 0, class, options, samDesired, sa, &hklm, dispos );
+ if (res) return res;
+
+ if ((res = create_hkcr_struct(retkey, &hkcr)))
+ {
+ RegCloseKey( hklm );
+ return res;
+ }
+
+ EnterCriticalSection( &hkcr_handles_cs );
+ hkcr->hklm = hklm;
+ LeaveCriticalSection( &hkcr_handles_cs );
+
+ return res;
+}
+
+static LSTATUS WINAPI open_hkcr( HKEY hkey, const WCHAR *name, REGSAM samDesired, HKEY *retkey )
+{
+ HKEY hklm;
+ opened_hkcr_t *hkcr = NULL;
+ LSTATUS res;
+ *retkey = 0;
+
+ hkey = resolve_hkcr( hkey );
+ res = RegOpenKeyExW( hkey, name, 0, samDesired, &hklm );
+ if (res) return res;
+
+ if ((res = create_hkcr_struct(retkey, &hkcr)))
+ {
+ RegCloseKey( hklm );
+ return res;
+ }
+
+ EnterCriticalSection( &hkcr_handles_cs );
+ hkcr->hklm = hklm;
+ LeaveCriticalSection( &hkcr_handles_cs );
+
+ return res;
+}
+
+
/* create one of the HKEY_* special root keys */
static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
{
HKEY ret = 0;
int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
- if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
+ if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
+ {
+ if (create_hkcr( HKEY_LOCAL_MACHINE, name_CLASSES_ROOT + 8, NULL, 0, access, NULL, &hkey, NULL )) return 0;
+ }
+ else if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
{
if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
@@ -267,7 +430,7 @@ static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
ret = hkey;
else
- NtClose( hkey ); /* somebody beat us to it */
+ RegCloseKey( hkey );
}
else
ret = hkey;
@@ -294,6 +457,22 @@ static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
return ret;
}
+static LSTATUS close_hkcr( HKEY hkey )
+{
+ opened_hkcr_t *hkcr;
+
+ hkcr = get_opened_hkcr(hkey);
+ if (!hkcr) return ERROR_INVALID_HANDLE;
+
+ EnterCriticalSection( &hkcr_handles_cs );
+ RegCloseKey( hkcr->hklm );
+ hkcr->init = FALSE;
+ hkcr_handles_free[nb_hkcr_handles_free++] = (UINT_PTR)hkey >> 2;
+ LeaveCriticalSection( &hkcr_handles_cs );
+
+ return ERROR_SUCCESS;
+}
+
/******************************************************************************
* RegOverridePredefKey [ADVAPI32.@]
@@ -338,6 +517,7 @@ LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR
if (reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey)) return create_hkcr( hkey, name, class, options, access, sa, retkey, dispos );
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
@@ -393,6 +573,20 @@ LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR cl
}
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey))
+ {
+ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+ NtCurrentTeb()->StaticUnicodeBuffer,
+ sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+ RtlInitAnsiString( &classA, class );
+ if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
+ {
+ status = create_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, classW.Buffer, options, access, sa, retkey, dispos );
+ RtlFreeUnicodeString( &classW );
+ }
+ return status;
+ }
+
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
@@ -468,6 +662,8 @@ LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM acc
if (!retkey) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey)) return open_hkcr( hkey, name, access, retkey );
+
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
attr.ObjectName = &nameW;
@@ -515,6 +711,14 @@ LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM acce
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey))
+ {
+ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+ NtCurrentTeb()->StaticUnicodeBuffer,
+ sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+ return open_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, access, retkey );
+ }
+
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
@@ -641,6 +845,8 @@ LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_
if (reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
status = NtEnumerateKey( hkey, index, KeyNodeInformation,
buffer, sizeof(buffer), &total_size );
@@ -705,6 +911,8 @@ LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_l
if (reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
status = NtEnumerateKey( hkey, index, KeyNodeInformation,
buffer, sizeof(buffer), &total_size );
@@ -832,6 +1040,8 @@ LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPD
if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
@@ -1018,6 +1228,8 @@ LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDW
if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
@@ -1080,6 +1292,7 @@ LSTATUS WINAPI RegCloseKey( HKEY hkey )
{
if (!hkey) return ERROR_INVALID_HANDLE;
if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
+ if (IS_HKCR(hkey)) return close_hkcr( hkey );
return RtlNtStatusToDosError( NtClose( hkey ) );
}
@@ -1096,6 +1309,16 @@ LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD re
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey))
+ {
+ if (!(ret = open_hkcr( hkey, name, access | DELETE, &tmp )))
+ {
+ ret = RtlNtStatusToDosError( NtDeleteKey( resolve_hkcr(tmp) ) );
+ close_hkcr( tmp );
+ }
+ return ret;
+ }
+
access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
{
@@ -1130,6 +1353,19 @@ LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD res
if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey))
+ {
+ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+ NtCurrentTeb()->StaticUnicodeBuffer,
+ sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+ if (!(ret = open_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, access | DELETE, &tmp )))
+ {
+ ret = RtlNtStatusToDosError( NtDeleteKey( resolve_hkcr(tmp) ) );
+ close_hkcr( tmp );
+ }
+ return ret;
+ }
+
access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
{
@@ -1211,6 +1447,8 @@ LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
}
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
RtlInitUnicodeString( &nameW, name );
return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
}
@@ -1249,6 +1487,8 @@ LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD typ
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
if (is_string( type )) /* need to convert to Unicode */
{
DWORD lenW;
@@ -1354,6 +1594,8 @@ LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDW
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
RtlInitUnicodeString( &name_str, name );
if (data) total_size = min( sizeof(buffer), *count + info_size );
@@ -1444,6 +1686,8 @@ LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWO
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
if (count) datalen = *count;
if (!data && count) *count = 0;
@@ -1882,6 +2126,8 @@ LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
if (data) total_size += *count;
total_size = min( sizeof(buffer), total_size );
@@ -1967,6 +2213,8 @@ LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_c
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
if (data) total_size += *count;
total_size = min( sizeof(buffer), total_size );
@@ -2486,6 +2734,7 @@ LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInform
LSTATUS WINAPI RegFlushKey( HKEY hkey )
{
hkey = get_special_root_hkey( hkey, 0 );
+ if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
if (!hkey) return ERROR_INVALID_HANDLE;
return RtlNtStatusToDosError( NtFlushKey( hkey ) );
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index 3df1cd2..875db01 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -31,7 +31,9 @@
#include "winerror.h"
#include "aclapi.h"
-#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
+#define SPECIAL_HKEY_MASK 0x80000003
+#define HKCR_FLAG 2
+#define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
static HKEY hkey_main;
static DWORD GLE;
@@ -2618,7 +2620,7 @@ static void test_classesroot_mask(void)
res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
- todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
+ ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
"hkcr mask not set in %p\n", hkey);
RegCloseKey( hkey );
--
1.8.2.3
More information about the wine-patches
mailing list