[PATCH 1/2] advapi32: HKCR merge: foundation
George Stephanos
gaf.stephanos at gmail.com
Mon Sep 16 09:05:22 CDT 2013
---
dlls/advapi32/registry.c | 250 ++++++++++++++++++++++++++++++++++++++++-
dlls/advapi32/tests/registry.c | 6 +-
2 files changed, 252 insertions(+), 4 deletions(-)
diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index c01e125..ab16a12 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -79,6 +79,30 @@ static const WCHAR * const root_key_names[] =
static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
static BOOL hkcu_cache_disabled;
+typedef struct {
+ 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;
+
+#define SPECIAL_HKEY_MASK 0x80000003
+#define HKCR_FLAG 2
+#define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
+
static const int is_win64 = (sizeof(void *) > sizeof(int));
/* check if value type needs string conversion (Ansi<->Unicode) */
@@ -224,13 +248,138 @@ static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *a
}
+static LSTATUS create_hkcr_struct( HKEY *hkey, opened_hkcr_t **hkcr )
+{
+ UINT_PTR handle = nb_hkcr_handles, i;
+ LSTATUS ret = ERROR_SUCCESS;
+
+ EnterCriticalSection( &hkcr_handles_cs );
+
+ for (i = 0; i < nb_hkcr_handles; i++)
+ {
+ if (!hkcr_handles[i])
+ {
+ handle = i;
+ break;
+ }
+ }
+
+ if (handle >= nb_hkcr_handles)
+ {
+ opened_hkcr_t **new_array;
+ if (hkcr_handles)
+ new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, hkcr_handles,
+ (nb_hkcr_handles * 2) * sizeof(*new_array) );
+ else
+ new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ 16 * sizeof(*new_array) );
+
+ if (!new_array)
+ {
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+ hkcr_handles = new_array;
+
+ nb_hkcr_handles = !nb_hkcr_handles ? 16 : nb_hkcr_handles * 2;
+ }
+
+ *hkcr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(opened_hkcr_t) );
+
+ if (*hkcr)
+ {
+ hkcr_handles[handle] = *hkcr;
+ *hkey = (HKEY)( handle << 2 | HKCR_FLAG );
+ }
+ else ret = ERROR_NOT_ENOUGH_MEMORY;
+
+end:
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return ret;
+}
+
+static HKEY resolve_hkcr( HKEY hkey )
+{
+ HKEY ret;
+ UINT_PTR idx = (UINT_PTR)hkey >> 2;
+ opened_hkcr_t *hkcr;
+ if (idx <= nb_hkcr_handles)
+ {
+ EnterCriticalSection( &hkcr_handles_cs );
+ hkcr = hkcr_handles[idx];
+
+ if (!hkcr)
+ {
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return NULL;
+ }
+
+ ret = hkcr->hklm;
+
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return ret;
+ }
+ return NULL;
+}
+
+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;
+ }
+
+ hkcr->hklm = hklm;
+
+ 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;
+ }
+
+ hkcr->hklm = hklm;
+
+ 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 );
@@ -258,7 +407,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 );
return ret;
}
@@ -276,6 +425,33 @@ static inline HKEY get_special_root_hkey( HKEY hkey )
return ret;
}
+static LSTATUS close_hkcr( HKEY hkey )
+{
+ UINT_PTR idx = (UINT_PTR)hkey >> 2;
+ opened_hkcr_t *hkcr;
+
+ if (idx <= nb_hkcr_handles)
+ {
+ EnterCriticalSection( &hkcr_handles_cs );
+
+ hkcr = hkcr_handles[idx];
+ if (!hkcr)
+ {
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ RegCloseKey(hkcr->hklm);
+
+ HeapFree( GetProcessHeap(), 0, hkcr );
+ hkcr_handles[idx] = 0;
+
+ LeaveCriticalSection( &hkcr_handles_cs );
+ return ERROR_SUCCESS;
+ }
+ return ERROR_INVALID_HANDLE;
+}
+
/******************************************************************************
* RegOverridePredefKey [ADVAPI32.@]
@@ -320,6 +496,7 @@ LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR
if (reserved) return ERROR_INVALID_PARAMETER;
if (!(hkey = get_special_root_hkey( hkey ))) 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;
@@ -375,6 +552,20 @@ LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR cl
}
if (!(hkey = get_special_root_hkey( hkey ))) 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;
@@ -450,6 +641,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 ))) 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;
@@ -497,6 +690,14 @@ LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM acce
if (!(hkey = get_special_root_hkey( hkey ))) 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;
@@ -623,6 +824,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 ))) 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 );
@@ -687,6 +890,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 ))) 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 );
@@ -814,6 +1019,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 ))) 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;
@@ -1000,6 +1207,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 ))) 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;
@@ -1062,6 +1271,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 ) );
}
@@ -1078,6 +1288,16 @@ LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD re
if (!(hkey = get_special_root_hkey( hkey ))) 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 )))
{
@@ -1112,6 +1332,19 @@ LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD res
if (!(hkey = get_special_root_hkey( hkey ))) 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 )))
{
@@ -1193,6 +1426,8 @@ LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
}
if (!(hkey = get_special_root_hkey( hkey ))) 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 ) );
}
@@ -1231,6 +1466,8 @@ LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD typ
if (!(hkey = get_special_root_hkey( hkey ))) 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;
@@ -1336,6 +1573,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 ))) 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 );
@@ -1426,6 +1665,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 ))) 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;
@@ -1864,6 +2105,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 ))) 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 );
@@ -1949,6 +2192,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 ))) 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 );
@@ -2468,6 +2713,7 @@ LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInform
LSTATUS WINAPI RegFlushKey( HKEY hkey )
{
hkey = get_special_root_hkey( hkey );
+ 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 981ac93..027728a 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;
@@ -2584,7 +2586,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