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