-- v3: kernelbase: Implement RegLoadAppKey. ntdll: Implement REG_LOAD_APP_KEY flag ntdll: Pass filename to server in NtLoadKeyEx. ntdll: Implement roothandle parameter for NtLoadKeyEx
From: Santino Mazza smazza@codeweavers.com
--- dlls/ntdll/unix/registry.c | 16 ++++++++++------ include/wine/server_protocol.h | 6 +++++- server/protocol.def | 3 +++ server/registry.c | 1 + server/request.h | 5 ++++- server/trace.c | 8 +++++++- 6 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 797e32a5bf1..1643bff5da4 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -700,7 +700,7 @@ 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; + HANDLE keyfilename, key; data_size_t len; struct object_attributes *objattr; char *unix_name; @@ -712,14 +712,14 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f if (flags) FIXME( "flags %x not handled\n", flags ); if (trustkey) FIXME("trustkey parameter not supported\n"); if (event) FIXME("event parameter not supported\n"); - if (access) FIXME("access parameter not supported\n"); - if (roothandle) FIXME("roothandle is not filled\n"); if (iostatus) FIXME("iostatus is not filled\n");
+ 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, + ret = open_unix_file( &keyfilename, unix_name, GENERIC_READ | SYNCHRONIZE, &new_attr, 0, 0, FILE_OPEN, 0, NULL, 0 ); free( unix_name ); } @@ -732,14 +732,18 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
SERVER_START_REQ( load_registry ) { - req->file = wine_server_obj_handle( key ); + req->file = wine_server_obj_handle( keyfilename ); + req->access = access; wine_server_add_data( req, objattr, len ); ret = wine_server_call( req ); + key = wine_server_ptr_handle( reply->hkey ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS; } SERVER_END_REQ;
- NtClose( key ); + if (roothandle) *roothandle = key; + else NtClose(key); + NtClose( keyfilename ); free( objattr ); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fb3168c4a6a..0fc9cbcafbb 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 access; /* VARARG(objattr,object_attributes); */ + char __pad_20[4]; }; 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..470242187cd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1826,7 +1826,10 @@ struct process_info /* Load a registry branch from a file */ @REQ(load_registry) obj_handle_t file; /* file to load from */ + 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..2817db327e0 100644 --- a/server/registry.c +++ b/server/registry.c @@ -2298,6 +2298,7 @@ DECL_HANDLER(load_registry) if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { load_registry( key, req->file ); + reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); release_object( key ); } if (parent) release_object( parent ); diff --git a/server/request.h b/server/request.h index 9e943cceb3c..edb69ee137d 100644 --- a/server/request.h +++ b/server/request.h @@ -1231,7 +1231,10 @@ 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, 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 ); 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..329ee3a7b9f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2407,9 +2407,15 @@ 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, ", 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 +4875,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
Pass filename instead of openning a file handle and passing it to wineserver. This will help to simplify future implementations for load_key where we have to keep track of the file to lock it, save it, etc. For example, with application hives. --- dlls/ntdll/unix/registry.c | 12 ++------ include/wine/server_protocol.h | 5 ++-- server/protocol.def | 2 +- server/registry.c | 53 +++++++++++++++++++--------------- server/request.h | 5 ++-- server/trace.c | 4 +-- 6 files changed, 39 insertions(+), 42 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 1643bff5da4..b53ee35f488 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -700,7 +700,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) { NTSTATUS ret; - HANDLE keyfilename, key; + HANDLE key; data_size_t len; struct object_attributes *objattr; char *unix_name; @@ -717,12 +717,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( &keyfilename, 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; @@ -732,9 +727,9 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
SERVER_START_REQ( load_registry ) { - req->file = wine_server_obj_handle( keyfilename ); 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 ); key = wine_server_ptr_handle( reply->hkey ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS; @@ -743,7 +738,6 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
if (roothandle) *roothandle = key; else NtClose(key); - NtClose( keyfilename ); free( objattr ); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 0fc9cbcafbb..2aa2dc1880f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2360,10 +2360,9 @@ struct delete_key_value_reply struct load_registry_request { struct request_header __header; - obj_handle_t file; unsigned int access; /* VARARG(objattr,object_attributes); */ - char __pad_20[4]; + /* VARARG(filename,string); */ }; struct load_registry_reply { @@ -6328,7 +6327,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 756 +#define SERVER_PROTOCOL_VERSION 758
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index 470242187cd..a5a8105bf06 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1825,9 +1825,9 @@ struct process_info
/* Load a registry branch from a file */ @REQ(load_registry) - obj_handle_t file; /* file to load from */ 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 2817db327e0..22856e62b5e 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 */ @@ -637,15 +638,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; @@ -699,6 +691,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; @@ -1747,24 +1740,17 @@ 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(); }
/* load one of the initial registry files */ @@ -2119,6 +2105,22 @@ 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 ) { @@ -2280,8 +2282,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;
@@ -2297,7 +2302,7 @@ DECL_HANDLER(load_registry)
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { - load_registry( key, req->file ); + load_registry( key, filename ); reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); release_object( key ); } diff --git a/server/request.h b/server/request.h index edb69ee137d..10fbddc0852 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, access) == 16 ); -C_ASSERT( sizeof(struct load_registry_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, access) == 12 ); +C_ASSERT( sizeof(struct load_registry_request) == 16 ); 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 ); diff --git a/server/trace.c b/server/trace.c index 329ee3a7b9f..c96b4addffe 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2406,9 +2406,9 @@ 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, ", access=%08x", req->access ); + 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
--- dlls/ntdll/unix/registry.c | 3 +- include/wine/server_protocol.h | 4 ++- include/winnt.h | 1 + server/protocol.def | 1 + server/registry.c | 50 ++++++++++++++++++++++++++++++++-- server/request.h | 5 ++-- server/trace.c | 3 +- 7 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index b53ee35f488..a5510af92b0 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -709,7 +709,7 @@ 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 (flags) FIXME( "flags %x not handled\n", flags ); + if (flags && (flags & ~REG_LOAD_APP_KEY)) FIXME( "flags %x not handled\n", flags ); if (trustkey) FIXME("trustkey parameter not supported\n"); if (event) FIXME("event parameter not supported\n"); if (iostatus) FIXME("iostatus is not filled\n"); @@ -727,6 +727,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
SERVER_START_REQ( load_registry ) { + req->flags = flags; req->access = access; wine_server_add_data( req, objattr, len ); wine_server_add_data( req, unix_name, strlen(unix_name) + 1 ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2aa2dc1880f..0b47e438513 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2360,9 +2360,11 @@ struct delete_key_value_reply struct load_registry_request { struct request_header __header; + unsigned int flags; unsigned int access; /* VARARG(objattr,object_attributes); */ /* VARARG(filename,string); */ + char __pad_20[4]; }; struct load_registry_reply { @@ -6327,7 +6329,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 758 +#define SERVER_PROTOCOL_VERSION 759
/* ### protocol_version end ### */
diff --git a/include/winnt.h b/include/winnt.h index 76aee026d84..ac61da783c9 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -5517,6 +5517,7 @@ typedef struct _TAPE_GET_MEDIA_PARAMETERS { #define REG_REFRESH_HIVE 0x00000002 #define REG_NO_LAZY_FLUSH 0x00000004 #define REG_FORCE_RESTORE 0x00000008 +#define REG_LOAD_APP_KEY 0x00000010
#define KEY_READ ((STANDARD_RIGHTS_READ| \ KEY_QUERY_VALUE| \ diff --git a/server/protocol.def b/server/protocol.def index a5a8105bf06..4e0c4b905db 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1825,6 +1825,7 @@ struct process_info
/* Load a registry branch from a file */ @REQ(load_registry) + unsigned int flags; /* flags */ unsigned int access; /* wanted access rights */ VARARG(objattr,object_attributes); /* object attributes */ VARARG(filename,string); /* file to load name */ diff --git a/server/registry.c b/server/registry.c index 22856e62b5e..ce25b01f7e9 100644 --- a/server/registry.c +++ b/server/registry.c @@ -1753,6 +1753,33 @@ static void load_registry( struct key *key, const char *filename ) else file_set_error(); }
+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; + 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, filename ); + + key->file = fopen(filename, "r+"); + if (!key->file) + { + file_set_error(); + return; + } + flockfile(key->file); +} + /* load one of the initial registry files */ static int load_init_registry_from_file( const char *filename, struct key *key ) { @@ -1839,10 +1866,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; @@ -1920,6 +1949,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 );
@@ -2290,7 +2324,7 @@ DECL_HANDLER(load_registry)
if (!objattr) return;
- if (!thread_single_check_privilege( current, SeRestorePrivilege )) + if (!(req->flags & REG_LOAD_APP_KEY) && !thread_single_check_privilege( current, SeRestorePrivilege )) { set_error( STATUS_PRIVILEGE_NOT_HELD ); return; @@ -2302,8 +2336,18 @@ DECL_HANDLER(load_registry)
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { - load_registry( key, filename ); - reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); + if (req->flags & REG_LOAD_APP_KEY) + load_app_registry( key, filename ); + else + load_registry( key, filename ); + + 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 10fbddc0852..faf66287b60 100644 --- a/server/request.h +++ b/server/request.h @@ -1230,8 +1230,9 @@ 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, access) == 12 ); -C_ASSERT( sizeof(struct load_registry_request) == 16 ); +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 ); C_ASSERT( FIELD_OFFSET(struct unload_registry_request, parent) == 12 ); diff --git a/server/trace.c b/server/trace.c index c96b4addffe..97435dc7493 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2406,7 +2406,8 @@ 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, " access=%08x", req->access ); + 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 ); }
From: Santino Mazza smazza@codeweavers.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 55a8074f1b7..e2024ec8899 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -1652,7 +1652,7 @@ static void test_reg_load_app_key(void) ok(appkey != NULL, "got a null key\n");
ret = RegSetValueExA(appkey, "testkey", 0, REG_BINARY, test_data, sizeof(test_data)); - todo_wine ok(ret == ERROR_SUCCESS, "couldn't set key value %lx\n", ret); + ok(ret == ERROR_SUCCESS, "couldn't set key value %lx\n", ret); RegCloseKey(appkey);
wait_file_available(hivefilepath); @@ -1665,9 +1665,9 @@ static void test_reg_load_app_key(void) size = sizeof(test_data); memset(output, 0xff, sizeof(output)); ret = RegGetValueA(appkey, NULL, "testkey", RRF_RT_REG_BINARY, NULL, output, &size); - todo_wine ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); + ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret); ok(size == sizeof(test_data), "size doesn't match %ld != %ld\n", size, (DWORD)sizeof(test_data)); - todo_wine ok(!memcmp(test_data, output, sizeof(test_data)), "output is not what expected\n"); + ok(!memcmp(test_data, output, sizeof(test_data)), "output is not what expected\n");
RegCloseKey(appkey);
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 91462d80e06..a010884088e 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; + TRACE("%s %p %lu %lu %lu\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, REG_LOAD_APP_KEY, 0, 0, sam, (HANDLE *)result, 0); + + RtlFreeUnicodeString(&destkey_path); + RtlFreeUnicodeString(&filenameW); + + return RtlNtStatusToDosError(status); }
Huw Davies (@huw) commented about dlls/ntdll/unix/registry.c:
HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus )
{ NTSTATUS ret;
- HANDLE key;
- HANDLE keyfilename, key;
How about renaming `key` to `file` and the parameter `file` to `file_attr`.
This renaming could be done as a separate commit.
Huw Davies (@huw) commented about dlls/ntdll/unix/registry.c:
SERVER_START_REQ( load_registry ) {
req->file = wine_server_obj_handle( key );
req->file = wine_server_obj_handle( keyfilename );
req->access = access; wine_server_add_data( req, objattr, len ); ret = wine_server_call( req );
} SERVER_END_REQ;key = wine_server_ptr_handle( reply->hkey ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS;
- NtClose( key );
- if (roothandle) *roothandle = key;
- else NtClose(key);
Only call `NtClose()` if `!ret`. Also add spaces either side of `key`.
On reflection adding a simple test for this (at least the handle return bit) would be nice.
It probably makes sense to shorten this MR to deal just with the handle return stuff and leave app key work for a further MR. You could also add a commit that simply adds the `REG_LOAD_APP_KEY` define to `winnt.h` - this will avoid having to recompile much of Wine when applying any future MRs.