Redesign of the server communication protocol to allow arbitrary sized
data to be exchanged.
Split request and reply structures to make backwards compatibility
easier.
Moved many console functions to dlls/kernel, added code page support,
changed a few requests to behave properly with the new protocol.
diff --git a/server/registry.c b/server/registry.c
index 961f441..f8e82f4 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -29,7 +29,7 @@
#include "winbase.h"
#include "winreg.h"
#include "winnt.h" /* registry definitions */
-
+#include "ntddk.h"
/* a registry key */
struct key
@@ -285,7 +285,7 @@
}
}
-/* duplicate a key path from the request buffer */
+/* duplicate a key path */
/* returns a pointer to a static buffer, so only useable once per request */
static WCHAR *copy_path( const WCHAR *path, size_t len, int skip_root )
{
@@ -303,17 +303,17 @@
return buffer;
}
-/* copy a path from the request buffer, in cases where the length is stored in front of the path */
-static WCHAR *copy_req_path( void *req, size_t *len, int skip_root )
+/* copy a path from the request buffer */
+static WCHAR *copy_req_path( size_t len, int skip_root )
{
- const WCHAR *name_ptr = get_req_data(req);
- if ((*len = sizeof(WCHAR) + *name_ptr++) > get_req_data_size(req))
+ const WCHAR *name_ptr = get_req_data();
+ if (len > get_req_data_size())
{
fatal_protocol_error( current, "copy_req_path: invalid length %d/%d\n",
- *len, get_req_data_size(req) );
+ len, get_req_data_size() );
return NULL;
}
- return copy_path( name_ptr, *len - sizeof(WCHAR), skip_root );
+ return copy_path( name_ptr, len, skip_root );
}
/* return the next token in a given path */
@@ -564,26 +564,39 @@
}
/* query information about a key or a subkey */
-static size_t enum_key( struct key *key, int index, struct enum_key_request *req )
+static void enum_key( struct key *key, int index, int info_class, struct enum_key_reply *reply )
{
int i;
size_t len, namelen, classlen;
int max_subkey = 0, max_class = 0;
int max_value = 0, max_data = 0;
- WCHAR *data = get_req_data(req);
+ WCHAR *data;
if (index != -1) /* -1 means use the specified key directly */
{
if ((index < 0) || (index > key->last_subkey))
{
set_error( STATUS_NO_MORE_ENTRIES );
- return 0;
+ return;
}
key = key->subkeys[index];
}
- if (req->full)
+ namelen = strlenW(key->name) * sizeof(WCHAR);
+ classlen = key->class ? strlenW(key->class) * sizeof(WCHAR) : 0;
+
+ switch(info_class)
{
+ case KeyBasicInformation:
+ classlen = 0; /* only return the name */
+ /* fall through */
+ case KeyNodeInformation:
+ reply->max_subkey = 0;
+ reply->max_class = 0;
+ reply->max_value = 0;
+ reply->max_data = 0;
+ break;
+ case KeyFullInformation:
for (i = 0; i <= key->last_subkey; i++)
{
struct key *subkey = key->subkeys[i];
@@ -600,43 +613,37 @@
len = key->values[i].len;
if (len > max_data) max_data = len;
}
- req->max_subkey = max_subkey;
- req->max_class = max_class;
- req->max_value = max_value;
- req->max_data = max_data;
+ reply->max_subkey = max_subkey;
+ reply->max_class = max_class;
+ reply->max_value = max_value;
+ reply->max_data = max_data;
+ namelen = 0; /* only return the class */
+ break;
+ default:
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
}
- else
+ reply->subkeys = key->last_subkey + 1;
+ reply->values = key->last_value + 1;
+ reply->modif = key->modif;
+ reply->total = namelen + classlen;
+
+ len = min( reply->total, get_reply_max_size() );
+ if (len && (data = set_reply_data_size( len )))
{
- req->max_subkey = 0;
- req->max_class = 0;
- req->max_value = 0;
- req->max_data = 0;
+ if (len > namelen)
+ {
+ reply->namelen = namelen;
+ memcpy( data, key->name, namelen );
+ memcpy( (char *)data + namelen, key->class, len - namelen );
+ }
+ else
+ {
+ reply->namelen = len;
+ memcpy( data, key->name, len );
+ }
}
- req->subkeys = key->last_subkey + 1;
- req->values = key->last_value + 1;
- req->modif = key->modif;
-
- namelen = strlenW(key->name) * sizeof(WCHAR);
- classlen = key->class ? strlenW(key->class) * sizeof(WCHAR) : 0;
-
- len = namelen + classlen + sizeof(WCHAR);
- if (len > get_req_data_size(req))
- {
- len = get_req_data_size(req);
- if (len < sizeof(WCHAR)) return 0;
- }
-
- *data++ = namelen;
- len -= sizeof(WCHAR);
- if (len > namelen)
- {
- memcpy( data, key->name, namelen );
- memcpy( (char *)data + namelen, key->class, min(classlen,len-namelen) );
- }
- else memcpy( data, key->name, len );
-
if (debug_level > 1) dump_operation( key, NULL, "Enum" );
- return len + sizeof(WCHAR);
}
/* delete a key and its values */
@@ -743,43 +750,13 @@
}
/* set a key value */
-static void set_value( struct key *key, WCHAR *name, int type, unsigned int total_len,
- unsigned int offset, unsigned int data_len, const void *data )
+static void set_value( struct key *key, WCHAR *name, int type, const void *data, size_t len )
{
struct key_value *value;
void *ptr = NULL;
- if (data_len + offset > total_len)
- {
- set_error( STATUS_INVALID_PARAMETER );
- return;
- }
-
- if (offset) /* adding data to an existing value */
- {
- int index;
- if (!(value = find_value( key, name, &index )))
- {
- set_error( STATUS_OBJECT_NAME_NOT_FOUND );
- return;
- }
- if (value->len != total_len)
- {
- set_error( STATUS_INVALID_PARAMETER );
- return;
- }
- memcpy( (char *)value->data + offset, data, data_len );
- if (debug_level > 1) dump_operation( key, value, "Set" );
- return;
- }
-
/* first copy the data */
- if (total_len)
- {
- if (!(ptr = mem_alloc( total_len ))) return;
- memcpy( ptr, data, data_len );
- if (data_len < total_len) memset( (char *)ptr + data_len, 0, total_len - data_len );
- }
+ if (len && !(ptr = memdup( data, len ))) return;
if (!(value = insert_value( key, name )))
{
@@ -788,30 +765,23 @@
}
if (value->data) free( value->data ); /* already existing, free previous data */
value->type = type;
- value->len = total_len;
+ value->len = len;
value->data = ptr;
touch_key( key );
if (debug_level > 1) dump_operation( key, value, "Set" );
}
/* get a key value */
-static size_t get_value( struct key *key, const WCHAR *name, unsigned int offset,
- unsigned int maxlen, int *type, int *len, void *data )
+static void get_value( struct key *key, const WCHAR *name, int *type, int *len )
{
struct key_value *value;
int index;
- size_t ret = 0;
if ((value = find_value( key, name, &index )))
{
*type = value->type;
*len = value->len;
- if (value->data && offset < value->len)
- {
- if (maxlen > value->len - offset) maxlen = value->len - offset;
- memcpy( data, (char *)value->data + offset, maxlen );
- ret = maxlen;
- }
+ if (value->data) set_reply_data( value->data, min( value->len, get_reply_max_size() ));
if (debug_level > 1) dump_operation( key, value, "Get" );
}
else
@@ -819,54 +789,57 @@
*type = -1;
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
}
- return ret;
}
/* enumerate a key value */
-static size_t enum_value( struct key *key, int i, unsigned int offset,
- unsigned int maxlen, int *type, int *len, void *data )
+static void enum_value( struct key *key, int i, int info_class, struct enum_key_value_reply *reply )
{
struct key_value *value;
- size_t ret = 0;
if (i < 0 || i > key->last_value) set_error( STATUS_NO_MORE_ENTRIES );
else
{
- WCHAR *name_ptr = data;
+ void *data;
+ size_t namelen, maxlen;
+
value = &key->values[i];
- *type = value->type;
- *len = value->len;
+ reply->type = value->type;
+ namelen = strlenW( value->name ) * sizeof(WCHAR);
- if (maxlen >= sizeof(WCHAR))
+ switch(info_class)
{
- size_t name_len = 0;
+ case KeyValueBasicInformation:
+ reply->total = namelen;
+ break;
+ case KeyValueFullInformation:
+ reply->total = namelen + value->len;
+ break;
+ case KeyValuePartialInformation:
+ reply->total = value->len;
+ namelen = 0;
+ break;
+ default:
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
- /* copy the name only the first time (offset==0),
- * otherwise store an empty name in the buffer
- */
- maxlen -= sizeof(WCHAR);
- ret += sizeof(WCHAR);
- if (!offset)
+ maxlen = min( reply->total, get_reply_max_size() );
+ if (maxlen && ((data = set_reply_data_size( maxlen ))))
+ {
+ if (maxlen > namelen)
{
- name_len = strlenW( value->name ) * sizeof(WCHAR);
- if (name_len > maxlen) name_len = maxlen;
+ reply->namelen = namelen;
+ memcpy( data, value->name, namelen );
+ memcpy( (char *)data + namelen, value->data, maxlen - namelen );
}
- *name_ptr++ = name_len;
- memcpy( name_ptr, value->name, name_len );
- maxlen -= name_len;
- ret += name_len;
- data = (char *)name_ptr + name_len;
-
- if (value->data && offset < value->len)
+ else
{
- if (maxlen > value->len - offset) maxlen = value->len - offset;
- memcpy( data, (char *)value->data + offset, maxlen );
- ret += maxlen;
+ reply->namelen = maxlen;
+ memcpy( data, value->name, maxlen );
}
}
if (debug_level > 1) dump_operation( key, value, "Enum" );
}
- return ret;
}
/* delete a value */
@@ -1585,31 +1558,30 @@
struct key *key = NULL, *parent;
unsigned int access = req->access;
WCHAR *name, *class;
- size_t len;
if (access & MAXIMUM_ALLOWED) access = KEY_ALL_ACCESS; /* FIXME: needs general solution */
- req->hkey = 0;
- if (!(name = copy_req_path( req, &len, !req->parent ))) return;
+ reply->hkey = 0;
+ if (!(name = copy_req_path( req->namelen, !req->parent ))) return;
if ((parent = get_hkey_obj( req->parent, 0 /*FIXME*/ )))
{
- if (len == get_req_data_size(req)) /* no class specified */
+ if (req->namelen == get_req_data_size()) /* no class specified */
{
- key = create_key( parent, name, NULL, req->options, req->modif, &req->created );
+ key = create_key( parent, name, NULL, req->options, req->modif, &reply->created );
}
else
{
- const WCHAR *class_ptr = (WCHAR *)((char *)get_req_data(req) + len);
+ const WCHAR *class_ptr = (WCHAR *)((char *)get_req_data() + req->namelen);
- if ((class = req_strdupW( req, class_ptr, get_req_data_size(req) - len )))
+ if ((class = req_strdupW( req, class_ptr, get_req_data_size() - req->namelen )))
{
key = create_key( parent, name, class, req->options,
- req->modif, &req->created );
+ req->modif, &reply->created );
free( class );
}
}
if (key)
{
- req->hkey = alloc_handle( current->process, key, access, 0 );
+ reply->hkey = alloc_handle( current->process, key, access, 0 );
release_object( key );
}
release_object( parent );
@@ -1623,13 +1595,13 @@
unsigned int access = req->access;
if (access & MAXIMUM_ALLOWED) access = KEY_ALL_ACCESS; /* FIXME: needs general solution */
- req->hkey = 0;
+ reply->hkey = 0;
if ((parent = get_hkey_obj( req->parent, 0 /*FIXME*/ )))
{
- WCHAR *name = copy_path( get_req_data(req), get_req_data_size(req), !req->parent );
+ WCHAR *name = copy_path( get_req_data(), get_req_data_size(), !req->parent );
if (name && (key = open_key( parent, name )))
{
- req->hkey = alloc_handle( current->process, key, access, 0 );
+ reply->hkey = alloc_handle( current->process, key, access, 0 );
release_object( key );
}
release_object( parent );
@@ -1652,15 +1624,13 @@
DECL_HANDLER(enum_key)
{
struct key *key;
- size_t len = 0;
if ((key = get_hkey_obj( req->hkey,
req->index == -1 ? KEY_QUERY_VALUE : KEY_ENUMERATE_SUB_KEYS )))
{
- len = enum_key( key, req->index, req );
+ enum_key( key, req->index, req->info_class, reply );
release_object( key );
}
- set_req_data_size( req, len );
}
/* set a value of a registry key */
@@ -1668,15 +1638,14 @@
{
struct key *key;
WCHAR *name;
- size_t len;
- if (!(name = copy_req_path( req, &len, 0 ))) return;
+ if (!(name = copy_req_path( req->namelen, 0 ))) return;
if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
{
- size_t datalen = get_req_data_size(req) - len;
- const char *data = (char *)get_req_data(req) + len;
+ size_t datalen = get_req_data_size() - req->namelen;
+ const char *data = (char *)get_req_data() + req->namelen;
- set_value( key, name, req->type, req->total, req->offset, datalen, data );
+ set_value( key, name, req->type, data, datalen );
release_object( key );
}
}
@@ -1686,33 +1655,26 @@
{
struct key *key;
WCHAR *name;
- size_t len = 0, tmp;
- req->len = 0;
- if (!(name = copy_req_path( req, &tmp, 0 ))) return;
+ reply->total = 0;
+ if (!(name = copy_path( get_req_data(), get_req_data_size(), 0 ))) return;
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
{
- len = get_value( key, name, req->offset, get_req_data_size(req),
- &req->type, &req->len, get_req_data(req) );
+ get_value( key, name, &reply->type, &reply->total );
release_object( key );
}
- set_req_data_size( req, len );
}
/* enumerate the value of a registry key */
DECL_HANDLER(enum_key_value)
{
struct key *key;
- size_t len = 0;
- req->len = 0;
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
{
- len = enum_value( key, req->index, req->offset, get_req_data_size(req),
- &req->type, &req->len, get_req_data(req) );
+ enum_value( key, req->index, req->info_class, reply );
release_object( key );
}
- set_req_data_size( req, len );
}
/* delete a value of a registry key */
@@ -1723,7 +1685,7 @@
if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
{
- if ((name = req_strdupW( req, get_req_data(req), get_req_data_size(req) )))
+ if ((name = req_strdupW( req, get_req_data(), get_req_data_size() )))
{
delete_value( key, name );
free( name );
@@ -1786,7 +1748,7 @@
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS )))
{
- register_branch_for_saving( key, get_req_data(req), get_req_data_size(req) );
+ register_branch_for_saving( key, get_req_data(), get_req_data_size() );
release_object( key );
}
}