From f2ef2c2bb2d772dcccae0539e94a4ac3a6a4504d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 13 Sep 2002 21:42:28 +0000 Subject: [PATCH] Handle special registry root keys directly in advapi32, and avoid using them in kernel and ntdll. --- dlls/advapi32/registry.c | 123 ++++++++++++++++++++++++++++++++++++--- dlls/ntdll/cdrom.c | 4 +- dlls/ntdll/reg.c | 2 +- misc/registry.c | 84 +++++++++++++------------- win32/device.c | 101 +++++++++++++++++++++++++++++++- 5 files changed, 262 insertions(+), 52 deletions(-) diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index bc8be94b204..c67372a12d9 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -39,6 +39,47 @@ WINE_DEFAULT_DEBUG_CHANNEL(reg); +/* allowed bits for access mask */ +#define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED) + +#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT +#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA +#define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1) + +static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS]; + +static const WCHAR name_CLASSES_ROOT[] = + {'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'C','l','a','s','s','e','s',0}; +static const WCHAR name_LOCAL_MACHINE[] = + {'M','a','c','h','i','n','e',0}; +static const WCHAR name_USERS[] = + {'U','s','e','r',0}; +static const WCHAR name_PERFORMANCE_DATA[] = + {'P','e','r','f','D','a','t','a',0}; +static const WCHAR name_CURRENT_CONFIG[] = + {'M','a','c','h','i','n','e','\\', + 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\', + 'C','u','r','r','e','n','t',0}; +static const WCHAR name_DYN_DATA[] = + {'D','y','n','D','a','t','a',0}; + +#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key } +static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] = +{ + DECL_STR(CLASSES_ROOT), + { 0, 0, NULL }, /* HKEY_CURRENT_USER is determined dynamically */ + DECL_STR(LOCAL_MACHINE), + DECL_STR(USERS), + DECL_STR(PERFORMANCE_DATA), + DECL_STR(CURRENT_CONFIG), + DECL_STR(DYN_DATA) +}; +#undef DECL_STR + /* check if value type needs string conversion (Ansi<->Unicode) */ inline static int is_string( DWORD type ) @@ -52,8 +93,51 @@ inline static int is_version_nt(void) return !(GetVersion() & 0x80000000); } -/* allowed bits for access mask */ -#define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED) +/* create one of the HKEY_* special root keys */ +static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) +{ + HKEY ret = 0; + int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST; + + if (hkey == HKEY_CURRENT_USER) + { + if (RtlOpenCurrentUser( access, &hkey )) return 0; + TRACE( "HKEY_CURRENT_USER -> %08x\n", hkey ); + } + else + { + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &root_key_names[idx]; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0; + TRACE( "%s -> %08x\n", debugstr_w(attr.ObjectName->Buffer), hkey ); + } + + if (!(ret = InterlockedCompareExchange( (PLONG)&special_root_keys[idx], hkey, 0 ))) + ret = hkey; + else + NtClose( hkey ); /* somebody beat us to it */ + return ret; +} + +/* map the hkey from special root to normal key if necessary */ +inline static HKEY get_special_root_hkey( HKEY hkey ) +{ + HKEY ret = hkey; + + if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST)) + { + if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST])) + ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS ); + } + return ret; +} + /****************************************************************************** * RegCreateKeyExW [ADVAPI32.@] @@ -83,6 +167,7 @@ DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR cl if (reserved) return ERROR_INVALID_PARAMETER; if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; attr.Length = sizeof(attr); attr.RootDirectory = hkey; @@ -115,6 +200,7 @@ DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR clas if (reserved) return ERROR_INVALID_PARAMETER; if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */ else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; attr.Length = sizeof(attr); attr.RootDirectory = hkey; @@ -187,6 +273,8 @@ DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM acce OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &nameW; @@ -209,6 +297,8 @@ DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM acces if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */ + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; @@ -295,8 +385,7 @@ DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_le name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - - if (!hkey) return ERROR_INVALID_HANDLE; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; status = NtEnumerateKey( hkey, index, KeyNodeInformation, buffer, sizeof(buffer), &total_size ); @@ -358,8 +447,7 @@ DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - - if (!hkey) return ERROR_INVALID_HANDLE; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; status = NtEnumerateKey( hkey, index, KeyNodeInformation, buffer, sizeof(buffer), &total_size ); @@ -464,6 +552,7 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); if (status && status != STATUS_BUFFER_OVERFLOW) goto done; @@ -612,6 +701,7 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); if (status && status != STATUS_BUFFER_OVERFLOW) goto done; @@ -694,6 +784,8 @@ DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name ) DWORD ret; HKEY tmp; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + if (!name || !*name) { ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) ); @@ -726,6 +818,8 @@ DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name ) DWORD ret; HKEY tmp; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + if (!name || !*name) { ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) ); @@ -788,6 +882,7 @@ DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved, if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)]) count += sizeof(WCHAR); } + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; RtlInitUnicodeString( &nameW, name ); return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) ); @@ -814,6 +909,8 @@ DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type, if (data[count-1] && !data[count]) count++; } + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + if (is_string( type )) /* need to convert to Unicode */ { DWORD lenW; @@ -916,6 +1013,7 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 ); if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; RtlInitUnicodeString( &name_str, name ); @@ -983,6 +1081,7 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; RtlInitAnsiString( &nameA, name ); if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, @@ -1132,6 +1231,7 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co /* NT only checks count, not val_count */ if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); if (data) total_size += *count; @@ -1214,6 +1314,7 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou /* NT only checks count, not val_count */ if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); if (data) total_size += *count; @@ -1313,6 +1414,9 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name ) { UNICODE_STRING nameW; + + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + RtlInitUnicodeString( &nameW, name ); return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) ); } @@ -1326,12 +1430,12 @@ DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name ) STRING nameA; NTSTATUS status; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + RtlInitAnsiString( &nameA, name ); if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, &nameA, FALSE ))) - { status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString ); - } return RtlNtStatusToDosError( status ); } @@ -1353,6 +1457,7 @@ LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename ) if (!filename || !*filename) return ERROR_INVALID_PARAMETER; if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; len = strlenW( subkey ) * sizeof(WCHAR); if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER; @@ -1393,6 +1498,7 @@ LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename ) if (!filename || !*filename) return ERROR_INVALID_PARAMETER; if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH ))) return ERROR_INVALID_PARAMETER; @@ -1439,6 +1545,7 @@ LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa ) TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa ); if (!file || !*file) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; err = GetLastError(); GetFullPathNameA( file, sizeof(buffer), buffer, &name ); diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c index f53a39285ed..206802c2197 100644 --- a/dlls/ntdll/cdrom.c +++ b/dlls/ntdll/cdrom.c @@ -188,7 +188,7 @@ void CDROM_InitRegistry(int dev) DWORD disp; attr.Length = sizeof(attr); - attr.RootDirectory = HKEY_LOCAL_MACHINE; + attr.RootDirectory = 0; attr.ObjectName = &nameW; attr.Attributes = 0; attr.SecurityDescriptor = NULL; @@ -198,7 +198,7 @@ void CDROM_InitRegistry(int dev) return; /* Ensure there is Scsi key */ - if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "HARDWARE\\DEVICEMAP\\Scsi" ) || + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) || NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, &disp )) { diff --git a/dlls/ntdll/reg.c b/dlls/ntdll/reg.c index fb0a3a325ba..940a0aa3e61 100644 --- a/dlls/ntdll/reg.c +++ b/dlls/ntdll/reg.c @@ -621,7 +621,7 @@ DWORD WINAPI RtlOpenCurrentUser( RtlFormatCurrentUserKeyPath(&ObjectName); InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL); - ret = NtOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); + ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL); RtlFreeUnicodeString(&ObjectName); return ret; } diff --git a/misc/registry.c b/misc/registry.c index 945bf709452..d7e20639431 100644 --- a/misc/registry.c +++ b/misc/registry.c @@ -1086,7 +1086,8 @@ static void _save_at_exit(HKEY hkey,LPCSTR path) } /* configure save files and start the periodic saving timer [Internal] */ -static void _init_registry_saving( HKEY hkey_users_default ) +static void _init_registry_saving( HKEY hkey_local_machine, HKEY hkey_current_user, + HKEY hkey_users_default ) { int all; int period = 0; @@ -1106,8 +1107,8 @@ static void _init_registry_saving( HKEY hkey_users_default ) if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1)) { - _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER ); - _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE); + _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER ); + _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE); _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT); } @@ -1503,7 +1504,8 @@ static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_typ } /* load all native windows registry files [Internal] */ -static void _load_windows_registry( HKEY hkey_users_default ) +static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user, + HKEY hkey_users_default ) { int reg_type; WCHAR windir[MAX_PATHNAME_LEN]; @@ -1515,7 +1517,6 @@ static void _load_windows_registry( HKEY hkey_users_default ) static const WCHAR WineW[] = {'W','i','n','e',0}; static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0}; static const WCHAR empty_strW[] = { 0 }; - static const WCHAR Machine[] = {'M','a','c','h','i','n','e',0}; static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0}; static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0}; static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\', @@ -1545,7 +1546,7 @@ static void _load_windows_registry( HKEY hkey_users_default ) /* user specific ntuser.dat */ if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) { strcatW(path, ntuser_datW); - _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1); + _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1); } /* default user.dat */ @@ -1576,18 +1577,13 @@ static void _load_windows_registry( HKEY hkey_users_default ) NtClose( hkey ); } - RtlInitUnicodeString( &nameW, Machine ); - if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) - { - strcpyW(path, windir); - strcatW(path, samW); - _convert_and_load_native_registry(path,hkey,REG_WINNT,0); + strcpyW(path, windir); + strcatW(path, samW); + _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0); - strcpyW(path,windir); - strcatW(path, securityW); - _convert_and_load_native_registry(path,hkey,REG_WINNT,0); - NtClose( hkey ); - } + strcpyW(path,windir); + strcatW(path, securityW); + _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0); /* this key is generated when the nt-core booted successfully */ RtlInitUnicodeString( &nameW, Clone ); @@ -1602,16 +1598,11 @@ static void _load_windows_registry( HKEY hkey_users_default ) static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0}; static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0}; - RtlInitUnicodeString( &nameW, Machine ); - if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) - { - _convert_and_load_native_registry(system_1stW,hkey,REG_WIN95,0); + _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0); - strcpyW(path, windir); - strcatW(path, system_datW); - _convert_and_load_native_registry(path,hkey,REG_WIN95,0); - NtClose( hkey ); - } + strcpyW(path, windir); + strcatW(path, system_datW); + _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0); RtlInitUnicodeString( &nameW, ClassesRootW ); if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) @@ -1625,7 +1616,7 @@ static void _load_windows_registry( HKEY hkey_users_default ) if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) { /* user specific user.dat */ strcatW(path, user_datW); - _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1); + _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1); /* default user.dat */ if (hkey_users_default) { @@ -1636,7 +1627,7 @@ static void _load_windows_registry( HKEY hkey_users_default ) } else { strcpyW(path, windir); strcatW(path, user_datW); - _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1); + _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1); } break; } @@ -1658,19 +1649,20 @@ static void _load_windows_registry( HKEY hkey_users_default ) } /* load global registry files (stored in /etc/wine) [Internal] */ -static void _load_global_registry(void) +static void _load_global_registry( HKEY hkey_local_machine, HKEY hkey_users ) { TRACE("(void)\n"); /* Load the global HKU hive directly from sysconfdir */ - load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ); + load_wine_registry( hkey_users, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ); /* Load the global machine defaults directly from sysconfdir */ - load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ); + load_wine_registry( hkey_local_machine, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ); } /* load home registry files (stored in ~/.wine) [Internal] */ -static void _load_home_registry( HKEY hkey_users_default ) +static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user, + HKEY hkey_users_default ) { LPCSTR confdir = wine_get_config_dir(); LPSTR tmp = _xmalloc(strlen(confdir)+20); @@ -1681,11 +1673,11 @@ static void _load_home_registry( HKEY hkey_users_default ) strcpy(tmp,confdir); strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER); - load_wine_registry(HKEY_CURRENT_USER,tmp); + load_wine_registry(hkey_current_user,tmp); strcpy(tmp,confdir); strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE); - load_wine_registry(HKEY_LOCAL_MACHINE,tmp); + load_wine_registry(hkey_local_machine,tmp); free(tmp); } @@ -1693,11 +1685,13 @@ static void _load_home_registry( HKEY hkey_users_default ) /* load all registry (native and global and home) */ void SHELL_LoadRegistry( void ) { - HKEY hkey_users_default; + HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user; OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; - static const WCHAR DefaultW[] = {'U','s','e','r','\\','.','D','e','f','a','u','l','t',0}; + static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0}; + static const WCHAR UserW[] = {'U','s','e','r',0}; + static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0}; static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0}; static const WCHAR load_win_reg_filesW[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; static const WCHAR load_global_reg_filesW[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; @@ -1714,22 +1708,32 @@ void SHELL_LoadRegistry( void ) attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, MachineW ); + NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); + RtlInitUnicodeString( &nameW, UserW ); + NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); + + attr.RootDirectory = hkey_users; RtlInitUnicodeString( &nameW, DefaultW ); if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) { ERR("Cannot create HKEY_USERS/.Default\n" ); ExitProcess(1); } + RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user ); _set_registry_levels(0,0,0); _allocate_default_keys(); if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1)) - _load_windows_registry( hkey_users_default ); + _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default ); if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1)) - _load_global_registry(); + _load_global_registry( hkey_local_machine, hkey_users ); _set_registry_levels(1,0,0); if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1)) - _load_home_registry( hkey_users_default ); - _init_registry_saving( hkey_users_default ); + _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default ); + _init_registry_saving( hkey_local_machine, hkey_current_user, hkey_users_default ); NtClose(hkey_users_default); + NtClose(hkey_current_user); + NtClose(hkey_users); + NtClose(hkey_local_machine); } diff --git a/win32/device.c b/win32/device.c index 2e11c033c83..9fb573c7c44 100644 --- a/win32/device.c +++ b/win32/device.c @@ -570,12 +570,95 @@ void VxDCall( DWORD service, CONTEXT86 *context ) */ +#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT +#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA +#define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1) + +static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS]; + +static const WCHAR name_CLASSES_ROOT[] = + {'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'C','l','a','s','s','e','s',0}; +static const WCHAR name_LOCAL_MACHINE[] = + {'M','a','c','h','i','n','e',0}; +static const WCHAR name_USERS[] = + {'U','s','e','r',0}; +static const WCHAR name_PERFORMANCE_DATA[] = + {'P','e','r','f','D','a','t','a',0}; +static const WCHAR name_CURRENT_CONFIG[] = + {'M','a','c','h','i','n','e','\\', + 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\', + 'C','u','r','r','e','n','t',0}; +static const WCHAR name_DYN_DATA[] = + {'D','y','n','D','a','t','a',0}; + +#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key } +static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] = +{ + DECL_STR(CLASSES_ROOT), + { 0, 0, NULL }, /* HKEY_CURRENT_USER is determined dynamically */ + DECL_STR(LOCAL_MACHINE), + DECL_STR(USERS), + DECL_STR(PERFORMANCE_DATA), + DECL_STR(CURRENT_CONFIG), + DECL_STR(DYN_DATA) +}; +#undef DECL_STR + + /* check if value type needs string conversion (Ansi<->Unicode) */ inline static int is_string( DWORD type ) { return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); } +/* create one of the HKEY_* special root keys */ +static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) +{ + HKEY ret = 0; + int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST; + + if (hkey == HKEY_CURRENT_USER) + { + if (RtlOpenCurrentUser( access, &hkey )) return 0; + } + else + { + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &root_key_names[idx]; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0; + } + + if (!(ret = InterlockedCompareExchange( (PLONG)&special_root_keys[idx], hkey, 0 ))) + ret = hkey; + else + NtClose( hkey ); /* somebody beat us to it */ + return ret; +} + +/* map the hkey from special root to normal key if necessary */ +inline static HKEY get_special_root_hkey( HKEY hkey ) +{ + HKEY ret = hkey; + + if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST)) + { + if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST])) + ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS ); + } + return ret; +} + + /****************************************************************************** * VMM_RegCreateKeyA */ @@ -586,6 +669,8 @@ static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey ) ANSI_STRING nameA; NTSTATUS status; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &nameW; @@ -614,6 +699,8 @@ DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM ac STRING nameA; NTSTATUS status; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &nameW; @@ -649,7 +736,9 @@ static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name ) DWORD ret; HKEY tmp; - if (!name || !*name) return NtDeleteKey( hkey ); + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + + if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) ); if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp ))) { ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); @@ -670,6 +759,8 @@ static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD t WCHAR *dataW = NULL; NTSTATUS status; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + if (is_string(type)) { DWORD lenW; @@ -726,6 +817,8 @@ static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name ) STRING nameA; NTSTATUS status; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + RtlInitAnsiString( &nameA, name ); if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) { @@ -751,6 +844,7 @@ static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPD static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; RtlInitAnsiString( &nameA, name ); if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) @@ -862,6 +956,7 @@ static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val /* NT only checks count, not val_count */ if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); if (data) total_size += *count; @@ -957,6 +1052,8 @@ static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; DWORD total_size; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, buffer, sizeof(buffer), &total_size ); @@ -1003,6 +1100,8 @@ static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subke KEY_FULL_INFORMATION info; DWORD total_size; + if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; + status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size ); if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );