Alexandre Julliard : server: Initial support for Wow64 registry redirection .

Alexandre Julliard julliard at winehq.org
Tue Mar 2 10:32:34 CST 2010


Module: wine
Branch: master
Commit: ac08b038f00ede310543d102dfeba18d34c9b566
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ac08b038f00ede310543d102dfeba18d34c9b566

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Mar  2 12:03:17 2010 +0100

server: Initial support for Wow64 registry redirection.

---

 dlls/ntdll/tests/reg.c |    3 ++-
 server/registry.c      |   48 +++++++++++++++++++++++++++++++++++++++++++-----
 server/thread.c        |    7 +++++++
 server/thread.h        |    1 +
 4 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c
index d534240..4480bbf 100644
--- a/dlls/ntdll/tests/reg.c
+++ b/dlls/ntdll/tests/reg.c
@@ -1157,7 +1157,8 @@ static void test_redirection(void)
         dw = get_key_value( key, "Winetest", 0 );
         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
         check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
-        check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
+        dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
+        todo_wine ok( dw == 32, "wrong value %u\n", dw );
         pNtClose( key );
 
         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
diff --git a/server/registry.c b/server/registry.c
index ea7ea20..ad57bd2 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -84,6 +84,7 @@ struct key
 #define KEY_DELETED  0x0002  /* key has been deleted */
 #define KEY_DIRTY    0x0004  /* key has been modified */
 #define KEY_SYMLINK  0x0008  /* key is a symbolic link */
+#define KEY_WOW64    0x0010  /* key contains a Wow6432Node subkey */
 
 /* a key value */
 struct key_value
@@ -109,6 +110,7 @@ static const timeout_t save_period = 30 * -TICKS_PER_SEC;  /* delay between peri
 static struct timeout_user *save_timeout_user;  /* saving timer */
 
 static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\' };
+static const WCHAR wow6432node[] = {'W','o','w','6','4','3','2','N','o','d','e'};
 static const WCHAR symlink_value[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e'};
 static const struct unicode_str symlink_str = { symlink_value, sizeof(symlink_value) };
 
@@ -166,6 +168,12 @@ static const struct object_ops key_ops =
 };
 
 
+static inline int is_wow6432node( const WCHAR *name, unsigned int len )
+{
+    return (len == sizeof(wow6432node) &&
+            !memicmpW( name, wow6432node, sizeof(wow6432node)/sizeof(WCHAR) ));
+}
+
 /*
  * The registry text file format v2 used by this code is similar to the one
  * used by REGEDIT import/export functionality, with the following differences:
@@ -528,6 +536,7 @@ static struct key *alloc_subkey( struct key *parent, const struct unicode_str *n
         for (i = ++parent->last_subkey; i > index; i--)
             parent->subkeys[i] = parent->subkeys[i-1];
         parent->subkeys[index] = key;
+        if (is_wow6432node( key->name, key->namelen )) parent->flags |= KEY_WOW64;
     }
     return key;
 }
@@ -546,6 +555,7 @@ static void free_subkey( struct key *parent, int index )
     parent->last_subkey--;
     key->flags |= KEY_DELETED;
     key->parent = NULL;
+    if (is_wow6432node( key->name, key->namelen )) parent->flags &= ~KEY_WOW64;
     release_object( key );
 
     /* try to shrink the array */
@@ -587,6 +597,22 @@ static struct key *find_subkey( const struct key *key, const struct unicode_str
     return NULL;
 }
 
+/* return the wow64 variant of the key, or the key itself if none */
+static struct key *find_wow64_subkey( struct key *key, const struct unicode_str *name )
+{
+    static const struct unicode_str wow6432node_str = { wow6432node, sizeof(wow6432node) };
+    int index;
+
+    if (!(key->flags & KEY_WOW64)) return key;
+    if (!is_wow6432node( name->str, name->len ))
+    {
+        key = find_subkey( key, &wow6432node_str, &index );
+        assert( key );  /* if KEY_WOW64 is set we must find it */
+    }
+    return key;
+}
+
+
 /* follow a symlink and return the resolved key */
 static struct key *follow_symlink( struct key *key, int iteration )
 {
@@ -618,13 +644,15 @@ static struct key *follow_symlink( struct key *key, int iteration )
 }
 
 /* open a subkey */
