[PATCH v3 3/4] ntdll: Implement NtRenameKey().

Nikolay Sivov wine at gitlab.winehq.org
Tue Jun 28 15:53:27 CDT 2022


From: Nikolay Sivov <nsivov at codeweavers.com>

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/tests/reg.c         | 10 ++---
 dlls/ntdll/unix/registry.c     | 19 +++++++--
 include/wine/server_protocol.h | 18 ++++++++-
 server/protocol.def            |  7 ++++
 server/registry.c              | 74 ++++++++++++++++++++++++++++++++++
 server/request.h               |  4 ++
 server/trace.c                 |  9 +++++
 7 files changed, 131 insertions(+), 10 deletions(-)

diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c
index b0cbf137086..7c9d4914ba7 100644
--- a/dlls/ntdll/tests/reg.c
+++ b/dlls/ntdll/tests/reg.c
@@ -2126,7 +2126,6 @@ static void test_NtRenameKey(void)
     DWORD size;
 
     status = NtRenameKey(NULL, NULL);
-    todo_wine
     ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status);
 
     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
@@ -2140,17 +2139,18 @@ static void test_NtRenameKey(void)
     status = pNtCreateKey(&subkey, KEY_READ|DELETE, &attr, 0, 0, 0, 0);
     ok(!status, "Unexpected status %#lx.\n", status);
 
+    memset(&str2, 0, sizeof(str2));
+    status = NtRenameKey(subkey, &str2);
+    ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %#lx.\n", status);
+
     pRtlCreateUnicodeStringFromAsciiz(&str2, "renamed_subkey");
 
     status = NtRenameKey(subkey, NULL);
-    todo_wine
     ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status);
     status = NtRenameKey(NULL, &str);
-    todo_wine
     ok(status == STATUS_INVALID_HANDLE, "Unexpected status %#lx.\n", status);
 
     status = NtRenameKey(subkey, &str2);
-    todo_wine
     ok(status == STATUS_ACCESS_DENIED, "Unexpected status %#lx.\n", status);
     pNtClose(subkey);
 
@@ -2158,10 +2158,8 @@ static void test_NtRenameKey(void)
     ok(!status, "Unexpected status %#lx.\n", status);
     /* Rename to itself. */
     status = NtRenameKey(subkey, &str);
-    todo_wine
     ok(status == STATUS_CANNOT_DELETE, "Unexpected status %#lx.\n", status);
     status = NtRenameKey(subkey, &str2);
-    todo_wine
     ok(!status, "Unexpected status %#lx.\n", status);
 
     pRtlFreeUnicodeString(&str2);
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c
index 6628454440a..8901c350868 100644
--- a/dlls/ntdll/unix/registry.c
+++ b/dlls/ntdll/unix/registry.c
@@ -199,10 +199,23 @@ NTSTATUS WINAPI NtDeleteKey( HANDLE key )
 /******************************************************************************
  *              NtRenameKey  (NTDLL.@)
  */
-NTSTATUS WINAPI NtRenameKey( HANDLE handle, UNICODE_STRING *name )
+NTSTATUS WINAPI NtRenameKey( HANDLE key, UNICODE_STRING *name )
 {
-    FIXME( "(%p %s)\n", handle, debugstr_us(name) );
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS ret;
+
+    TRACE( "(%p %s)\n", key, debugstr_us(name) );
+
+    if (!name) return STATUS_ACCESS_VIOLATION;
+    if (!name->Buffer || !name->Length) return STATUS_INVALID_PARAMETER;
+
+    SERVER_START_REQ( rename_key )
+    {
+        req->hkey = wine_server_obj_handle( key );
+        wine_server_add_data( req, name->Buffer, name->Length );
+        ret = wine_server_call( req );
+    }
+    SERVER_END_REQ;
+    return ret;
 }
 
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 868add58abf..ce1b2630f53 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2384,6 +2384,19 @@ struct set_registry_notification_reply
 
 
 
+struct rename_key_request
+{
+    struct request_header __header;
+    obj_handle_t hkey;
+    /* VARARG(name,unicode_str); */
+};
+struct rename_key_reply
+{
+    struct reply_header __header;
+};
+
+
+
 struct create_timer_request
 {
     struct request_header __header;
@@ -5538,6 +5551,7 @@ enum request
     REQ_unload_registry,
     REQ_save_registry,
     REQ_set_registry_notification,
+    REQ_rename_key,
     REQ_create_timer,
     REQ_open_timer,
     REQ_set_timer,
@@ -5820,6 +5834,7 @@ union generic_request
     struct unload_registry_request unload_registry_request;
     struct save_registry_request save_registry_request;
     struct set_registry_notification_request set_registry_notification_request;
+    struct rename_key_request rename_key_request;
     struct create_timer_request create_timer_request;
     struct open_timer_request open_timer_request;
     struct set_timer_request set_timer_request;
@@ -6100,6 +6115,7 @@ union generic_reply
     struct unload_registry_reply unload_registry_reply;
     struct save_registry_reply save_registry_reply;
     struct set_registry_notification_reply set_registry_notification_reply;
+    struct rename_key_reply rename_key_reply;
     struct create_timer_reply create_timer_reply;
     struct open_timer_reply open_timer_reply;
     struct set_timer_reply set_timer_reply;
@@ -6288,7 +6304,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 751
+#define SERVER_PROTOCOL_VERSION 752
 
 /* ### protocol_version end ### */
 
diff --git a/server/protocol.def b/server/protocol.def
index 2be1658fca2..a8beccaf468 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1837,6 +1837,13 @@ struct process_info
 @END
 
 
+/* Rename a registry key */
+ at REQ(rename_key)
+    obj_handle_t hkey;         /* handle to the key to be renamed */
+    VARARG(name,unicode_str);  /* new name */
+ at END
+
+
 /* Create a waitable timer */
 @REQ(create_timer)
     unsigned int access;        /* wanted access rights */
diff --git a/server/registry.c b/server/registry.c
index 93e8a309593..6fe44b4351d 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -1007,6 +1007,64 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke
     if (debug_level > 1) dump_operation( key, NULL, "Enum" );
 }
 
