Initial implementation for registry application hives, this is a step forward to get Visual Studio to run. :-)
-- v6: server: save app hive into it's file when closing handle. server/registry: pass file name instead of file handle to server. kernelbase: Implement RegLoadAppKey. ntdll: Initial implementation for application hives. ntdll: Move NtLoadKey implementation to NtLoadKeyEx.
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/advapi32/tests/registry.c | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index df56b0968ee..e2707504c4f 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -1600,6 +1600,94 @@ static void test_reg_unload_key(void) DeleteFileA("saved_key.LOG"); }
+static void test_reg_load_app_key(void) +{ + DWORD ret; + HKEY key1; + HKEY key2; + HKEY childkey; + DWORD size1; + DWORD size2; + HANDLE hivefile; + + set_privileges(SE_BACKUP_NAME, FALSE); + set_privileges(SE_RESTORE_NAME, FALSE); + + /* Test with non existant file */ + ret = RegLoadAppKeyA("saved_app_key", &key1, KEY_READ, 0, 0); + ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key1 != NULL, "got a null key\n"); + + ret = GetFileAttributesA("saved_app_key"); + todo_wine ok(ret != -1, "hive file didn't got created.\n"); + + RegCloseKey(key1); + DeleteFileA("saved_app_key"); + + if (!set_privileges(SE_BACKUP_NAME, TRUE) || + !set_privileges(SE_RESTORE_NAME, FALSE)) + { + win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n"); + return; + } + + ret = RegSaveKeyA(hkey_main, "saved_app_key", NULL); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_ALREADY_EXISTS), "expected ERROR_SUCCESS, got %ld\n", ret); + + /* Test without process app key ownership */ + ret = RegLoadAppKeyA("saved_app_key", &key1, KEY_READ, 0, 0); + ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key1 != NULL, "got a null key\n"); + + ret = RegLoadAppKeyA("saved_app_key", &key2, KEY_READ, 0, 0); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_ALREADY_EXISTS) /* win7 */, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key2 != NULL || broken(key2 == NULL) /* win7 */, "got a null key\n"); + + RegCloseKey(key1); + RegCloseKey(key2); + + /* Test with process app key ownership */ + ret = RegLoadAppKeyA("saved_app_key", &key1, KEY_READ, REG_PROCESS_APPKEY, 0); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_ALREADY_EXISTS) /* win7 */, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key1 != NULL, "got a null key\n"); + + ret = RegLoadAppKeyA("saved_app_key", &key2, KEY_READ, 0, 0); + todo_wine ok(ret == ERROR_SHARING_VIOLATION || broken(ret == ERROR_ALREADY_EXISTS) /* win7 */, "expected ERROR_SHARING_VIOLATION, got %ld\n", ret); + todo_wine ok(key2 == NULL || broken(key2 != NULL), "expected null handle\n"); + + RegCloseKey(key1); + + ret = RegLoadAppKeyA("saved_app_key", &key2, KEY_READ, 0, 0); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_ALREADY_EXISTS) /* win7 */, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key2 != NULL || broken(key2 == NULL) /* win7 */, "got a null key\n"); + RegCloseKey(key2); + + + /* Check if the changes are saved to the file */ + hivefile = CreateFileA("saved_app_key", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + size1 = GetFileSize(hivefile, NULL); + CloseHandle(hivefile); + + ret = RegLoadAppKeyA("saved_app_key", &key1, KEY_READ | KEY_WRITE, 0, 0); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_ALREADY_EXISTS) /* win7 */, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(key1 != NULL, "got a null key\n"); + + ret = RegCreateKeyA(key1, "testkey", &childkey); + todo_wine ok(ret == ERROR_SUCCESS || broken(ret == ERROR_INVALID_HANDLE) /* win7 */, "error when creating testkey. %ld\n", ret); + RegCloseKey(key1); + + hivefile = CreateFileA("saved_app_key", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + size2 = GetFileSize(hivefile, NULL); + todo_wine ok(size2 > size1 || broken(size1 == size2) /* win7 */, "Expected file to increase size. %ld >= %ld\n", size1, size2); + CloseHandle(hivefile); + + DeleteFileA("saved_app_key"); + DeleteFileA("saved_app_key.LOG"); + +} + /* tests that show that RegConnectRegistry and OpenSCManager accept computer names without the \ prefix (what MSDN says). */ @@ -4485,6 +4573,7 @@ START_TEST(registry) test_classesroot_mask(); test_reg_save_key(); test_reg_load_key(); + test_reg_load_app_key(); test_reg_unload_key(); test_reg_copy_tree(); test_reg_delete_tree();
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/unix/loader.c | 1 + dlls/ntdll/unix/registry.c | 10 ++++++++++ dlls/wow64/registry.c | 24 ++++++++++++++++++++++++ dlls/wow64/syscall.h | 1 + include/winternl.h | 1 + 6 files changed, 38 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index c294490d544..7469763e7dc 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -244,6 +244,7 @@ @ stdcall -syscall NtLoadDriver(ptr) @ stdcall -syscall NtLoadKey2(ptr ptr long) @ stdcall -syscall NtLoadKey(ptr ptr) +@ stdcall -syscall NtLoadKeyEx(ptr ptr long long long long ptr ptr) @ stdcall -syscall NtLockFile(long long ptr ptr ptr ptr ptr ptr long long) # @ stub NtLockProductActivationKeys # @ stub NtLockRegistryKey diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index f58a716d08c..b78efddee1f 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -203,6 +203,7 @@ static void * const syscalls[] = NtLoadDriver, NtLoadKey, NtLoadKey2, + NtLoadKeyEx, NtLockFile, NtLockVirtualMemory, NtMakeTemporaryObject, diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 693a594e84b..fae969763e6 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -729,6 +729,16 @@ NTSTATUS WINAPI NtLoadKey2( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *fi return NtLoadKey( attr, file ); }
+/****************************************************************************** + * NtLoadKeyEx (NTDLL.@) + */ +NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags, HANDLE trustkey, + HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) +{ + FIXME( "(%p,%p,0x%08x,%p,%p,0x%08x,%p,%p) stub\n", attr, file, flags, trustkey, event, + access, roothandle, iostatus); + return STATUS_NOT_IMPLEMENTED; +}
/****************************************************************************** * NtUnloadKey (NTDLL.@) diff --git a/dlls/wow64/registry.c b/dlls/wow64/registry.c index dfb75d72bc7..6ced946766c 100644 --- a/dlls/wow64/registry.c +++ b/dlls/wow64/registry.c @@ -181,6 +181,30 @@ NTSTATUS WINAPI wow64_NtLoadKey2( UINT *args ) return NtLoadKey2( objattr_32to64( &attr, attr32 ), objattr_32to64( &file, file32 ), flags ); }
+/********************************************************************** + * wow64_NtLoadKeyEx + */ +NTSTATUS WINAPI wow64_NtLoadKeyEx( UINT *args ) +{ + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + OBJECT_ATTRIBUTES32 *file32 = get_ptr( &args ); + ULONG flags = get_ulong( &args ); + HANDLE trustkey = get_handle( &args ); + HANDLE event = get_handle( &args ); + ACCESS_MASK desired_access = get_ulong( &args ); + HANDLE *rootkey = get_ptr( &args ); + IO_STATUS_BLOCK32 *io32 = get_ptr( &args ); + + struct object_attr64 attr, file; + IO_STATUS_BLOCK io; + NTSTATUS status; + + status = NtLoadKeyEx( objattr_32to64( &attr, attr32 ), objattr_32to64( &file, file32 ), flags, + trustkey, event, desired_access, rootkey, iosb_32to64(&io, io32) ); + put_iosb(io32, &io); + return status; +} +
/********************************************************************** * wow64_NtNotifyChangeKey diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index 65fbca89f4f..b2b1ad6c2a8 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -104,6 +104,7 @@ SYSCALL_ENTRY( NtLoadDriver ) \ SYSCALL_ENTRY( NtLoadKey ) \ SYSCALL_ENTRY( NtLoadKey2 ) \ + SYSCALL_ENTRY( NtLoadKeyEx ) \ SYSCALL_ENTRY( NtLockFile ) \ SYSCALL_ENTRY( NtLockVirtualMemory ) \ SYSCALL_ENTRY( NtMakeTemporaryObject ) \ diff --git a/include/winternl.h b/include/winternl.h index 19354dd7ffb..24dd26af83c 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4024,6 +4024,7 @@ NTSYSAPI NTSTATUS WINAPI NtListenPort(HANDLE,PLPC_MESSAGE); NTSYSAPI NTSTATUS WINAPI NtLoadDriver(const UNICODE_STRING *); NTSYSAPI NTSTATUS WINAPI NtLoadKey(const OBJECT_ATTRIBUTES *,OBJECT_ATTRIBUTES *); NTSYSAPI NTSTATUS WINAPI NtLoadKey2(const OBJECT_ATTRIBUTES *,OBJECT_ATTRIBUTES *,ULONG); +NTSYSAPI NTSTATUS WINAPI NtLoadKeyEx(const OBJECT_ATTRIBUTES *, OBJECT_ATTRIBUTES *, ULONG, HANDLE, HANDLE, ACCESS_MASK, HANDLE *, IO_STATUS_BLOCK *); NTSYSAPI NTSTATUS WINAPI NtLockFile(HANDLE,HANDLE,PIO_APC_ROUTINE,void*,PIO_STATUS_BLOCK,PLARGE_INTEGER,PLARGE_INTEGER,ULONG*,BOOLEAN,BOOLEAN); NTSYSAPI NTSTATUS WINAPI NtLockVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG); NTSYSAPI NTSTATUS WINAPI NtMakeTemporaryObject(HANDLE);
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/ntdll/tests/reg.c | 118 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+)
diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index f3c4eb15da0..c2c6759ea43 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -150,6 +150,8 @@ static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); static NTSTATUS (WINAPI * pRtlCreateRegistryKey)(ULONG, PWSTR); static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *); static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN); +static NTSTATUS (WINAPI * pNtLoadKeyEx)(const OBJECT_ATTRIBUTES *, OBJECT_ATTRIBUTES *, ULONG, HANDLE, HANDLE, ACCESS_MASK, HANDLE*, IO_STATUS_BLOCK*); +static NTSTATUS (WINAPI * pNtUnloadKey)( OBJECT_ATTRIBUTES * ); static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE, void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN); static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*); @@ -193,6 +195,8 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtSetValueKey) NTDLL_GET_PROC(NtOpenKey) NTDLL_GET_PROC(NtNotifyChangeKey) + NTDLL_GET_PROC(NtLoadKeyEx) + NTDLL_GET_PROC(NtUnloadKey) NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath) NTDLL_GET_PROC(RtlCompareUnicodeString) NTDLL_GET_PROC(RtlReAllocateHeap) @@ -457,6 +461,19 @@ static void test_NtOpenKey(void) ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status ); pRtlFreeUnicodeString( &str );
+ /* test if application hive is accessible */ + pRtlCreateUnicodeStringFromAsciiz( &str, "\Registry\A" ); + status = pNtOpenKey(&key, KEY_READ, &attr); + todo_wine ok( status == STATUS_ACCESS_DENIED, "NtOpenKey failed: 0x%08lx\n", status ); + pNtClose( key ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "\Registry\A" ); + status = pNtOpenKey(&key, KEY_CREATE_SUB_KEY, &attr); + todo_wine ok( status == STATUS_ACCESS_DENIED, "NtOpenKey failed: 0x%08lx\n", status ); + pNtClose( key ); + pRtlFreeUnicodeString( &str ); + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr); ok(status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status); @@ -677,6 +694,12 @@ static void test_NtCreateKey(void) if (!status) pNtClose( subkey ); pRtlFreeUnicodeString( &str );
+ /* test if we can create a new application hive key */ + pRtlCreateUnicodeStringFromAsciiz( &str, "\Registry\A\FooTest" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + todo_wine ok( status == STATUS_ACCESS_DENIED || broken(status == STATUS_OBJECT_PATH_NOT_FOUND) /* win7 */, "NtCreateKey failed: 0x%08lx\n", status ); + pRtlFreeUnicodeString( &str ); + pNtClose(key); }
@@ -2268,6 +2291,100 @@ static void test_NtRenameKey(void) pNtClose(key); }
+static BOOL set_privileges(LPCSTR privilege, BOOL set) +{ + TOKEN_PRIVILEGES tp; + HANDLE hToken; + LUID luid; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + return FALSE; + + if(!LookupPrivilegeValueA(NULL, privilege, &luid)) + { + CloseHandle(hToken); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + + if (set) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + if (GetLastError() != ERROR_SUCCESS) + { + CloseHandle(hToken); + return FALSE; + } + + CloseHandle(hToken); + return TRUE; +} + +static void test_NtLoadKeyEx(void) +{ + NTSTATUS status; + DWORD size, attr; + CHAR *directory; + OBJECT_ATTRIBUTES destkey, file; + UNICODE_STRING str, filename; + HANDLE rootkey; + HANDLE hivefile; + + /* Create empty hive file */ + hivefile = CreateFileA("savedkey", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hivefile == INVALID_HANDLE_VALUE) + { + win_skip("error when creating file %ld\n", GetLastError()); + return; + } + CloseHandle(hivefile); + + size = GetFullPathNameA("savedkey", 0, NULL, NULL); + directory = malloc(size + 4); + strcpy(directory, "\??\"); + GetFullPathNameA("savedkey", size, &directory[4], NULL); + pRtlCreateUnicodeStringFromAsciiz(&filename, directory); + file.Length = sizeof(file); + + InitializeObjectAttributes(&file, &filename, OBJ_CASE_INSENSITIVE, 0, 0); + InitializeObjectAttributes(&destkey, &str, 0, 0, 0); + + /* Test for application flag (0x10) */ + pRtlCreateUnicodeStringFromAsciiz(&str, "\REGISTRY\A\test1"); + status = pNtLoadKeyEx(&destkey, &file, 0x10, 0, 0, 0, &rootkey, 0); + todo_wine ok(status == STATUS_ACCESS_DENIED || broken(status == STATUS_ACCESS_VIOLATION) /* win7 */, "NtLoadKeyEx failed: %lx\n", status); + + status = pNtLoadKeyEx(&destkey, &file, 0x10, 0, 0, GENERIC_ALL, &rootkey, 0); + todo_wine ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_VIOLATION) /* win7 */, "NtLoadKeyEx failed: %lx\n", status); + pNtClose(rootkey); + + DeleteFileA("savedkey"); + /* Test normal key load */ + if (!set_privileges(SE_RESTORE_NAME, TRUE) || + !set_privileges(SE_BACKUP_NAME, FALSE)) + { + win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n"); + return; + } + + pRtlCreateUnicodeStringFromAsciiz(&str, "\REGISTRY\Machine\test2"); + status = pNtLoadKeyEx(&destkey, &file, 0, 0, 0, 0, NULL, 0); + todo_wine ok(status == STATUS_SUCCESS, "NtLoadKeyEx failed: %lx\n", status); + pNtUnloadKey(&destkey); + + attr = GetFileAttributesA("savedkey"); + todo_wine ok(attr != INVALID_FILE_ATTRIBUTES, "expected NtLoadKeyEx to create a file\n"); + + pRtlFreeUnicodeString(&str); + pRtlFreeUnicodeString(&filename); + DeleteFileA("savedkey"); +} + START_TEST(reg) { static const WCHAR winetest[] = {'\','W','i','n','e','T','e','s','t',0}; @@ -2298,6 +2415,7 @@ START_TEST(reg) test_symlinks(); test_redirection(); test_NtRenameKey(); + test_NtLoadKeyEx();
pRtlFreeUnicodeString(&winetestpath);
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/ntdll/unix/registry.c | 42 ++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index fae969763e6..0ec55cae90a 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -680,6 +680,25 @@ NTSTATUS WINAPI NtFlushKey( HANDLE key ) * NtLoadKey (NTDLL.@) */ NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file ) +{ + TRACE("(%p,%p)", attr, file); + return NtLoadKeyEx(attr, file, 0, 0, 0, 0, NULL, NULL); +} + +/****************************************************************************** + * NtLoadKey2 (NTDLL.@) + */ +NTSTATUS WINAPI NtLoadKey2( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags ) +{ + if (flags) FIXME("unhandled flag REG_NO_LAZY_FLUSH"); + return NtLoadKey( attr, file ); +} + +/****************************************************************************** + * NtLoadKeyEx (NTDLL.@) + */ +NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags, HANDLE trustkey, + HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) { NTSTATUS ret; HANDLE key; @@ -689,7 +708,7 @@ NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *fil UNICODE_STRING nt_name; OBJECT_ATTRIBUTES new_attr = *file;
- TRACE("(%p,%p)\n", attr, file); + TRACE("(%p,%p,0x%x,%p,%p,0x%x,%p,%p)\n", attr, file, flags, trustkey, event, access, roothandle, iostatus);
get_redirect( &new_attr, &nt_name ); if (!(ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ))) @@ -719,27 +738,6 @@ NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *fil return ret; }
- -/****************************************************************************** - * NtLoadKey2 (NTDLL.@) - */ -NTSTATUS WINAPI NtLoadKey2( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags ) -{ - FIXME( "(%p,%p,0x%08x) semi-stub: ignoring flags\n", attr, file, flags ); - return NtLoadKey( attr, file ); -} - -/****************************************************************************** - * NtLoadKeyEx (NTDLL.@) - */ -NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags, HANDLE trustkey, - HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) -{ - FIXME( "(%p,%p,0x%08x,%p,%p,0x%08x,%p,%p) stub\n", attr, file, flags, trustkey, event, - access, roothandle, iostatus); - return STATUS_NOT_IMPLEMENTED; -} - /****************************************************************************** * NtUnloadKey (NTDLL.@) */
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/ntdll/unix/registry.c | 8 ++++++ include/wine/server_protocol.h | 6 ++++- server/protocol.def | 4 +++ server/registry.c | 45 ++++++++++++++++++++++++++++++++-- server/request.h | 6 ++++- server/trace.c | 9 ++++++- 6 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 0ec55cae90a..892ffc8fbab 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -710,6 +710,8 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
TRACE("(%p,%p,0x%x,%p,%p,0x%x,%p,%p)\n", attr, file, flags, trustkey, event, access, roothandle, iostatus);
+ if (roothandle) *roothandle = NULL; + get_redirect( &new_attr, &nt_name ); if (!(ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ))) { @@ -727,8 +729,14 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f SERVER_START_REQ( load_registry ) { req->file = wine_server_obj_handle( key ); + req->flags = flags; + req->access = access; wine_server_add_data( req, objattr, len ); ret = wine_server_call( req ); + if (roothandle) + *roothandle = wine_server_ptr_handle( reply->hkey ); + else + NtClose( wine_server_ptr_handle( reply->hkey ) ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS; } SERVER_END_REQ; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fb3168c4a6a..220a1ace665 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2361,11 +2361,15 @@ struct load_registry_request { struct request_header __header; obj_handle_t file; + unsigned int flags; + unsigned int access; /* VARARG(objattr,object_attributes); */ }; struct load_registry_reply { struct reply_header __header; + obj_handle_t hkey; + char __pad_12[4]; };
@@ -6324,7 +6328,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 755 +#define SERVER_PROTOCOL_VERSION 756
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index d828d41d1f7..defe071a722 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1826,7 +1826,11 @@ struct process_info /* Load a registry branch from a file */ @REQ(load_registry) obj_handle_t file; /* file to load from */ + unsigned int flags; /* flags */ + unsigned int access; /* wanted access rights */ VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t hkey; /* handle to root key */ @END
diff --git a/server/registry.c b/server/registry.c index 96ba18a0a5a..7ce7a27eacf 100644 --- a/server/registry.c +++ b/server/registry.c @@ -102,6 +102,10 @@ struct key
#define OBJ_KEY_WOW64 0x100000 /* magic flag added to attributes for WoW64 redirection */
+/* load key flags */ +#define LOAD_NONE 0x0 +#define LOAD_APP_KEY 0x10 + /* a key value */ struct key_value { @@ -1767,6 +1771,25 @@ static void load_registry( struct key *key, obj_handle_t handle ) } }
+static void load_app_registry( struct key *key, obj_handle_t handle ) +{ + WCHAR applicationhive_fullpath[12] = {'\', 'R', 'E', 'G', 'I', 'S', 'T', 'R', 'Y', '\', 'A'}; + WCHAR *key_fullpath; + data_size_t key_fullpath_size; + + /* check if we are loading in \REGISTRY\A */ + key_fullpath = key_get_full_name( (struct object*)key, &key_fullpath_size ); + if (key_fullpath_size < (sizeof(applicationhive_fullpath) - 1 ) || + memcmp( key_fullpath, applicationhive_fullpath, sizeof(applicationhive_fullpath) - 2 )) + { + set_error( STATUS_PRIVILEGE_NOT_HELD ); + } + free( key_fullpath ); + + if (!get_error()) + load_registry( key, handle ); +} + /* load one of the initial registry files */ static int load_init_registry_from_file( const char *filename, struct key *key ) { @@ -1853,10 +1876,12 @@ void init_registry(void) 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\', 'P','e','r','f','l','i','b','\', '0','0','9'}; + static const WCHAR application[] = {'A'}; static const struct unicode_str root_name = { REGISTRY, sizeof(REGISTRY) }; static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) }; static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) }; static const struct unicode_str perflib_name = { perflib, sizeof(perflib) }; + static const struct unicode_str application_name = { application, sizeof(application) };
WCHAR *current_user_path; struct unicode_str current_user_str; @@ -1934,6 +1959,11 @@ void init_registry(void) release_object( key ); }
+ /* create application hive */ + if (!(key = create_key_recursive( root_key, &application_name, current_time ))) + fatal_error( "could not create \REGISTRY\A registry key\n" ); + release_object(key); + release_object( hklm ); release_object( hkcu );
@@ -2285,7 +2315,7 @@ DECL_HANDLER(load_registry)
if (!objattr) return;
- if (!thread_single_check_privilege( current, SeRestorePrivilege )) + if (!(req->flags & LOAD_APP_KEY) && !thread_single_check_privilege( current, SeRestorePrivilege )) { set_error( STATUS_PRIVILEGE_NOT_HELD ); return; @@ -2297,7 +2327,18 @@ DECL_HANDLER(load_registry)
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { - load_registry( key, req->file ); + if (req->flags & LOAD_APP_KEY) + load_app_registry( key, req->file ); + else + load_registry( key, req->file ); + + if (!get_error()) + reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); + else + { + reply->hkey = 0; + delete_key( key, 1 ); + } release_object( key ); } if (parent) release_object( parent ); diff --git a/server/request.h b/server/request.h index 9e943cceb3c..c10d98691ba 100644 --- a/server/request.h +++ b/server/request.h @@ -1231,7 +1231,11 @@ C_ASSERT( sizeof(struct enum_key_value_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct delete_key_value_request, hkey) == 12 ); C_ASSERT( sizeof(struct delete_key_value_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct load_registry_request, file) == 12 ); -C_ASSERT( sizeof(struct load_registry_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, flags) == 16 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, access) == 20 ); +C_ASSERT( sizeof(struct load_registry_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_reply, hkey) == 8 ); +C_ASSERT( sizeof(struct load_registry_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct unload_registry_request, parent) == 12 ); C_ASSERT( FIELD_OFFSET(struct unload_registry_request, attributes) == 16 ); C_ASSERT( sizeof(struct unload_registry_request) == 24 ); diff --git a/server/trace.c b/server/trace.c index c6a324bb905..b7a4c47849f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2407,9 +2407,16 @@ static void dump_delete_key_value_request( const struct delete_key_value_request static void dump_load_registry_request( const struct load_registry_request *req ) { fprintf( stderr, " file=%04x", req->file ); + fprintf( stderr, ", flags=%08x", req->flags ); + fprintf( stderr, ", access=%08x", req->access ); dump_varargs_object_attributes( ", objattr=", cur_size ); }
+static void dump_load_registry_reply( const struct load_registry_reply *req ) +{ + fprintf( stderr, " hkey=%04x", req->hkey ); +} + static void dump_unload_registry_request( const struct unload_registry_request *req ) { fprintf( stderr, " parent=%04x", req->parent ); @@ -4869,7 +4876,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_key_value_reply, (dump_func)dump_enum_key_value_reply, NULL, - NULL, + (dump_func)dump_load_registry_reply, NULL, NULL, NULL,
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codweavers.com --- dlls/advapi32/tests/registry.c | 6 +-- dlls/kernelbase/registry.c | 70 ++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index e2707504c4f..555cc72451e 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -1615,8 +1615,8 @@ static void test_reg_load_app_key(void)
/* Test with non existant file */ ret = RegLoadAppKeyA("saved_app_key", &key1, KEY_READ, 0, 0); - ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); - ok(key1 != NULL, "got a null key\n"); + todo_wine ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); + todo_wine ok(key1 != NULL, "got a null key\n");
ret = GetFileAttributesA("saved_app_key"); todo_wine ok(ret != -1, "hive file didn't got created.\n"); @@ -1674,7 +1674,7 @@ static void test_reg_load_app_key(void) ok(key1 != NULL, "got a null key\n");
ret = RegCreateKeyA(key1, "testkey", &childkey); - todo_wine ok(ret == ERROR_SUCCESS || broken(ret == ERROR_INVALID_HANDLE) /* win7 */, "error when creating testkey. %ld\n", ret); + ok(ret == ERROR_SUCCESS || broken(ret == ERROR_INVALID_HANDLE) /* win7 */, "error when creating testkey. %ld\n", ret); RegCloseKey(key1);
hivefile = CreateFileA("saved_app_key", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 91462d80e06..a0fa81118b9 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -3080,35 +3080,81 @@ cleanup: return ret; }
+static void generate_string_uuid(WCHAR *out, DWORD out_size) +{ + UUID uuid; + LARGE_INTEGER ft; + ULONG seed; + + NtQuerySystemTime(&ft); + seed = ft.LowPart; + for (int i = 0; i < sizeof(uuid); ++i) + ((UCHAR*)&uuid)[i] = (UCHAR)RtlRandom(&seed); + + + uuid.Data3 &= 0x0fff; + uuid.Data3 |= (4 << 12); + uuid.Data4[0] &= 0x3f; + uuid.Data4[0] |= 0x80; + + swprintf(out, out_size, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", uuid.Data1, + uuid.Data2, uuid.Data3, uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3], + uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]); +}
/****************************************************************************** * RegLoadAppKeyA (kernelbase.@) * */ -LSTATUS WINAPI RegLoadAppKeyA(const char *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) +LSTATUS WINAPI RegLoadAppKeyA(const char *filename, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) { - FIXME("%s %p %lu %lu %lu: stub\n", wine_dbgstr_a(file), result, sam, options, reserved); + UNICODE_STRING filenameW; + LSTATUS status; + FIXME("%s %p %lu %lu %lu: stub\n", wine_dbgstr_a(filename), result, sam, options, reserved);
- if (!file || reserved) - return ERROR_INVALID_PARAMETER; - - *result = (HKEY)0xdeadbeef; - return ERROR_SUCCESS; + RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + status = RegLoadAppKeyW(filenameW.Buffer, result, sam, options, reserved); + RtlFreeUnicodeString(&filenameW); + return status; }
/****************************************************************************** * RegLoadAppKeyW (kernelbase.@) * */ -LSTATUS WINAPI RegLoadAppKeyW(const WCHAR *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) +LSTATUS WINAPI RegLoadAppKeyW(const WCHAR *filename, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) { - FIXME("%s %p %lu %lu %lu: stub\n", wine_dbgstr_w(file), result, sam, options, reserved); + NTSTATUS status; + WCHAR application_root[13] = L"\REGISTRY\A\"; + WCHAR rootguid_str[39]; + WCHAR *destkey_path_tmp; + UNICODE_STRING destkey_path, filenameW; + OBJECT_ATTRIBUTES destkey, file; + + TRACE("%s %p %lu %lu %lu\n", wine_dbgstr_w(filename), result, sam, options, reserved);
- if (!file || reserved) + if (!filename || reserved) return ERROR_INVALID_PARAMETER;
- *result = (HKEY)0xdeadbeef; - return ERROR_SUCCESS; + InitializeObjectAttributes(&destkey, &destkey_path, 0, 0, 0); + RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL); + InitializeObjectAttributes(&file, &filenameW, 0, 0, 0); + + generate_string_uuid(rootguid_str, sizeof(rootguid_str)); + + destkey_path_tmp = heap_alloc_zero(sizeof(application_root) + sizeof(rootguid_str)); + wcscat(destkey_path_tmp, application_root); + wcscat(destkey_path_tmp, rootguid_str); + + RtlCreateUnicodeString(&destkey_path, destkey_path_tmp); + heap_free(destkey_path_tmp); + + status = NtLoadKeyEx(&destkey, &file, 0x10 /* LOAD_APP_KEY flag */, 0, 0, sam, (HANDLE *)result, 0); + + RtlFreeUnicodeString(&destkey_path); + RtlFreeUnicodeString(&filenameW); + + return RtlNtStatusToDosError(status); }
From: Santino Mazza smazza@codeweavers.com
This change simplifies the code for future changes in load_registry and load_app_registry.
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/ntdll/unix/registry.c | 12 +++--------- include/wine/server_protocol.h | 5 +++-- server/protocol.def | 2 +- server/registry.c | 32 ++++++++++++++------------------ server/request.h | 5 ++--- server/trace.c | 4 ++-- 6 files changed, 25 insertions(+), 35 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 892ffc8fbab..96c2f1a4c64 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -701,7 +701,6 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) { NTSTATUS ret; - HANDLE key; data_size_t len; struct object_attributes *objattr; char *unix_name; @@ -713,12 +712,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f if (roothandle) *roothandle = NULL;
get_redirect( &new_attr, &nt_name ); - if (!(ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ))) - { - ret = open_unix_file( &key, unix_name, GENERIC_READ | SYNCHRONIZE, - &new_attr, 0, 0, FILE_OPEN, 0, NULL, 0 ); - free( unix_name ); - } + ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ); free( nt_name.Buffer );
if (ret) return ret; @@ -728,10 +722,10 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
SERVER_START_REQ( load_registry ) { - req->file = wine_server_obj_handle( key ); req->flags = flags; req->access = access; wine_server_add_data( req, objattr, len ); + wine_server_add_data( req, unix_name, strlen(unix_name) + 1 ); ret = wine_server_call( req ); if (roothandle) *roothandle = wine_server_ptr_handle( reply->hkey ); @@ -741,7 +735,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f } SERVER_END_REQ;
- NtClose( key ); + free( unix_name ); free( objattr ); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 220a1ace665..3343c0de396 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2360,10 +2360,11 @@ struct delete_key_value_reply struct load_registry_request { struct request_header __header; - obj_handle_t file; unsigned int flags; unsigned int access; /* VARARG(objattr,object_attributes); */ + /* VARARG(filename,string); */ + char __pad_20[4]; }; struct load_registry_reply { @@ -6328,7 +6329,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 756 +#define SERVER_PROTOCOL_VERSION 757
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index defe071a722..4e0c4b905db 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1825,10 +1825,10 @@ struct process_info
/* Load a registry branch from a file */ @REQ(load_registry) - obj_handle_t file; /* file to load from */ unsigned int flags; /* flags */ unsigned int access; /* wanted access rights */ VARARG(objattr,object_attributes); /* object attributes */ + VARARG(filename,string); /* file to load name */ @REPLY obj_handle_t hkey; /* handle to root key */ @END diff --git a/server/registry.c b/server/registry.c index 7ce7a27eacf..d88797d7591 100644 --- a/server/registry.c +++ b/server/registry.c @@ -1751,27 +1751,20 @@ static void load_keys( struct key *key, const char *filename, FILE *f, int prefi }
/* load a part of the registry from a file */ -static void load_registry( struct key *key, obj_handle_t handle ) +static void load_registry( struct key *key, const char *filename ) { - struct file *file; - int fd; + FILE *f;
- if (!(file = get_file_obj( current->process, handle, FILE_READ_DATA ))) return; - fd = dup( get_file_unix_fd( file ) ); - release_object( file ); - if (fd != -1) + f = fopen( filename, "r" ); + if (f) { - FILE *f = fdopen( fd, "r" ); - if (f) - { - load_keys( key, NULL, f, -1 ); - fclose( f ); - } - else file_set_error(); + load_keys( key, NULL, f, -1 ); + fclose( f ); } + else file_set_error(); }
-static void load_app_registry( struct key *key, obj_handle_t handle ) +static void load_app_registry( struct key *key, const char *filename ) { WCHAR applicationhive_fullpath[12] = {'\', 'R', 'E', 'G', 'I', 'S', 'T', 'R', 'Y', '\', 'A'}; WCHAR *key_fullpath; @@ -1787,7 +1780,7 @@ static void load_app_registry( struct key *key, obj_handle_t handle ) free( key_fullpath );
if (!get_error()) - load_registry( key, handle ); + load_registry( key, filename ); }
/* load one of the initial registry files */ @@ -2310,8 +2303,11 @@ DECL_HANDLER(load_registry) { struct key *key, *parent = NULL; struct unicode_str name; + const char *filename; + data_size_t filename_len; const struct security_descriptor *sd; const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL ); + filename = get_req_data_after_objattr(objattr, &filename_len);
if (!objattr) return;
@@ -2328,9 +2324,9 @@ DECL_HANDLER(load_registry) if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { if (req->flags & LOAD_APP_KEY) - load_app_registry( key, req->file ); + load_app_registry( key, filename ); else - load_registry( key, req->file ); + load_registry( key, filename );
if (!get_error()) reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); diff --git a/server/request.h b/server/request.h index c10d98691ba..faf66287b60 100644 --- a/server/request.h +++ b/server/request.h @@ -1230,9 +1230,8 @@ C_ASSERT( FIELD_OFFSET(struct enum_key_value_reply, namelen) == 16 ); C_ASSERT( sizeof(struct enum_key_value_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct delete_key_value_request, hkey) == 12 ); C_ASSERT( sizeof(struct delete_key_value_request) == 16 ); -C_ASSERT( FIELD_OFFSET(struct load_registry_request, file) == 12 ); -C_ASSERT( FIELD_OFFSET(struct load_registry_request, flags) == 16 ); -C_ASSERT( FIELD_OFFSET(struct load_registry_request, access) == 20 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, flags) == 12 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, access) == 16 ); C_ASSERT( sizeof(struct load_registry_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct load_registry_reply, hkey) == 8 ); C_ASSERT( sizeof(struct load_registry_reply) == 16 ); diff --git a/server/trace.c b/server/trace.c index b7a4c47849f..97435dc7493 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2406,10 +2406,10 @@ static void dump_delete_key_value_request( const struct delete_key_value_request
static void dump_load_registry_request( const struct load_registry_request *req ) { - fprintf( stderr, " file=%04x", req->file ); - fprintf( stderr, ", flags=%08x", req->flags ); + fprintf( stderr, " flags=%08x", req->flags ); fprintf( stderr, ", access=%08x", req->access ); dump_varargs_object_attributes( ", objattr=", cur_size ); + dump_varargs_string( ", filename=", cur_size ); }
static void dump_load_registry_reply( const struct load_registry_reply *req )
From: Santino Mazza smazza@codeweavers.com
Signed-off-by: Santino Mazza smazza@codeweavers.com --- dlls/advapi32/tests/registry.c | 2 +- server/registry.c | 36 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index 555cc72451e..81f3fb788ef 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -1680,7 +1680,7 @@ static void test_reg_load_app_key(void) hivefile = CreateFileA("saved_app_key", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); size2 = GetFileSize(hivefile, NULL); - todo_wine ok(size2 > size1 || broken(size1 == size2) /* win7 */, "Expected file to increase size. %ld >= %ld\n", size1, size2); + ok(size2 > size1 || broken(size1 == size2) /* win7 */, "Expected file to increase size. %ld >= %ld\n", size1, size2); CloseHandle(hivefile);
DeleteFileA("saved_app_key"); diff --git a/server/registry.c b/server/registry.c index d88797d7591..eacac63ecd6 100644 --- a/server/registry.c +++ b/server/registry.c @@ -90,6 +90,7 @@ struct key unsigned int flags; /* flags */ timeout_t modif; /* last modification time */ struct list notify_list; /* list of notifications */ + FILE *file; /* loaded file */ };
/* key flags */ @@ -641,15 +642,6 @@ static void key_unlink_name( struct object *obj, struct object_name *name ) } }
-/* close the notification associated with a handle */ -static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) -{ - struct key * key = (struct key *) obj; - struct notify *notify = find_notify( key, process, handle ); - if (notify) do_notification( key, notify, 1 ); - return 1; /* ok to close */ -} - static void key_destroy( struct object *obj ) { int i; @@ -703,6 +695,7 @@ static struct key *create_key_object( struct object *parent, const struct unicod key->last_value = -1; key->values = NULL; key->modif = modif; + key->file = NULL; list_init( &key->notify_list );
if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK; @@ -1781,6 +1774,14 @@ static void load_app_registry( struct key *key, const char *filename )
if (!get_error()) load_registry( key, filename ); + + key->file = fopen(filename, "r+"); + if (!key->file) + { + file_set_error(); + return; + } + flockfile(key->file); }
/* load one of the initial registry files */ @@ -2142,6 +2143,23 @@ void flush_registry(void) if (fchdir( server_dir_fd ) == -1) fatal_error( "chdir to server dir: %s\n", strerror( errno )); }
+/* close the notification associated with a handle */ +static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) +{ + struct key * key = (struct key *) obj; + struct notify *notify = find_notify( key, process, handle ); + if (notify) do_notification( key, notify, 1 ); + if (key->file) + { + save_all_subkeys(key, key->file); + funlockfile(key->file); + if (fclose(key->file)) file_set_error(); + delete_key(key, 1); + } + return 1; /* ok to close */ +} + + /* determine if the thread is wow64 (32-bit client running on 64-bit prefix) */ static int is_wow64_thread( struct thread *thread ) {
On Sun Aug 28 16:00:06 2022 +0000, Etaash Mathamsetty wrote:
I think to reduce the spam made by that function you could say unhandled flag REG_NO_LAZY_FLUSH or something, since that's the only other flag it takes (other than no flags)
I added the check so it only prints the fixme message when a flag is passed. :)
Etaash Mathamsetty (@etaash.mathamsetty) commented about dlls/ntdll/unix/registry.c:
NtLoadKey (NTDLL.@)
*/ NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file ) +{
- TRACE("(%p,%p)", attr, file);
- return NtLoadKeyEx(attr, file, 0, 0, 0, 0, NULL, NULL);
+}
+/******************************************************************************
NtLoadKey2 (NTDLL.@)
- */
+NTSTATUS WINAPI NtLoadKey2( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags ) +{
- if (flags) FIXME("unhandled flag REG_NO_LAZY_FLUSH");
1. I am pretty sure FIXME and TRACE require \n to go to the next line 2. Instead of saying FIXME("unhandled flag REG_NO_LAZY_FLUSH"), instead do FIXME("unhandled flags %x\n", flags), in the unlikely case that flags other than REG_NO_LAZY_FLUSH can be passed