mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-03 00:42:46 +00:00
server: Use standard named object functions for registry keys.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b79ff648ef
commit
569c27945e
|
@ -1009,13 +1009,11 @@ static void test_name_limits(void)
|
|||
status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
|
||||
ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %lx\n", str.Length, status );
|
||||
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
|
||||
todo_wine
|
||||
ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %lx\n", str.Length, status );
|
||||
str.Length = 2000;
|
||||
status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
|
||||
ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %lx\n", str.Length, status );
|
||||
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
|
||||
todo_wine
|
||||
ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %lx\n", str.Length, status );
|
||||
/* some Windows versions change the error past 2050 chars, others past 4066 chars, some don't */
|
||||
str.Length = 5000;
|
||||
|
@ -1026,7 +1024,6 @@ static void test_name_limits(void)
|
|||
"%u: NtCreateKey failed %lx\n", str.Length, status );
|
||||
ret = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
|
||||
todo_wine
|
||||
ok( status == STATUS_BUFFER_OVERFLOW ||
|
||||
status == STATUS_BUFFER_TOO_SMALL ||
|
||||
status == STATUS_INVALID_PARAMETER,
|
||||
|
@ -1042,7 +1039,6 @@ static void test_name_limits(void)
|
|||
ok( !ret, "handle set %p\n", ret );
|
||||
ret = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_NAME_INVALID ||
|
||||
status == STATUS_BUFFER_OVERFLOW ||
|
||||
status == STATUS_BUFFER_TOO_SMALL,
|
||||
|
|
|
@ -382,8 +382,7 @@ static void test_NtOpenKey(void)
|
|||
InitializeObjectAttributes(&attr, &str, 0, 0, 0);
|
||||
key = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08lx\n", status);
|
||||
todo_wine
|
||||
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08lx\n", status);
|
||||
ok(!key, "key = %p\n", key);
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
|
@ -402,25 +401,21 @@ static void test_NtOpenKey(void)
|
|||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\\\\\" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pNtClose( key );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
@ -433,38 +428,32 @@ static void test_NtOpenKey(void)
|
|||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\\\" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pNtClose( key );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
|
@ -608,13 +597,11 @@ static void test_NtCreateKey(void)
|
|||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
|
||||
"NtCreateKey failed: 0x%08lx\n", status );
|
||||
if (!status) pNtClose( subkey );
|
||||
|
@ -629,7 +616,6 @@ static void test_NtCreateKey(void)
|
|||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\\\" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
|
||||
"NtCreateKey failed: 0x%08lx\n", status );
|
||||
if (!status) pNtClose( subkey );
|
||||
|
@ -637,31 +623,26 @@ static void test_NtCreateKey(void)
|
|||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
|
||||
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
||||
todo_wine
|
||||
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
|
@ -1318,17 +1299,9 @@ static void test_symlinks(void)
|
|||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08lx\n", status );
|
||||
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pNtClose( key );
|
||||
if (status) /* can be removed once todo_wine above is fixed */
|
||||
{
|
||||
attr.ObjectName = &target_str;
|
||||
attr.Attributes = OBJ_OPENLINK;
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
|
||||
pNtClose( key );
|
||||
}
|
||||
|
||||
attr.ObjectName = &target_str;
|
||||
attr.Attributes = OBJ_OPENLINK;
|
||||
|
@ -1424,7 +1397,6 @@ static void test_symlinks(void)
|
|||
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
|
||||
|
||||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
todo_wine
|
||||
ok( status == STATUS_NAME_TOO_LONG || status == STATUS_INVALID_PARAMETER /* Win10 1607+ */,
|
||||
"NtOpenKey failed: 0x%08lx\n", status );
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ struct key
|
|||
#define KEY_WOWSHARE 0x0010 /* key is a Wow64 shared key (used for Software\Classes) */
|
||||
#define KEY_PREDEF 0x0020 /* key is marked as predefined */
|
||||
|
||||
#define OBJ_KEY_WOW64 0x100000 /* magic flag added to attributes for WoW64 redirection */
|
||||
|
||||
/* a key value */
|
||||
struct key_value
|
||||
{
|
||||
|
@ -124,7 +126,6 @@ static const timeout_t save_period = 30 * -TICKS_PER_SEC; /* delay between peri
|
|||
static struct timeout_user *save_timeout_user; /* saving timer */
|
||||
static enum prefix_type { PREFIX_UNKNOWN, PREFIX_32BIT, PREFIX_64BIT } prefix_type;
|
||||
|
||||
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) };
|
||||
|
@ -198,6 +199,7 @@ static const struct object_ops key_ops =
|
|||
|
||||
static inline int is_wow6432node( const WCHAR *name, unsigned int len )
|
||||
{
|
||||
len = get_path_element( name, len );
|
||||
return (len == sizeof(wow6432node) && !memicmp_strW( name, wow6432node, sizeof( wow6432node )));
|
||||
}
|
||||
|
||||
|
@ -461,30 +463,14 @@ static struct security_descriptor *key_get_sd( struct object *obj )
|
|||
|
||||
static WCHAR *key_get_full_name( struct object *obj, data_size_t *ret_len )
|
||||
{
|
||||
static const WCHAR backslash = '\\';
|
||||
struct key *key = (struct key *) obj;
|
||||
data_size_t len = sizeof(root_name) - sizeof(WCHAR);
|
||||
char *ret;
|
||||
|
||||
if (key->flags & KEY_DELETED)
|
||||
{
|
||||
set_error( STATUS_KEY_DELETED );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (key = (struct key *)obj; key != root_key; key = get_parent( key )) len += key->obj.name->len + sizeof(WCHAR);
|
||||
if (!(ret = malloc( len ))) return NULL;
|
||||
|
||||
*ret_len = len;
|
||||
key = (struct key *)obj;
|
||||
for (key = (struct key *)obj; key != root_key; key = get_parent( key ))
|
||||
{
|
||||
memcpy( ret + len - key->obj.name->len, key->obj.name->name, key->obj.name->len );
|
||||
len -= key->obj.name->len + sizeof(WCHAR);
|
||||
memcpy( ret + len, &backslash, sizeof(WCHAR) );
|
||||
}
|
||||
memcpy( ret, root_name, sizeof(root_name) - sizeof(WCHAR) );
|
||||
return (WCHAR *)ret;
|
||||
return default_get_full_name( obj, ret_len );
|
||||
}
|
||||
|
||||
static struct object *key_lookup_name( struct object *obj, struct unicode_str *name,
|
||||
|
@ -549,6 +535,13 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
|
|||
if (name->str[next / sizeof(WCHAR)] != '\\') break;
|
||||
|
||||
if (!(found = find_subkey( key, &tmp, &index )))
|
||||
{
|
||||
/* try in the 64-bit parent */
|
||||
if ((key->flags & KEY_WOWSHARE) && (attr & OBJ_KEY_WOW64))
|
||||
found = find_subkey( get_parent( key ), &tmp, &index );
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (next < name->len) /* path still has elements */
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
|
@ -561,6 +554,8 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
|
|||
{
|
||||
name->str += next / sizeof(WCHAR);
|
||||
name->len -= next;
|
||||
if ((attr & OBJ_KEY_WOW64) && found->wow6432node && !is_wow6432node( name->str, name->len ))
|
||||
found = found->wow6432node;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -676,58 +671,20 @@ static void key_destroy( struct object *obj )
|
|||
}
|
||||
}
|
||||
|
||||
/* get the request vararg as registry path */
|
||||
static inline void get_req_path( struct unicode_str *str, int skip_root )
|
||||
{
|
||||
str->str = get_req_data();
|
||||
str->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
|
||||
|
||||
if (skip_root && str->len >= sizeof(root_name) && !memicmp_strW( str->str, root_name, sizeof(root_name) ))
|
||||
{
|
||||
str->str += ARRAY_SIZE( root_name );
|
||||
str->len -= sizeof(root_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* return the next token in a given path */
|
||||
/* 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 )
|
||||
{
|
||||
data_size_t i = 0, len = path->len / sizeof(WCHAR);
|
||||
|
||||
if (!token->str) /* first time */
|
||||
{
|
||||
/* path cannot start with a backslash */
|
||||
if (len && path->str[0] == '\\')
|
||||
{
|
||||
set_error( STATUS_OBJECT_PATH_INVALID );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = token->str - path->str;
|
||||
i += token->len / sizeof(WCHAR);
|
||||
while (i < len && path->str[i] == '\\') i++;
|
||||
}
|
||||
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 struct unicode_str *name, timeout_t modif )
|
||||
static struct key *create_key_object( struct object *parent, const struct unicode_str *name,
|
||||
unsigned int attributes, unsigned int options, timeout_t modif,
|
||||
const struct security_descriptor *sd )
|
||||
{
|
||||
struct object_name *name_ptr;
|
||||
struct key *key;
|
||||
|
||||
if (!(name_ptr = mem_alloc( offsetof( struct object_name, name[name->len / sizeof(WCHAR)] ))))
|
||||
return NULL;
|
||||
if (!name->len) return open_named_object( parent, &key_ops, name, attributes );
|
||||
|
||||
if ((key = alloc_object( &key_ops )))
|
||||
if ((key = create_named_object( parent, &key_ops, name, attributes, sd )))
|
||||
{
|
||||
key->obj.name = name_ptr;
|
||||
if (get_error() != STATUS_OBJECT_NAME_EXISTS)
|
||||
{
|
||||
/* initialize it if it didn't already exist */
|
||||
key->class = NULL;
|
||||
key->classlen = 0;
|
||||
key->flags = 0;
|
||||
|
@ -741,12 +698,18 @@ static struct key *alloc_key( const struct unicode_str *name, timeout_t modif )
|
|||
key->modif = modif;
|
||||
list_init( &key->notify_list );
|
||||
|
||||
name_ptr->obj = &key->obj;
|
||||
name_ptr->len = name->len;
|
||||
name_ptr->parent = NULL;
|
||||
memcpy( name_ptr->name, name->str, name->len );
|
||||
if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK;
|
||||
if (options & REG_OPTION_VOLATILE) key->flags |= KEY_VOLATILE;
|
||||
else if (parent && (get_parent( key )->flags & KEY_VOLATILE))
|
||||
{
|
||||
set_error( STATUS_CHILD_MUST_BE_VOLATILE );
|
||||
unlink_named_object( &key->obj );
|
||||
release_object( key );
|
||||
return NULL;
|
||||
}
|
||||
else key->flags |= KEY_DIRTY;
|
||||
}
|
||||
}
|
||||
else free( name_ptr );
|
||||
return key;
|
||||
}
|
||||
|
||||
|
@ -796,223 +759,104 @@ static void touch_key( struct key *key, unsigned int change )
|
|||
for (key = get_parent( key ); key; key = get_parent( key )) check_notify( key, change, 0 );
|
||||
}
|
||||
|
||||
/* allocate a subkey for a given key, and return its index */
|
||||
static struct key *alloc_subkey( struct key *parent, const struct unicode_str *name, timeout_t modif )
|
||||
/* get the wow6432node key if any, grabbing it and releasing the original key */
|
||||
static struct key *grab_wow6432node( struct key *key )
|
||||
{
|
||||
struct key *key;
|
||||
struct key *ret = key->wow6432node;
|
||||
|
||||
if (!(key = alloc_key( name, modif ))) return NULL;
|
||||
if (key_link_name( &key->obj, key->obj.name, &parent->obj )) return key;
|
||||
if (!ret) return key;
|
||||
grab_object( ret );
|
||||
release_object( key );
|
||||
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 )
|
||||
{
|
||||
if (!key->wow6432node) return key;
|
||||
if (!is_wow6432node( name->str, name->len )) return key->wow6432node;
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/* follow a symlink and return the resolved key */
|
||||
static struct key *follow_symlink( struct key *key, int iteration )
|
||||
{
|
||||
struct unicode_str path, token;
|
||||
struct key_value *value;
|
||||
int index;
|
||||
|
||||
if (iteration > 16) return NULL;
|
||||
if (!(key->flags & KEY_SYMLINK)) return key;
|
||||
if (!(value = find_value( key, &symlink_str, &index ))) return NULL;
|
||||
|
||||
path.str = value->data;
|
||||
path.len = (value->len / sizeof(WCHAR)) * sizeof(WCHAR);
|
||||
if (path.len <= sizeof(root_name)) return NULL;
|
||||
if (memicmp_strW( path.str, root_name, sizeof(root_name) )) return NULL;
|
||||
path.str += ARRAY_SIZE( root_name );
|
||||
path.len -= sizeof(root_name);
|
||||
|
||||
key = root_key;
|
||||
token.str = NULL;
|
||||
if (!get_path_token( &path, &token )) return NULL;
|
||||
while (token.len)
|
||||
{
|
||||
if (!(key = find_subkey( key, &token, &index ))) break;
|
||||
if (!(key = follow_symlink( key, iteration + 1 ))) break;
|
||||
get_path_token( &path, &token );
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/* open a key until we find an element that doesn't exist */
|
||||
/* helper for open_key and create_key */
|
||||
static struct key *open_key_prefix( struct key *key, const struct unicode_str *name,
|
||||
unsigned int access, struct unicode_str *token, int *index )
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct key *subkey;
|
||||
if (!(subkey = find_subkey( key, token, index )))
|
||||
{
|
||||
if ((key->flags & KEY_WOWSHARE) && !(access & KEY_WOW64_64KEY))
|
||||
{
|
||||
/* try in the 64-bit parent */
|
||||
key = get_parent( key );
|
||||
subkey = find_subkey( key, token, index );
|
||||
}
|
||||
}
|
||||
if (!subkey) break;
|
||||
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 );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* open a subkey */
|
||||
static struct key *open_key( struct key *key, const struct unicode_str *name, unsigned int access,
|
||||
unsigned int attributes )
|
||||
static struct key *open_key( struct key *parent, const struct unicode_str *name,
|
||||
unsigned int access, unsigned int attributes )
|
||||
{
|
||||
int index;
|
||||
struct unicode_str token;
|
||||
struct key *key;
|
||||
|
||||
if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;
|
||||
|
||||
if (token.len)
|
||||
if (name->len >= 65534)
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
set_error( STATUS_OBJECT_NAME_INVALID );
|
||||
return NULL;
|
||||
}
|
||||
if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
|
||||
if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
|
||||
|
||||
if (parent && (access & KEY_WOW64_32KEY))
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
return NULL;
|
||||
if (parent->wow6432node && !is_wow6432node( name->str, name->len ))
|
||||
parent = parent->wow6432node;
|
||||
}
|
||||
|
||||
if (!(access & KEY_WOW64_64KEY)) attributes |= OBJ_KEY_WOW64;
|
||||
|
||||
if (!(key = open_named_object( &parent->obj, &key_ops, name, attributes ))) return NULL;
|
||||
|
||||
if (!(access & KEY_WOW64_64KEY)) key = grab_wow6432node( key );
|
||||
if (debug_level > 1) dump_operation( key, NULL, "Open" );
|
||||
if (key->flags & KEY_PREDEF) set_error( STATUS_PREDEFINED_HANDLE );
|
||||
grab_object( key );
|
||||
return key;
|
||||
}
|
||||
|
||||
/* 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 access, unsigned int attributes,
|
||||
static struct key *create_key( struct key *parent, const struct unicode_str *name,
|
||||
unsigned int options, unsigned int access, unsigned int attributes,
|
||||
const struct security_descriptor *sd )
|
||||
{
|
||||
int index;
|
||||
struct unicode_str token, next;
|
||||
struct key *key;
|
||||
|
||||
if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;
|
||||
if (options & REG_OPTION_CREATE_LINK) attributes = (attributes & ~OBJ_OPENIF) | OBJ_OPENLINK;
|
||||
|
||||
if (!token.len) /* the key already exists */
|
||||
if (parent && (access & KEY_WOW64_32KEY))
|
||||
{
|
||||
if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
|
||||
if (options & REG_OPTION_CREATE_LINK)
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_COLLISION );
|
||||
return NULL;
|
||||
if (parent->wow6432node && !is_wow6432node( name->str, name->len )) parent = parent->wow6432node;
|
||||
}
|
||||
if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
|
||||
if (!(access & KEY_WOW64_64KEY)) attributes |= OBJ_KEY_WOW64;
|
||||
|
||||
if (!(key = create_key_object( &parent->obj, name, attributes, options, current_time, sd )))
|
||||
return NULL;
|
||||
}
|
||||
if (debug_level > 1) dump_operation( key, NULL, "Open" );
|
||||
|
||||
if (get_error() == STATUS_OBJECT_NAME_EXISTS)
|
||||
{
|
||||
if (key->flags & KEY_PREDEF) set_error( STATUS_PREDEFINED_HANDLE );
|
||||
grab_object( key );
|
||||
set_error( STATUS_OBJECT_NAME_EXISTS );
|
||||
return key;
|
||||
if (!(access & KEY_WOW64_64KEY)) key = grab_wow6432node( key );
|
||||
}
|
||||
|
||||
/* token must be the last path component at this point */
|
||||
next = token;
|
||||
get_path_token( name, &next );
|
||||
if (next.len)
|
||||
else
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((key->flags & KEY_VOLATILE) && !(options & REG_OPTION_VOLATILE))
|
||||
{
|
||||
set_error( STATUS_CHILD_MUST_BE_VOLATILE );
|
||||
return NULL;
|
||||
}
|
||||
make_dirty( key );
|
||||
if (!(key = alloc_subkey( key, &token, current_time ))) return NULL;
|
||||
|
||||
if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK;
|
||||
if (options & REG_OPTION_VOLATILE) key->flags |= KEY_VOLATILE;
|
||||
else key->flags |= KEY_DIRTY;
|
||||
|
||||
if (sd) default_set_sd( &key->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
|
||||
|
||||
if (parent) touch_key( get_parent( key ), REG_NOTIFY_CHANGE_NAME );
|
||||
if (debug_level > 1) dump_operation( key, NULL, "Create" );
|
||||
if (class && class->len)
|
||||
{
|
||||
key->classlen = class->len;
|
||||
free(key->class);
|
||||
if (!(key->class = memdup( class->str, key->classlen ))) key->classlen = 0;
|
||||
}
|
||||
touch_key( get_parent( key ), REG_NOTIFY_CHANGE_NAME );
|
||||
grab_object( key );
|
||||
return key;
|
||||
}
|
||||
|
||||
/* recursively create a subkey (for internal use only) */
|
||||
static struct key *create_key_recursive( struct key *key, const struct unicode_str *name, timeout_t modif )
|
||||
static struct key *create_key_recursive( struct key *root, const struct unicode_str *name, timeout_t modif )
|
||||
{
|
||||
struct key *base;
|
||||
int index;
|
||||
struct unicode_str token;
|
||||
struct key *key, *parent = (struct key *)grab_object( root );
|
||||
struct unicode_str tmp;
|
||||
const WCHAR *str = name->str;
|
||||
data_size_t len = name->len;
|
||||
|
||||
token.str = NULL;
|
||||
if (!get_path_token( name, &token )) return NULL;
|
||||
while (token.len)
|
||||
while (len)
|
||||
{
|
||||
struct key *subkey;
|
||||
if (!(subkey = find_subkey( key, &token, &index ))) break;
|
||||
key = subkey;
|
||||
if (!(key = follow_symlink( key, 0 )))
|
||||
{
|
||||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
return NULL;
|
||||
}
|
||||
get_path_token( name, &token );
|
||||
}
|
||||
tmp.str = str;
|
||||
tmp.len = get_path_element( str, len );
|
||||
key = create_key_object( &parent->obj, &tmp, OBJ_OPENIF, 0, modif, NULL );
|
||||
release_object( parent );
|
||||
if (!key) return NULL;
|
||||
parent = key;
|
||||
|
||||
if (token.len)
|
||||
/* skip trailing \\ and move to the next element */
|
||||
if (tmp.len < len)
|
||||
{
|
||||
if (!(key = alloc_subkey( key, &token, modif ))) return NULL;
|
||||
base = key;
|
||||
for (;;)
|
||||
{
|
||||
get_path_token( name, &token );
|
||||
if (!token.len) break;
|
||||
if (!(key = alloc_subkey( key, &token, modif )))
|
||||
{
|
||||
unlink_named_object( &base->obj );
|
||||
return NULL;
|
||||
tmp.len += sizeof(WCHAR);
|
||||
str += tmp.len / sizeof(WCHAR);
|
||||
len -= tmp.len;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
grab_object( key );
|
||||
return key;
|
||||
return parent;
|
||||
}
|
||||
|
||||
/* query information about a key or a subkey */
|
||||
|
@ -1113,46 +957,44 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke
|
|||
}
|
||||
|
||||
/* rename a key and its values */
|
||||
static int rename_key( struct key *key, const struct unicode_str *new_name )
|
||||
static void rename_key( struct key *key, const struct unicode_str *new_name )
|
||||
{
|
||||
struct unicode_str token, name;
|
||||
struct object_name *new_name_ptr;
|
||||
struct key *subkey, *parent = get_parent( key );
|
||||
data_size_t len;
|
||||
int i, index, cur_index;
|
||||
|
||||
token.str = NULL;
|
||||
|
||||
/* changing to a path is not allowed */
|
||||
if (!new_name->len || !get_path_token( new_name, &token ) || token.len != new_name->len)
|
||||
len = get_path_element( new_name->str, new_name->len );
|
||||
if (!len || len != new_name->len || len > MAX_NAME_LEN * sizeof(WCHAR))
|
||||
{
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for existing subkey with the same name */
|
||||
if (!parent || (subkey = find_subkey( parent, new_name, &index )))
|
||||
{
|
||||
set_error( STATUS_CANNOT_DELETE );
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == parent->wow6432node || is_wow6432node( new_name->str, new_name->len ))
|
||||
{
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(new_name_ptr = mem_alloc( offsetof( struct object_name, name[new_name->len / sizeof(WCHAR)] ))))
|
||||
return -1;
|
||||
return;
|
||||
|
||||
new_name_ptr->obj = &key->obj;
|
||||
new_name_ptr->len = new_name->len;
|
||||
new_name_ptr->parent = &parent->obj;
|
||||
memcpy( new_name_ptr->name, new_name->str, new_name->len );
|
||||
|
||||
name.str = key->obj.name->name;
|
||||
name.len = key->obj.name->len;
|
||||
find_subkey( parent, &name, &cur_index );
|
||||
for (cur_index = 0; cur_index <= parent->last_subkey; cur_index++)
|
||||
if (parent->subkeys[cur_index] == key) break;
|
||||
|
||||
if (cur_index < index && (index - cur_index) > 1)
|
||||
{
|
||||
|
@ -1169,9 +1011,7 @@ static int rename_key( struct key *key, const struct unicode_str *new_name )
|
|||
key->obj.name = new_name_ptr;
|
||||
|
||||
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 */
|
||||
|
@ -1475,13 +1315,6 @@ static struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access )
|
|||
return key;
|
||||
}
|
||||
|
||||
/* get the registry key corresponding to a parent key handle */
|
||||
static inline struct key *get_parent_hkey_obj( obj_handle_t hkey )
|
||||
{
|
||||
if (!hkey) return (struct key *)grab_object( root_key );
|
||||
return get_hkey_obj( hkey, 0 );
|
||||
}
|
||||
|
||||
/* read a line from the input file */
|
||||
static int read_next_line( struct file_load_info *info )
|
||||
{
|
||||
|
@ -1996,6 +1829,7 @@ static void init_supported_machines(void)
|
|||
/* registry initialisation */
|
||||
void init_registry(void)
|
||||
{
|
||||
static const WCHAR REGISTRY[] = {'\\','R','E','G','I','S','T','R','Y'};
|
||||
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 WCHAR classes_i386[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
|
@ -2016,7 +1850,7 @@ void init_registry(void)
|
|||
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
||||
'P','e','r','f','l','i','b','\\',
|
||||
'0','0','9'};
|
||||
static const struct unicode_str root_name = { NULL, 0 };
|
||||
static const struct unicode_str root_name = { REGISTRY, sizeof(REGISTRY) };
|
||||
static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) };
|
||||
static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) };
|
||||
static const struct unicode_str perflib_name = { perflib, sizeof(perflib) };
|
||||
|
@ -2032,9 +1866,9 @@ void init_registry(void)
|
|||
if (fchdir( config_dir_fd ) == -1) fatal_error( "chdir to config dir: %s\n", strerror( errno ));
|
||||
|
||||
/* create the root key */
|
||||
root_key = alloc_key( &root_name, current_time );
|
||||
root_key = create_key_object( NULL, &root_name, OBJ_PERMANENT, 0, current_time, NULL );
|
||||
assert( root_key );
|
||||
make_object_permanent( &root_key->obj );
|
||||
release_object( root_key );
|
||||
|
||||
/* load system.reg into Registry\Machine */
|
||||
|
||||
|
@ -2292,9 +2126,10 @@ static int is_wow64_thread( struct thread *thread )
|
|||
/* create a registry key */
|
||||
DECL_HANDLER(create_key)
|
||||
{
|
||||
struct key *key = NULL, *parent;
|
||||
struct unicode_str name, class;
|
||||
struct key *key, *parent = NULL;
|
||||
unsigned int access = req->access;
|
||||
const WCHAR *class;
|
||||
struct unicode_str name;
|
||||
const struct security_descriptor *sd;
|
||||
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
|
||||
|
||||
|
@ -2302,50 +2137,41 @@ DECL_HANDLER(create_key)
|
|||
|
||||
if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
|
||||
|
||||
class.str = get_req_data_after_objattr( objattr, &class.len );
|
||||
class.len = (class.len / sizeof(WCHAR)) * sizeof(WCHAR);
|
||||
|
||||
if (!objattr->rootdir && name.len >= sizeof(root_name) &&
|
||||
!memicmp_strW( name.str, root_name, sizeof(root_name) ))
|
||||
if (objattr->rootdir)
|
||||
{
|
||||
name.str += ARRAY_SIZE( root_name );
|
||||
name.len -= sizeof(root_name);
|
||||
if (!(parent = get_hkey_obj( objattr->rootdir, 0 ))) return;
|
||||
}
|
||||
|
||||
/* NOTE: no access rights are required from the parent handle to create a key */
|
||||
if ((parent = get_parent_hkey_obj( objattr->rootdir )))
|
||||
if ((key = create_key( parent, &name, req->options, access, objattr->attributes, sd )))
|
||||
{
|
||||
if ((key = create_key( parent, &name, &class, req->options, access,
|
||||
objattr->attributes, sd )))
|
||||
if ((class = get_req_data_after_objattr( objattr, &key->classlen )))
|
||||
{
|
||||
key->classlen = (key->classlen / sizeof(WCHAR)) * sizeof(WCHAR);
|
||||
if (!(key->class = memdup( class, key->classlen ))) key->classlen = 0;
|
||||
}
|
||||
reply->hkey = alloc_handle( current->process, key, access, objattr->attributes );
|
||||
release_object( key );
|
||||
}
|
||||
release_object( parent );
|
||||
}
|
||||
if (parent) release_object( parent );
|
||||
}
|
||||
|
||||
/* open a registry key */
|
||||
DECL_HANDLER(open_key)
|
||||
{
|
||||
struct key *key, *parent;
|
||||
struct unicode_str name;
|
||||
struct key *key, *parent = NULL;
|
||||
unsigned int access = req->access;
|
||||
struct unicode_str name = get_req_unicode_str();
|
||||
|
||||
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 (req->parent && !(parent = get_hkey_obj( req->parent, 0 ))) return;
|
||||
|
||||
if ((key = open_key( parent, &name, access, req->attributes )))
|
||||
{
|
||||
reply->hkey = alloc_handle( current->process, key, access, req->attributes );
|
||||
release_object( key );
|
||||
}
|
||||
release_object( parent );
|
||||
}
|
||||
if (parent) release_object( parent );
|
||||
}
|
||||
|
||||
/* delete a registry key */
|
||||
|
@ -2449,7 +2275,7 @@ DECL_HANDLER(delete_key_value)
|
|||
/* load a registry branch from a file */
|
||||
DECL_HANDLER(load_registry)
|
||||
{
|
||||
struct key *key, *parent;
|
||||
struct key *key, *parent = NULL;
|
||||
struct unicode_str name;
|
||||
const struct security_descriptor *sd;
|
||||
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
|
||||
|
@ -2461,30 +2287,23 @@ DECL_HANDLER(load_registry)
|
|||
set_error( STATUS_PRIVILEGE_NOT_HELD );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!objattr->rootdir && name.len >= sizeof(root_name) &&
|
||||
!memicmp_strW( name.str, root_name, sizeof(root_name) ))
|
||||
if (objattr->rootdir)
|
||||
{
|
||||
name.str += ARRAY_SIZE( root_name );
|
||||
name.len -= sizeof(root_name);
|
||||
if (!(parent = get_hkey_obj( objattr->rootdir, 0 ))) return;
|
||||
}
|
||||
|
||||
if ((parent = get_parent_hkey_obj( objattr->rootdir )))
|
||||
{
|
||||
if ((key = create_key( parent, &name, NULL, 0, KEY_WOW64_64KEY, 0, sd )))
|
||||
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd )))
|
||||
{
|
||||
load_registry( key, req->file );
|
||||
release_object( key );
|
||||
}
|
||||
release_object( parent );
|
||||
}
|
||||
if (parent) release_object( parent );
|
||||
}
|
||||
|
||||
DECL_HANDLER(unload_registry)
|
||||
{
|
||||
struct key *key, *parent;
|
||||
struct unicode_str name;
|
||||
unsigned int access = 0;
|
||||
struct key *key, *parent = NULL;
|
||||
struct unicode_str name = get_req_unicode_str();
|
||||
|
||||
if (!thread_single_check_privilege( current, SeRestorePrivilege ))
|
||||
{
|
||||
|
@ -2492,12 +2311,9 @@ DECL_HANDLER(unload_registry)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
|
||||
if (req->parent && !(parent = get_hkey_obj( req->parent, 0 ))) return;
|
||||
|
||||
if ((parent = get_parent_hkey_obj( req->parent )))
|
||||
{
|
||||
get_req_path( &name, !req->parent );
|
||||
if ((key = open_key( parent, &name, access, req->attributes )))
|
||||
if ((key = open_key( parent, &name, KEY_WOW64_64KEY, req->attributes )))
|
||||
{
|
||||
if (key->obj.handle_count)
|
||||
set_error( STATUS_CANNOT_DELETE );
|
||||
|
@ -2505,8 +2321,7 @@ DECL_HANDLER(unload_registry)
|
|||
delete_key( key, 1 ); /* FIXME */
|
||||
release_object( key );
|
||||
}
|
||||
release_object( parent );
|
||||
}
|
||||
if (parent) release_object( parent );
|
||||
}
|
||||
|
||||
/* save a registry branch to a file */
|
||||
|
@ -2577,14 +2392,12 @@ DECL_HANDLER(set_registry_notification)
|
|||
/* rename a registry key */
|
||||
DECL_HANDLER(rename_key)
|
||||
{
|
||||
struct unicode_str name;
|
||||
struct unicode_str name = get_req_unicode_str();
|
||||
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 );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue