From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 179 +++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 78 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 135ff48bf7e..f490c849c17 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -140,82 +140,10 @@ static HKEY get_perflib_key( HANDLE key ) return key; }
-/* wrapper for NtCreateKey that creates the key recursively if necessary */ -static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, - const UNICODE_STRING *class, ULONG options, PULONG dispos ) -{ - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; - HANDLE subkey, root = attr->RootDirectory; - - if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - { - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); - UNICODE_STRING str; - - /* don't try to create registry root */ - if (!attr->RootDirectory && len > 10 && !wcsnicmp( buffer, L"\Registry\", 10 )) i += 10; - - while (i < len && buffer[i] != '\') i++; - if (i == len && !force_wow32) return status; - - attrs = attr->Attributes; - attr->ObjectName = &str; - - for (;;) - { - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - if (force_wow32 && pos) - { - if (is_wow6432node( &str )) force_wow32 = FALSE; - else if ((subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - attr->Attributes = attrs; - status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - } - else - { - attr->Attributes = attrs & ~OBJ_OPENLINK; - status = NtCreateKey( &subkey, access, attr, 0, class, - options & ~REG_OPTION_CREATE_LINK, dispos ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (!NT_SUCCESS(status)) return status; - if (i == len) break; - attr->RootDirectory = subkey; - while (i < len && buffer[i] == '\') i++; - pos = i; - while (i < len && buffer[i] != '\') i++; - } - } - attr->RootDirectory = subkey; - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - if (status == STATUS_PREDEFINED_HANDLE) - { - attr->RootDirectory = get_perflib_key( attr->RootDirectory ); - status = STATUS_SUCCESS; - } - *retkey = attr->RootDirectory; - return status; -} - static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { + BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); + ACCESS_MASK access_64 = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY; DWORD i = 0, len = name->Length / sizeof(WCHAR); WCHAR *buffer = name->Buffer; OBJECT_ATTRIBUTES attr; @@ -239,14 +167,14 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR if (i == len) { if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; - status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options ); } else { if (!(options & REG_OPTION_OPEN_LINK)) attr.Attributes &= ~OBJ_OPENLINK; - status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options & ~REG_OPTION_OPEN_LINK ); + options &= ~REG_OPTION_OPEN_LINK; }
+ status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); if (status == STATUS_PREDEFINED_HANDLE) { *subkey = get_perflib_key( *subkey ); @@ -260,7 +188,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR name->Buffer += i; name->Length -= i * sizeof(WCHAR);
- if (!is_wow6432node( name )) + if (is_wow64_key && !is_wow6432node( name )) { HKEY wow6432node = open_wow6432node( *subkey ); if (wow6432node) @@ -274,7 +202,6 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR return status; }
- /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) { @@ -312,6 +239,102 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK ac return status; }
+static NTSTATUS create_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, + const UNICODE_STRING *class, PULONG dispos ) +{ + DWORD i = 0, len = name->Length / sizeof(WCHAR); + WCHAR *buffer = name->Buffer; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + NTSTATUS status; + + attr.Length = sizeof(attr); + attr.RootDirectory = (HANDLE)root; + attr.ObjectName = &str; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (i < len && buffer[i] == '\') return STATUS_OBJECT_PATH_INVALID; + while (i < len && buffer[i] != '\') i++; + + str.Buffer = name->Buffer; + str.Length = i * sizeof(WCHAR); + + if (i == len) + { + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + } + else + { + options &= ~REG_OPTION_CREATE_LINK; + } + + status = NtCreateKey( (HANDLE *)subkey, access, &attr, 0, class, options, dispos ); + if (status == STATUS_PREDEFINED_HANDLE) + { + *subkey = get_perflib_key( *subkey ); + status = STATUS_SUCCESS; + } + + if (!status) + { + while (i < len && buffer[i] == '\') i++; + + name->Buffer += i; + name->Length -= i * sizeof(WCHAR); + } + + return status; +} + +/* wrapper for NtCreateKey that creates the key recursively if necessary */ +static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, + const UNICODE_STRING *class, ULONG options, PULONG dispos ) +{ + HKEY subkey, root = attr->RootDirectory, subkey_root = root; + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + UNICODE_STRING name; + + *retkey = NULL; + + name.Buffer = attr->ObjectName->Buffer; + name.Length = attr->ObjectName->Length; + + while (name.Length) + { + status = open_subkey( &subkey, subkey_root, &name, options & REG_OPTION_OPEN_LINK, access ); + if (status) break; + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + + if (!status && (options & REG_OPTION_CREATE_LINK)) + { + NtClose( subkey_root ); + status = STATUS_OBJECT_NAME_COLLISION; + } + + if (!status) + if (dispos) *dispos = REG_OPENED_EXISTING_KEY; + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + status = STATUS_SUCCESS; + while (!status && name.Length) + { + status = create_subkey( &subkey, subkey_root, &name, options, access, class, dispos ); + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + } + + if (!status) + *retkey = subkey_root; + + return status; +} + /* create one of the HKEY_* special root keys */ static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) {