-static struct key *open_key( struct key *key, const struct unicode_str *name, unsigned int attributes )
+static struct key *open_key( struct key *key, const struct unicode_str *name, unsigned int access,
+                             unsigned int attributes )
 {
     int index;
     struct unicode_str token;
 
     token.str = NULL;
     if (!get_path_token( name, &token )) return NULL;
+    if (access & KEY_WOW64_32KEY) key = find_wow64_subkey( key, &token );
     while (token.len)
     {
         if (!(key = find_subkey( key, &token, &index )))
@@ -634,6 +662,7 @@ static struct key *open_key( struct key *key, const struct unicode_str *name, un
         }
         get_path_token( name, &token );
         if (!token.len) break;
+        if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
         if (!(key = follow_symlink( key, 0 )))
         {
             set_error( STATUS_OBJECT_NAME_NOT_FOUND );
@@ -641,6 +670,7 @@ static struct key *open_key( struct key *key, const struct unicode_str *name, un
         }
     }
 
+    if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
     if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
     {
         set_error( STATUS_OBJECT_NAME_NOT_FOUND );
@@ -654,7 +684,7 @@ static struct key *open_key( struct key *key, const struct unicode_str *name, un
 /* create a subkey */
 static struct key *create_key( struct key *key, const struct unicode_str *name,
                                const struct unicode_str *class, unsigned int options,
-                               unsigned int attributes, int *created )
+                               unsigned int access, unsigned int attributes, int *created )
 {
     int index;
     struct unicode_str token, next;
@@ -668,6 +698,7 @@ static struct key *create_key( struct key *key, const struct unicode_str *name,
     token.str = NULL;
     if (!get_path_token( name, &token )) return NULL;
     *created = 0;
+    if (access & KEY_WOW64_32KEY) key = find_wow64_subkey( key, &token );
     while (token.len)
     {
         struct key *subkey;
@@ -675,6 +706,7 @@ static struct key *create_key( struct key *key, const struct unicode_str *name,
         key = subkey;
         get_path_token( name, &token );
         if (!token.len) break;
+        if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
         if (!(key = follow_symlink( key, 0 )))
         {
             set_error( STATUS_OBJECT_NAME_NOT_FOUND );
@@ -684,6 +716,7 @@ static struct key *create_key( struct key *key, const struct unicode_str *name,
 
     if (!token.len)  /* the key already exists */
     {
+        if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
         if (options & REG_OPTION_CREATE_LINK)
         {
             set_error( STATUS_OBJECT_NAME_COLLISION );
@@ -1786,6 +1819,8 @@ DECL_HANDLER(create_key)
     struct unicode_str name, class;
     unsigned int access = req->access;
 
+    if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
+
     reply->hkey = 0;
 
     if (req->namelen > get_req_data_size())
@@ -1806,7 +1841,8 @@ DECL_HANDLER(create_key)
     /* NOTE: no access rights are required from the parent handle to create a key */
     if ((parent = get_parent_hkey_obj( req->parent )))
     {
-        if ((key = create_key( parent, &name, &class, req->options, req->attributes, &reply->created )))
+        if ((key = create_key( parent, &name, &class, req->options, access,
+                               req->attributes, &reply->created )))
         {
             reply->hkey = alloc_handle( current->process, key, access, req->attributes );
             release_object( key );
@@ -1822,12 +1858,14 @@ DECL_HANDLER(open_key)
     struct unicode_str name;
     unsigned int access = req->access;
 
+    if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
+
     reply->hkey = 0;
     /* NOTE: no access rights are required to open the parent key, only the child key */
     if ((parent = get_parent_hkey_obj( req->parent )))
     {
         get_req_path( &name, !req->parent );
-        if ((key = open_key( parent, &name, req->attributes )))
+        if ((key = open_key( parent, &name, access, req->attributes )))
         {
             reply->hkey = alloc_handle( current->process, key, access, req->attributes );
             release_object( key );
@@ -1961,7 +1999,7 @@ DECL_HANDLER(load_registry)
     {
         int dummy;
         get_req_path( &name, !req->hkey );
-        if ((key = create_key( parent, &name, NULL, 0, 0, &dummy )))
+        if ((key = create_key( parent, &name, NULL, 0, KEY_WOW64_64KEY, 0, &dummy )))
         {
             load_registry( key, req->file );
             release_object( key );
diff --git a/server/thread.c b/server/thread.c
index bdb6c3c..a6bc55a 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -67,6 +67,7 @@ static const unsigned int supported_cpus = CPU_FLAG(CPU_SPARC);
 #else
 #error Unsupported CPU
 #endif
+#define CPU_64BIT_MASK CPU_FLAG(CPU_x86_64)
 
 /* thread queues */
 
@@ -408,6 +409,12 @@ struct thread *get_thread_from_pid( int pid )
     return NULL;
 }
 
+/* determine if the thread is wow64 (32-bit client running on 64-bit server) */
+int is_wow64_thread( struct thread *thread )
+{
+    return (supported_cpus & CPU_64BIT_MASK) && !(CPU_FLAG(thread->process->cpu) & CPU_64BIT_MASK);
+}
+
 int set_thread_affinity( struct thread *thread, affinity_t affinity )
 {
     int ret = 0;
diff --git a/server/thread.h b/server/thread.h
index 1e95732..045a43c 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -118,6 +118,7 @@ extern int thread_add_inflight_fd( struct thread *thread, int client, int server
 extern int thread_get_inflight_fd( struct thread *thread, int client );
 extern struct thread_snapshot *thread_snap( int *count );
 extern struct token *thread_get_impersonation_token( struct thread *thread );
+extern int is_wow64_thread( struct thread *thread );
 extern int set_thread_affinity( struct thread *thread, affinity_t affinity );
 
 /* ptrace functions */




More information about the wine-cvs mailing list