Use struct unicode_str instead of null-terminated strings where

possible, and remove constraints on total key path length.
This commit is contained in:
Alexandre Julliard 2005-11-22 12:05:36 +00:00
parent 95414ef44c
commit 7f9e281b72
1 changed files with 213 additions and 192 deletions

View File

@ -19,8 +19,6 @@
*/
/* To do:
* - behavior with deleted keys
* - values larger than request buffer
* - symbolic links
*/
@ -65,6 +63,8 @@ struct key
struct object obj; /* object header */
WCHAR *name; /* key name */
WCHAR *class; /* key class */
unsigned short namelen; /* length of key name */
unsigned short classlen; /* length of class name */
struct key *parent; /* parent key */
int last_subkey; /* last in use subkey */
int nb_subkeys; /* count of allocated subkeys */
@ -86,7 +86,8 @@ struct key
struct key_value
{
WCHAR *name; /* value name */
int type; /* value type */
unsigned short namelen; /* length of value name */
unsigned short type; /* value type */
size_t len; /* value data length in bytes */
void *data; /* pointer to value data */
};
@ -94,6 +95,8 @@ struct key_value
#define MIN_SUBKEYS 8 /* min. number of allocated subkeys per key */
#define MIN_VALUES 8 /* min. number of allocated values per key */
#define MAX_NAME_LEN MAX_PATH /* max. length of a key name */
#define MAX_VALUE_LEN MAX_PATH /* max. length of a value name */
/* the root of the registry tree */
static struct key *root_key;
@ -118,12 +121,13 @@ static struct save_branch_info save_branch_info[MAX_SAVE_BRANCH_INFO];
/* information about a file being loaded */
struct file_load_info
{
FILE *file; /* input file */
char *buffer; /* line buffer */
int len; /* buffer length */
int line; /* current input line */
WCHAR *tmp; /* temp buffer to use while parsing input */
size_t tmplen; /* length of temp buffer */
const char *filename; /* input file name */
FILE *file; /* input file */
char *buffer; /* line buffer */
int len; /* buffer length */
int line; /* current input line */
WCHAR *tmp; /* temp buffer to use while parsing input */
size_t tmplen; /* length of temp buffer */
};
@ -169,7 +173,7 @@ static void dump_path( const struct key *key, const struct key *base, FILE *f )
dump_path( key->parent, base, f );
fprintf( f, "\\\\" );
}
dump_strW( key->name, strlenW(key->name), f, "[]" );
dump_strW( key->name, key->namelen / sizeof(WCHAR), f, "[]" );
}
/* dump a value to a text file */
@ -178,10 +182,10 @@ static void dump_value( const struct key_value *value, FILE *f )
unsigned int i;
int count;
if (value->name[0])
if (value->namelen)
{
fputc( '\"', f );
count = 1 + dump_strW( value->name, strlenW(value->name), f, "\"\"" );
count = 1 + dump_strW( value->name, value->namelen / sizeof(WCHAR), f, "\"\"" );
count += fprintf( f, "\"=" );
}
else count = fprintf( f, "@=" );
@ -313,7 +317,7 @@ static void key_destroy( struct object *obj )
if (key->class) free( key->class );
for (i = 0; i <= key->last_value; i++)
{
free( key->values[i].name );
if (key->values[i].name) free( key->values[i].name );
if (key->values[i].data) free( key->values[i].data );
}
if (key->values) free( key->values );
@ -331,81 +335,59 @@ static void key_destroy( struct object *obj )
}
}
/* 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 )
/* get the request vararg as registry path */
inline static void get_req_path( struct unicode_str *str, int skip_root )
{
static WCHAR buffer[MAX_PATH+1];
static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\',0 };
static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\' };
if (len > sizeof(buffer)-sizeof(buffer[0]))
{
set_error( STATUS_BUFFER_OVERFLOW );
return NULL;
}
memcpy( buffer, path, len );
buffer[len / sizeof(WCHAR)] = 0;
if (skip_root && !strncmpiW( buffer, root_name, 10 )) return buffer + 10;
return buffer;
}
str->str = get_req_data();
str->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
/* 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();
if (len > get_req_data_size())
if (skip_root && str->len >= sizeof(root_name) &&
!memicmpW( str->str, root_name, sizeof(root_name)/sizeof(WCHAR) ))
{
fatal_protocol_error( current, "copy_req_path: invalid length %d/%d\n",
len, get_req_data_size() );
return NULL;
str->str += sizeof(root_name)/sizeof(WCHAR);
str->len -= sizeof(root_name);
}
return copy_path( name_ptr, len, skip_root );
}
/* return the next token in a given path */
/* returns a pointer to a static buffer, so only useable once per request */
static WCHAR *get_path_token( WCHAR *initpath )
/* token->str must point inside the path, or be NULL for the first call */
static struct unicode_str *get_path_token( const struct unicode_str *path, struct unicode_str *token )
{
static WCHAR *path;
WCHAR *ret;
size_t i = 0, len = path->len / sizeof(WCHAR);
if (initpath)
if (!token->str) /* first time */
{
/* path cannot start with a backslash */
if (*initpath == '\\')
if (len && path->str[0] == '\\')
{
set_error( STATUS_OBJECT_PATH_INVALID );
return NULL;
}
path = initpath;
}
else while (*path == '\\') path++;
ret = path;
while (*path && *path != '\\') path++;
if (*path) *path++ = 0;
return ret;
}
/* duplicate a Unicode string from the request buffer */
static WCHAR *req_strdupW( const void *req, const WCHAR *str, size_t len )
{
WCHAR *name;
if ((name = mem_alloc( len + sizeof(WCHAR) )) != NULL)
else
{
memcpy( name, str, len );
name[len / sizeof(WCHAR)] = 0;
i = token->str - path->str;
i += token->len / sizeof(WCHAR);
while (i < len && path->str[i] == '\\') i++;
}
return name;
token->str = path->str + i;
while (i < len && path->str[i] != '\\') i++;
token->len = (path->str + i - token->str) * sizeof(WCHAR);
return token;
}
/* allocate a key object */
static struct key *alloc_key( const WCHAR *name, time_t modif )
static struct key *alloc_key( const struct unicode_str *name, time_t modif )
{
struct key *key;
if ((key = alloc_object( &key_ops )))
{
key->name = NULL;
key->class = NULL;
key->namelen = name->len;
key->classlen = 0;
key->flags = 0;
key->last_subkey = -1;
key->nb_subkeys = 0;
@ -416,7 +398,7 @@ static struct key *alloc_key( const WCHAR *name, time_t modif )
key->modif = modif;
key->parent = NULL;
list_init( &key->notify_list );
if (!(key->name = strdupW( name )))
if (name->len && !(key->name = memdup( name->str, name->len )))
{
release_object( key );
key = NULL;
@ -500,11 +482,17 @@ static int grow_subkeys( struct key *key )
}
/* allocate a subkey for a given key, and return its index */
static struct key *alloc_subkey( struct key *parent, const WCHAR *name, int index, time_t modif )
static struct key *alloc_subkey( struct key *parent, const struct unicode_str *name,
int index, time_t modif )
{
struct key *key;
int i;
if (name->len > MAX_NAME_LEN * sizeof(WCHAR))
{
set_error( STATUS_NAME_TOO_LONG );
return NULL;
}
if (parent->last_subkey + 1 == parent->nb_subkeys)
{
/* need to grow the array */
@ -550,16 +538,20 @@ static void free_subkey( struct key *parent, int index )
}
/* find the named child of a given key and return its index */
static struct key *find_subkey( const struct key *key, const WCHAR *name, int *index )
static struct key *find_subkey( const struct key *key, const struct unicode_str *name, int *index )
{
int i, min, max, res;
size_t len;
min = 0;
max = key->last_subkey;
while (min <= max)
{
i = (min + max) / 2;
if (!(res = strcmpiW( key->subkeys[i]->name, name )))
len = min( key->subkeys[i]->namelen, name->len );
res = memicmpW( key->subkeys[i]->name, name->str, len / sizeof(WCHAR) );
if (!res) res = key->subkeys[i]->namelen - name->len;
if (!res)
{
*index = i;
return key->subkeys[i];
@ -572,21 +564,21 @@ static struct key *find_subkey( const struct key *key, const WCHAR *name, int *i
}
/* open a subkey */
/* warning: the key name must be writeable (use copy_path) */
static struct key *open_key( struct key *key, WCHAR *name )
static struct key *open_key( struct key *key, const struct unicode_str *name )
{
int index;
WCHAR *path;
struct unicode_str token;
if (!(path = get_path_token( name ))) return NULL;
while (*path)
token.str = NULL;
if (!get_path_token( name, &token )) return NULL;
while (token.len)
{
if (!(key = find_subkey( key, path, &index )))
if (!(key = find_subkey( key, &token, &index )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
break;
}
path = get_path_token( NULL );
get_path_token( name, &token );
}
if (debug_level > 1) dump_operation( key, NULL, "Open" );
@ -595,13 +587,12 @@ static struct key *open_key( struct key *key, WCHAR *name )
}
/* create a subkey */
/* warning: the key name must be writeable (use copy_path) */
static struct key *create_key( struct key *key, WCHAR *name, WCHAR *class,
int flags, time_t modif, int *created )
static struct key *create_key( struct key *key, const struct unicode_str *name,
const struct unicode_str *class, int flags, time_t modif, int *created )
{
struct key *base;
int base_idx, index;
WCHAR *path;
int index;
struct unicode_str token;
if (key->flags & KEY_DELETED) /* we cannot create a subkey under a deleted key */
{
@ -615,38 +606,44 @@ static struct key *create_key( struct key *key, WCHAR *name, WCHAR *class,
}
if (!modif) modif = time(NULL);
if (!(path = get_path_token( name ))) return NULL;
token.str = NULL;
if (!get_path_token( name, &token )) return NULL;
*created = 0;
while (*path)
while (token.len)
{
struct key *subkey;
if (!(subkey = find_subkey( key, path, &index ))) break;
if (!(subkey = find_subkey( key, &token, &index ))) break;
key = subkey;
path = get_path_token( NULL );
get_path_token( name, &token );
}
/* create the remaining part */
if (!*path) goto done;
if (!token.len) goto done;
*created = 1;
if (flags & KEY_DIRTY) make_dirty( key );
if (!(key = alloc_subkey( key, &token, index, modif ))) return NULL;
base = key;
base_idx = index;
key = alloc_subkey( key, path, index, modif );
while (key)
for (;;)
{
key->flags |= flags;
path = get_path_token( NULL );
if (!*path) goto done;
get_path_token( name, &token );
if (!token.len) break;
/* we know the index is always 0 in a new key */
key = alloc_subkey( key, path, 0, modif );
if (!(key = alloc_subkey( key, &token, 0, modif )))
{
free_subkey( base, index );
return NULL;
}
}
if (base_idx != -1) free_subkey( base, base_idx );
return NULL;
done:
if (debug_level > 1) dump_operation( key, NULL, "Create" );
if (class) key->class = strdupW(class);
if (class && class->len)
{
key->classlen = class->len;
if (!(key->class = memdup( class->str, key->classlen ))) key->classlen = 0;
}
grab_object( key );
return key;
}
@ -659,7 +656,7 @@ static void enum_key( const struct key *key, int index, int info_class,
size_t len, namelen, classlen;
int max_subkey = 0, max_class = 0;
int max_value = 0, max_data = 0;
WCHAR *data;
char *data;
if (index != -1) /* -1 means use the specified key directly */
{
@ -671,8 +668,8 @@ static void enum_key( const struct key *key, int index, int info_class,
key = key->subkeys[index];
}
namelen = strlenW(key->name) * sizeof(WCHAR);
classlen = key->class ? strlenW(key->class) * sizeof(WCHAR) : 0;
namelen = key->namelen;
classlen = key->classlen;
switch(info_class)
{
@ -689,15 +686,14 @@ static void enum_key( const struct key *key, int index, int info_class,
for (i = 0; i <= key->last_subkey; i++)
{
struct key *subkey = key->subkeys[i];
len = strlenW( subkey->name );
len = subkey->namelen / sizeof(WCHAR);
if (len > max_subkey) max_subkey = len;
if (!subkey->class) continue;
len = strlenW( subkey->class );
len = subkey->classlen / sizeof(WCHAR);
if (len > max_class) max_class = len;
}
for (i = 0; i <= key->last_value; i++)
{
len = strlenW( key->values[i].name );
len = key->values[i].namelen / sizeof(WCHAR);
if (len > max_value) max_value = len;
len = key->values[i].len;
if (len > max_data) max_data = len;
@ -724,7 +720,7 @@ static void enum_key( const struct key *key, int index, int info_class,
{
reply->namelen = namelen;
memcpy( data, key->name, namelen );
memcpy( (char *)data + namelen, key->class, len - namelen );
memcpy( data + namelen, key->class, len - namelen );
}
else
{
@ -800,16 +796,20 @@ static int grow_values( struct key *key )
}
/* find the named value of a given key and return its index in the array */
static struct key_value *find_value( const struct key *key, const WCHAR *name, int *index )
static struct key_value *find_value( const struct key *key, const struct unicode_str *name, int *index )
{
int i, min, max, res;
size_t len;
min = 0;
max = key->last_value;
while (min <= max)
{
i = (min + max) / 2;
if (!(res = strcmpiW( key->values[i].name, name )))
len = min( key->values[i].namelen, name->len );
res = memicmpW( key->values[i].name, name->str, len / sizeof(WCHAR) );
if (!res) res = key->values[i].namelen - name->len;
if (!res)
{
*index = i;
return &key->values[i];
@ -822,27 +822,34 @@ static struct key_value *find_value( const struct key *key, const WCHAR *name, i
}
/* insert a new value; the index must have been returned by find_value */
static struct key_value *insert_value( struct key *key, const WCHAR *name, int index )
static struct key_value *insert_value( struct key *key, const struct unicode_str *name, int index )
{
struct key_value *value;
WCHAR *new_name;
WCHAR *new_name = NULL;
int i;
if (name->len > MAX_VALUE_LEN * sizeof(WCHAR))
{
set_error( STATUS_NAME_TOO_LONG );
return NULL;
}
if (key->last_value + 1 == key->nb_values)
{
if (!grow_values( key )) return NULL;
}
if (!(new_name = strdupW(name))) return NULL;
if (name->len && !(new_name = memdup( name->str, name->len ))) return NULL;
for (i = ++key->last_value; i > index; i--) key->values[i] = key->values[i - 1];
value = &key->values[index];
value->name = new_name;
value->len = 0;
value->data = NULL;
value->name = new_name;
value->namelen = name->len;
value->len = 0;
value->data = NULL;
return value;
}
/* set a key value */
static void set_value( struct key *key, WCHAR *name, int type, const void *data, size_t len )
static void set_value( struct key *key, const struct unicode_str *name,
int type, const void *data, size_t len )
{
struct key_value *value;
void *ptr = NULL;
@ -879,7 +886,7 @@ static void set_value( struct key *key, WCHAR *name, int type, const void *data,
}
/* get a key value */
static void get_value( struct key *key, const WCHAR *name, int *type, unsigned int *len )
static void get_value( struct key *key, const struct unicode_str *name, int *type, unsigned int *len )
{
struct key_value *value;
int index;
@ -911,7 +918,7 @@ static void enum_value( struct key *key, int i, int info_class, struct enum_key_
value = &key->values[i];
reply->type = value->type;
namelen = strlenW( value->name ) * sizeof(WCHAR);
namelen = value->namelen;
switch(info_class)
{
@ -950,7 +957,7 @@ static void enum_value( struct key *key, int i, int info_class, struct enum_key_
}
/* delete a value */
static void delete_value( struct key *key, const WCHAR *name )
static void delete_value( struct key *key, const struct unicode_str *name )
{
struct key_value *value;
int i, index, nb_values;
@ -961,7 +968,7 @@ static void delete_value( struct key *key, const WCHAR *name )
return;
}
if (debug_level > 1) dump_operation( key, value, "Delete" );
free( value->name );
if (value->name) free( value->name );
if (value->data) free( value->data );
for (i = index; i < key->last_value; i++) key->values[i] = key->values[i + 1];
key->last_value--;
@ -1038,14 +1045,17 @@ static int get_file_tmp_space( struct file_load_info *info, size_t size )
/* report an error while loading an input file */
static void file_read_error( const char *err, struct file_load_info *info )
{
fprintf( stderr, "Line %d: %s '%s'\n", info->line, err, info->buffer );
if (info->filename)
fprintf( stderr, "%s:%d: %s '%s'\n", info->filename, info->line, err, info->buffer );
else
fprintf( stderr, "<fd>:%d: %s '%s'\n", info->line, err, info->buffer );
}
/* parse an escaped string back into Unicode */
/* return the number of chars read from the input, or -1 on output overflow */
static int parse_strW( WCHAR *dest, int *len, const char *src, char endchar )
static int parse_strW( WCHAR *dest, size_t *len, const char *src, char endchar )
{
int count = sizeof(WCHAR); /* for terminating null */
size_t count = sizeof(WCHAR); /* for terminating null */
const char *p = src;
while (*p && *p != endchar)
{
@ -1138,10 +1148,11 @@ static struct key *load_key( struct key *base, const char *buffer, int flags,
int prefix_len, struct file_load_info *info,
int default_modif )
{
WCHAR *p, *name;
int res, len, modif;
WCHAR *p;
struct unicode_str name;
int res, modif;
size_t len = strlen(buffer) * sizeof(WCHAR);
len = strlen(buffer) * sizeof(WCHAR);
if (!get_file_tmp_space( info, len )) return NULL;
if ((res = parse_strW( info->tmp, &len, buffer, ']' )) == -1)
@ -1164,19 +1175,16 @@ static struct key *load_key( struct key *base, const char *buffer, int flags,
/* empty key name, return base key */
return (struct key *)grab_object( base );
}
if (!(name = copy_path( p, len - (p - info->tmp) * sizeof(WCHAR), 0 )))
{
file_read_error( "Key is too long", info );
return NULL;
}
return create_key( base, name, NULL, flags, modif, &res );
name.str = p;
name.len = len - (p - info->tmp + 1) * sizeof(WCHAR);
return create_key( base, &name, NULL, flags, modif, &res );
}
/* parse a comma-separated list of hex digits */
static int parse_hex( unsigned char *dest, int *len, const char *buffer )
static int parse_hex( unsigned char *dest, size_t *len, const char *buffer )
{
const char *p = buffer;
int count = 0;
size_t count = 0;
while (isxdigit(*p))
{
int val;
@ -1194,30 +1202,32 @@ static int parse_hex( unsigned char *dest, int *len, const char *buffer )
}
/* parse a value name and create the corresponding value */
static struct key_value *parse_value_name( struct key *key, const char *buffer, int *len,
static struct key_value *parse_value_name( struct key *key, const char *buffer, size_t *len,
struct file_load_info *info )
{
struct key_value *value;
int index, maxlen;
struct unicode_str name;
int index;
size_t maxlen = strlen(buffer) * sizeof(WCHAR);
maxlen = strlen(buffer) * sizeof(WCHAR);
if (!get_file_tmp_space( info, maxlen )) return NULL;
name.str = info->tmp;
if (buffer[0] == '@')
{
info->tmp[0] = 0;
name.len = 0;
*len = 1;
}
else
{
if ((*len = parse_strW( info->tmp, &maxlen, buffer + 1, '\"' )) == -1) goto error;
name.len = maxlen - sizeof(WCHAR);
(*len)++; /* for initial quote */
}
while (isspace(buffer[*len])) (*len)++;
if (buffer[*len] != '=') goto error;
(*len)++;
while (isspace(buffer[*len])) (*len)++;
if (!(value = find_value( key, info->tmp, &index )))
value = insert_value( key, info->tmp, index );
if (!(value = find_value( key, &name, &index ))) value = insert_value( key, &name, index );
return value;
error:
@ -1230,8 +1240,8 @@ static int load_value( struct key *key, const char *buffer, struct file_load_inf
{
DWORD dw;
void *ptr, *newptr;
int maxlen, len, res;
int type, parse_type;
int res, type, parse_type;
size_t maxlen, len;
struct key_value *value;
if (!(value = parse_value_name( key, buffer, &len, info ))) return 0;
@ -1296,7 +1306,8 @@ static int get_prefix_len( struct key *key, const char *name, struct file_load_i
{
WCHAR *p;
int res;
int len = strlen(name) * sizeof(WCHAR);
size_t len = strlen(name) * sizeof(WCHAR);
if (!get_file_tmp_space( info, len )) return 0;
if ((res = parse_strW( info->tmp, &len, name, ']' )) == -1)
@ -1305,10 +1316,10 @@ static int get_prefix_len( struct key *key, const char *name, struct file_load_i
return 0;
}
for (p = info->tmp; *p; p++) if (*p == '\\') break;
*p = 0;
len = (p - info->tmp) * sizeof(WCHAR);
for (res = 1; key != root_key; res++)
{
if (!strcmpiW( info->tmp, key->name )) break;
if (len == key->namelen && !memicmpW( info->tmp, key->name, len / sizeof(WCHAR) )) break;
key = key->parent;
}
if (key == root_key) res = 0; /* no matching name */
@ -1317,7 +1328,7 @@ static int get_prefix_len( struct key *key, const char *name, struct file_load_i
/* load all the keys from the input file */
/* prefix_len is the number of key name prefixes to skip, or -1 for autodetection */
static void load_keys( struct key *key, FILE *f, int prefix_len )
static void load_keys( struct key *key, const char *filename, FILE *f, int prefix_len )
{
struct key *subkey = NULL;
struct file_load_info info;
@ -1325,6 +1336,7 @@ static void load_keys( struct key *key, FILE *f, int prefix_len )
int default_modif = time(NULL);
int flags = (key->flags & KEY_VOLATILE) ? KEY_VOLATILE : KEY_DIRTY;
info.filename = filename;
info.file = f;
info.len = 4;
info.tmplen = 4;
@ -1390,7 +1402,7 @@ static void load_registry( struct key *key, obj_handle_t handle )
FILE *f = fdopen( fd, "r" );
if (f)
{
load_keys( key, f, -1 );
load_keys( key, NULL, f, -1 );
fclose( f );
}
else file_set_error();
@ -1404,24 +1416,22 @@ static void load_init_registry_from_file( const char *filename, struct key *key
if ((f = fopen( filename, "r" )))
{
load_keys( key, f, 0 );
load_keys( key, filename, f, 0 );
fclose( f );
if (get_error() == STATUS_NOT_REGISTRY_FILE)
fatal_error( "%s is not a valid registry file\n", filename );
if (get_error())
fatal_error( "loading %s failed with error %x\n", filename, get_error() );
{
fprintf( stderr, "%s is not a valid registry file\n", filename );
return;
}
}
if (!(key->flags & KEY_VOLATILE))
{
assert( save_branch_count < MAX_SAVE_BRANCH_INFO );
assert( save_branch_count < MAX_SAVE_BRANCH_INFO );
if ((save_branch_info[save_branch_count].path = strdup( filename )))
save_branch_info[save_branch_count++].key = (struct key *)grab_object( key );
}
if ((save_branch_info[save_branch_count].path = strdup( filename )))
save_branch_info[save_branch_count++].key = (struct key *)grab_object( key );
}
static WCHAR *format_user_registry_path( const SID *sid )
static WCHAR *format_user_registry_path( const SID *sid, struct unicode_str *path )
{
static const WCHAR prefixW[] = {'U','s','e','r','\\','S',0};
static const WCHAR formatW[] = {'-','%','u',0};
@ -1439,16 +1449,22 @@ static WCHAR *format_user_registry_path( const SID *sid )
for (i = 0; i < sid->SubAuthorityCount; i++)
p += sprintfW( p, formatW, sid->SubAuthority[i] );
return memdup( buffer, (p + 1 - buffer) * sizeof(WCHAR) );
path->len = (p - buffer) * sizeof(WCHAR);
path->str = p = memdup( buffer, path->len );
return p;
}
/* registry initialisation */
void init_registry(void)
{
static const WCHAR root_name[] = { 0 };
static const WCHAR HKLM[] = { 'M','a','c','h','i','n','e' };
static const WCHAR HKU_default[] = { 'U','s','e','r','\\','.','D','e','f','a','u','l','t' };
static const struct unicode_str root_name = { NULL, 0 };
static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) };
static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) };
WCHAR *current_user_path;
struct unicode_str current_user_str;
const char *config = wine_get_config_dir();
char *p, *filename;
@ -1456,7 +1472,7 @@ void init_registry(void)
int dummy;
/* create the root key */
root_key = alloc_key( root_name, time(NULL) );
root_key = alloc_key( &root_name, time(NULL) );
assert( root_key );
if (!(filename = malloc( strlen(config) + 16 ))) fatal_error( "out of memory\n" );
@ -1465,8 +1481,7 @@ void init_registry(void)
/* load system.reg into Registry\Machine */
if (!(key = create_key( root_key, copy_path( HKLM, sizeof(HKLM), 0 ),
NULL, 0, time(NULL), &dummy )))
if (!(key = create_key( root_key, &HKLM_name, NULL, 0, time(NULL), &dummy )))
fatal_error( "could not create Machine registry key\n" );
strcpy( p, "/system.reg" );
@ -1475,8 +1490,7 @@ void init_registry(void)
/* load userdef.reg into Registry\User\.Default */
if (!(key = create_key( root_key, copy_path( HKU_default, sizeof(HKU_default), 0 ),
NULL, 0, time(NULL), &dummy )))
if (!(key = create_key( root_key, &HKU_name, NULL, 0, time(NULL), &dummy )))
fatal_error( "could not create User\\.Default registry key\n" );
strcpy( p, "/userdef.reg" );
@ -1486,9 +1500,9 @@ void init_registry(void)
/* load user.reg into HKEY_CURRENT_USER */
/* FIXME: match default user in token.c. should get from process token instead */
current_user_path = format_user_registry_path( security_interactive_sid );
current_user_path = format_user_registry_path( security_interactive_sid, &current_user_str );
if (!current_user_path ||
!(key = create_key( root_key, current_user_path, NULL, 0, time(NULL), &dummy )))
!(key = create_key( root_key, &current_user_str, NULL, 0, time(NULL), &dummy )))
fatal_error( "could not create HKEY_CURRENT_USER registry key\n" );
free( current_user_path );
strcpy( p, "/user.reg" );
@ -1686,32 +1700,33 @@ void close_registry(void)
DECL_HANDLER(create_key)
{
struct key *key = NULL, *parent;
struct unicode_str name, class;
unsigned int access = req->access;
WCHAR *name, *class;
if (access & MAXIMUM_ALLOWED) access = KEY_ALL_ACCESS; /* FIXME: needs general solution */
reply->hkey = 0;
if (!(name = copy_req_path( req->namelen, !req->parent ))) return;
if (req->namelen > get_req_data_size())
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
class.str = (const WCHAR *)get_req_data() + req->namelen / sizeof(WCHAR);
class.len = ((get_req_data_size() - req->namelen) / sizeof(WCHAR)) * sizeof(WCHAR);
get_req_path( &name, !req->parent );
if (name.str > class.str)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
name.len = (class.str - name.str) * sizeof(WCHAR);
/* NOTE: no access rights are required from the parent handle to create a key */
if ((parent = get_hkey_obj( req->parent, 0 )))
{
int flags = (req->options & REG_OPTION_VOLATILE) ? KEY_VOLATILE : KEY_DIRTY;
if (req->namelen == get_req_data_size()) /* no class specified */
{
key = create_key( parent, name, NULL, flags, req->modif, &reply->created );
}
else
{
const WCHAR *class_ptr = (const WCHAR *)((const char *)get_req_data() + req->namelen);
if ((class = req_strdupW( req, class_ptr, get_req_data_size() - req->namelen )))
{
key = create_key( parent, name, class, flags, req->modif, &reply->created );
free( class );
}
}
if (key)
if ((key = create_key( parent, &name, &class, flags, req->modif, &reply->created )))
{
reply->hkey = alloc_handle( current->process, key, access, 0 );
release_object( key );
@ -1724,6 +1739,7 @@ DECL_HANDLER(create_key)
DECL_HANDLER(open_key)
{
struct key *key, *parent;
struct unicode_str name;
unsigned int access = req->access;
if (access & MAXIMUM_ALLOWED) access = KEY_ALL_ACCESS; /* FIXME: needs general solution */
@ -1731,8 +1747,8 @@ DECL_HANDLER(open_key)
/* NOTE: no access rights are required to open the parent key, only the child key */
if ((parent = get_hkey_obj( req->parent, 0 )))
{
WCHAR *name = copy_path( get_req_data(), get_req_data_size(), !req->parent );
if (name && (key = open_key( parent, name )))
get_req_path( &name, !req->parent );
if ((key = open_key( parent, &name )))
{
reply->hkey = alloc_handle( current->process, key, access, 0 );
release_object( key );
@ -1781,15 +1797,22 @@ DECL_HANDLER(enum_key)
DECL_HANDLER(set_key_value)
{
struct key *key;
WCHAR *name;
struct unicode_str name;
if (req->namelen > get_req_data_size())
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
name.str = get_req_data();
name.len = (req->namelen / sizeof(WCHAR)) * sizeof(WCHAR);
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->namelen;
const char *data = (const char *)get_req_data() + req->namelen;
set_value( key, name, req->type, data, datalen );
set_value( key, &name, req->type, data, datalen );
release_object( key );
}
}
@ -1798,13 +1821,13 @@ DECL_HANDLER(set_key_value)
DECL_HANDLER(get_key_value)
{
struct key *key;
WCHAR *name;
struct unicode_str name;
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 )))
{
get_value( key, name, &reply->type, &reply->total );
get_req_unicode_str( &name );
get_value( key, &name, &reply->type, &reply->total );
release_object( key );
}
}
@ -1824,16 +1847,13 @@ DECL_HANDLER(enum_key_value)
/* delete a value of a registry key */
DECL_HANDLER(delete_key_value)
{
WCHAR *name;
struct key *key;
struct unicode_str name;
if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
{
if ((name = req_strdupW( req, get_req_data(), get_req_data_size() )))
{
delete_value( key, name );
free( name );
}
get_req_unicode_str( &name );
delete_value( key, &name );
release_object( key );
}
}
@ -1843,6 +1863,7 @@ DECL_HANDLER(load_registry)
{
struct key *key, *parent;
struct token *token = thread_get_impersonation_token( current );
struct unicode_str name;
const LUID_AND_ATTRIBUTES privs[] =
{
@ -1860,8 +1881,8 @@ DECL_HANDLER(load_registry)
if ((parent = get_hkey_obj( req->hkey, 0 )))
{
int dummy;
WCHAR *name = copy_path( get_req_data(), get_req_data_size(), !req->hkey );
if (name && (key = create_key( parent, name, NULL, KEY_DIRTY, time(NULL), &dummy )))
get_req_path( &name, !req->hkey );
if ((key = create_key( parent, &name, NULL, KEY_DIRTY, time(NULL), &dummy )))
{
load_registry( key, req->file );
release_object( key );