+/* rename a key and its values */
+static int rename_key( struct key *key, const struct unicode_str *new_name )
+{
+    struct unicode_str token, name;
+    struct key *subkey;
+    int i, index, cur_index;
+    WCHAR *ptr;
+
+    token.str = NULL;
+    if (is_wow6432node( key->name, key->namelen ))
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return -1;
+    }
+
+    /* changing to a path is not allowed */
+    if (!new_name->len || !get_path_token( new_name, &token ) || token.len != new_name->len)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return -1;
+    }
+
+    /* check for existing subkey with the same name */
+    if (!key->parent || (subkey = find_subkey( key->parent, new_name, &index )))
+    {
+        set_error( STATUS_CANNOT_DELETE );
+        return -1;
+    }
+
+    if (!(ptr = memdup( new_name->str, new_name->len ))) return -1;
+
+    name.str = key->name;
+    name.len = key->namelen;
+    find_subkey( key->parent, &name, &cur_index );
+
+    if (cur_index < index && (index - cur_index) > 1)
+    {
+        --index;
+        for (i = cur_index; i < index; ++i)
+            key->parent->subkeys[i] = key->parent->subkeys[i+1];
+    }
+    else if (cur_index > index)
+    {
+        for (i = cur_index; i > index; --i)
+            key->parent->subkeys[i] = key->parent->subkeys[i-1];
+    }
+    key->parent->subkeys[index] = key;
+
+    free( key->name );
+    key->name = ptr;
+    key->namelen = new_name->len;
+
+    if (debug_level > 1) dump_operation( key, NULL, "Rename" );
+    make_dirty( key );
+    touch_key( key, REG_NOTIFY_CHANGE_NAME );
+    return 0;
+}
+
 /* delete a key and its values */
 static int delete_key( struct key *key, int recurse )
 {
@@ -2413,3 +2471,19 @@ DECL_HANDLER(set_registry_notification)
         release_object( key );
     }
 }
+
+/* rename a registry key */
+DECL_HANDLER(rename_key)
+{
+    struct unicode_str name;
+    struct key *key;
+
+    key = get_hkey_obj( req->hkey, KEY_WRITE );
+    if (key)
+    {
+        name.str = get_req_data();
+        name.len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
+        rename_key( key, &name );
+        release_object( key );
+    }
+}
diff --git a/server/request.h b/server/request.h
index 7fd63905e0e..cbb4c5d7a01 100644
--- a/server/request.h
+++ b/server/request.h
@@ -210,6 +210,7 @@ DECL_HANDLER(load_registry);
 DECL_HANDLER(unload_registry);
 DECL_HANDLER(save_registry);
 DECL_HANDLER(set_registry_notification);
+DECL_HANDLER(rename_key);
 DECL_HANDLER(create_timer);
 DECL_HANDLER(open_timer);
 DECL_HANDLER(set_timer);
@@ -491,6 +492,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_unload_registry,
     (req_handler)req_save_registry,
     (req_handler)req_set_registry_notification,
+    (req_handler)req_rename_key,
     (req_handler)req_create_timer,
     (req_handler)req_open_timer,
     (req_handler)req_set_timer,
@@ -1230,6 +1232,8 @@ C_ASSERT( FIELD_OFFSET(struct set_registry_notification_request, event) == 16 );
 C_ASSERT( FIELD_OFFSET(struct set_registry_notification_request, subtree) == 20 );
 C_ASSERT( FIELD_OFFSET(struct set_registry_notification_request, filter) == 24 );
 C_ASSERT( sizeof(struct set_registry_notification_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct rename_key_request, hkey) == 12 );
+C_ASSERT( sizeof(struct rename_key_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct create_timer_request, access) == 12 );
 C_ASSERT( FIELD_OFFSET(struct create_timer_request, manual) == 16 );
 C_ASSERT( sizeof(struct create_timer_request) == 24 );
diff --git a/server/trace.c b/server/trace.c
index 15ca4e7d71e..4d4789d050a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2414,6 +2414,12 @@ static void dump_set_registry_notification_request( const struct set_registry_no
     fprintf( stderr, ", filter=%08x", req->filter );
 }
 
+static void dump_rename_key_request( const struct rename_key_request *req )
+{
+    fprintf( stderr, " hkey=%04x", req->hkey );
+    dump_varargs_unicode_str( ", name=", cur_size );
+}
+
 static void dump_create_timer_request( const struct create_timer_request *req )
 {
     fprintf( stderr, " access=%08x", req->access );
@@ -4578,6 +4584,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_unload_registry_request,
     (dump_func)dump_save_registry_request,
     (dump_func)dump_set_registry_notification_request,
+    (dump_func)dump_rename_key_request,
     (dump_func)dump_create_timer_request,
     (dump_func)dump_open_timer_request,
     (dump_func)dump_set_timer_request,
@@ -4856,6 +4863,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     NULL,
     NULL,
     NULL,
+    NULL,
     (dump_func)dump_create_timer_reply,
     (dump_func)dump_open_timer_reply,
     (dump_func)dump_set_timer_reply,
@@ -5134,6 +5142,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "unload_registry",
     "save_registry",
     "set_registry_notification",
+    "rename_key",
     "create_timer",
     "open_timer",
     "set_timer",
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/218



More information about the wine-devel mailing list