From 09e5a3c2629ddcc795a69f70b0672f393abd96ed Mon Sep 17 00:00:00 2001 From: George Stephanos Date: Sat, 24 Aug 2013 20:30:05 +0200 Subject: [PATCH 1/3] advapi32: HKCR merge: foundation --- dlls/advapi32/registry.c | 249 ++++++++++++++++++++++++++++++++++++++++- dlls/advapi32/tests/registry.c | 2 +- 2 files changed, 248 insertions(+), 3 deletions(-) diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index c01e125..5768272 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -79,6 +79,29 @@ 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 HKCR_MASK 2 +#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == HKCR_MASK) + static const int is_win64 = (sizeof(void *) > sizeof(int)); /* check if value type needs string conversion (Ansi<->Unicode) */ @@ -224,13 +247,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_MASK ); + } + 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 +406,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 +424,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 +495,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 +551,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 +640,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 +689,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 +823,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 +889,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 +1018,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 +1206,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 +1270,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 +1287,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 +1331,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 +1425,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 +1465,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 +1572,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 +1664,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 +2104,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 +2191,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 +2712,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..d94757f 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2584,7 +2584,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