Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
b139b935
Commit
b139b935
authored
Feb 15, 2010
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Implement registry symlinks.
parent
2ec945d4
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
97 additions
and
47 deletions
+97
-47
reg.c
dlls/ntdll/tests/reg.c
+0
-30
registry.c
server/registry.c
+97
-17
No files found.
dlls/ntdll/tests/reg.c
View file @
b139b935
...
...
@@ -638,22 +638,18 @@ static void test_symlinks(void)
/* REG_SZ is not allowed */
status
=
pNtSetValueKey
(
link
,
&
symlink_str
,
0
,
REG_SZ
,
target
,
target_len
);
todo_wine
ok
(
status
==
STATUS_ACCESS_DENIED
,
"NtSetValueKey wrong status 0x%08x
\n
"
,
status
);
status
=
pNtSetValueKey
(
link
,
&
symlink_str
,
0
,
REG_LINK
,
target
,
target_len
-
sizeof
(
WCHAR
)
);
ok
(
status
==
STATUS_SUCCESS
,
"NtSetValueKey failed: 0x%08x
\n
"
,
status
);
/* other values are not allowed */
status
=
pNtSetValueKey
(
link
,
&
link_str
,
0
,
REG_LINK
,
target
,
target_len
-
sizeof
(
WCHAR
)
);
todo_wine
ok
(
status
==
STATUS_ACCESS_DENIED
,
"NtSetValueKey wrong status 0x%08x
\n
"
,
status
);
/* try opening the target through the link */
attr
.
ObjectName
=
&
link_str
;
status
=
pNtOpenKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
);
todo_wine
ok
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
,
"NtOpenKey wrong status 0x%08x
\n
"
,
status
);
if
(
!
status
)
pNtClose
(
key
);
attr
.
ObjectName
=
&
target_str
;
status
=
pNtCreateKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
0
,
0
,
0
);
...
...
@@ -670,14 +666,10 @@ static void test_symlinks(void)
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
value_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
sizeof
(
DWORD
),
"wrong len %u
\n
"
,
len
);
}
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
ok
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
/* REG_LINK can be created in non-link keys */
...
...
@@ -699,11 +691,8 @@ static void test_symlinks(void)
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
value_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
sizeof
(
DWORD
),
"wrong len %u
\n
"
,
len
);
}
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
ok
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
...
...
@@ -719,24 +708,18 @@ static void test_symlinks(void)
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
target_len
-
sizeof
(
WCHAR
),
"wrong len %u
\n
"
,
len
);
}
pNtClose
(
key
);
status
=
pNtCreateKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
0
,
0
,
0
);
ok
(
status
==
STATUS_SUCCESS
,
"NtCreateKey failed: 0x%08x
\n
"
,
status
);
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
target_len
-
sizeof
(
WCHAR
),
"wrong len %u
\n
"
,
len
);
}
pNtClose
(
key
);
/* reopen the link from itself */
...
...
@@ -748,24 +731,18 @@ static void test_symlinks(void)
ok
(
status
==
STATUS_SUCCESS
,
"NtOpenKey failed: 0x%08x
\n
"
,
status
);
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
target_len
-
sizeof
(
WCHAR
),
"wrong len %u
\n
"
,
len
);
}
pNtClose
(
key
);
status
=
pNtCreateKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
0
,
0
,
0
);
ok
(
status
==
STATUS_SUCCESS
,
"NtCreateKey failed: 0x%08x
\n
"
,
status
);
len
=
sizeof
(
buffer
);
status
=
pNtQueryValueKey
(
key
,
&
symlink_str
,
KeyValuePartialInformation
,
info
,
len
,
&
len
);
todo_wine
{
ok
(
status
==
STATUS_SUCCESS
,
"NtQueryValueKey failed: 0x%08x
\n
"
,
status
);
ok
(
len
==
FIELD_OFFSET
(
KEY_VALUE_PARTIAL_INFORMATION
,
Data
)
+
target_len
-
sizeof
(
WCHAR
),
"wrong len %u
\n
"
,
len
);
}
pNtClose
(
key
);
if
(
0
)
/* crashes the Windows kernel in most versions */
...
...
@@ -793,9 +770,7 @@ static void test_symlinks(void)
attr
.
Attributes
=
0
;
attr
.
ObjectName
=
&
link_str
;
status
=
pNtOpenKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
);
todo_wine
ok
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
,
"NtOpenKey wrong status 0x%08x
\n
"
,
status
);
if
(
!
status
)
pNtClose
(
key
);
/* relative symlink, works only on win2k */
status
=
pNtSetValueKey
(
link
,
&
symlink_str
,
0
,
REG_LINK
,
targetW
+
1
,
sizeof
(
targetW
)
-
2
*
sizeof
(
WCHAR
)
);
...
...
@@ -804,12 +779,9 @@ static void test_symlinks(void)
status
=
pNtOpenKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
);
ok
(
status
==
STATUS_SUCCESS
||
status
==
STATUS_OBJECT_NAME_NOT_FOUND
,
"NtOpenKey wrong status 0x%08x
\n
"
,
status
);
if
(
!
status
)
pNtClose
(
key
);
status
=
pNtCreateKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
0
,
REG_OPTION_CREATE_LINK
,
0
);
todo_wine
ok
(
status
==
STATUS_OBJECT_NAME_COLLISION
,
"NtCreateKey failed: 0x%08x
\n
"
,
status
);
if
(
!
status
)
pNtClose
(
key
);
status
=
pNtDeleteKey
(
link
);
ok
(
status
==
STATUS_SUCCESS
,
"NtDeleteKey failed: 0x%08x
\n
"
,
status
);
...
...
@@ -832,10 +804,8 @@ static void test_symlinks(void)
ok
(
status
==
STATUS_SUCCESS
,
"NtSetValueKey failed: 0x%08x
\n
"
,
status
);
status
=
pNtOpenKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
);
todo_wine
ok
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
||
status
==
STATUS_NAME_TOO_LONG
,
"NtOpenKey failed: 0x%08x
\n
"
,
status
);
if
(
!
status
)
pNtClose
(
key
);
attr
.
Attributes
=
OBJ_OPENLINK
;
status
=
pNtOpenKey
(
&
key
,
KEY_ALL_ACCESS
,
&
attr
);
...
...
server/registry.c
View file @
b139b935
...
...
@@ -83,6 +83,7 @@ struct key
#define KEY_VOLATILE 0x0001
/* key is volatile (not saved to disk) */
#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 */
/* a key value */
struct
key_value
...
...
@@ -107,7 +108,12 @@ static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89)
static
const
timeout_t
save_period
=
30
*
-
TICKS_PER_SEC
;
/* delay between periodic saves */
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
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
)
};
static
void
set_periodic_save_timer
(
void
);
static
struct
key_value
*
find_value
(
const
struct
key
*
key
,
const
struct
unicode_str
*
name
,
int
*
index
);
/* information about where to save a registry branch */
struct
save_branch_info
...
...
@@ -351,8 +357,6 @@ 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
)
{
static
const
WCHAR
root_name
[]
=
{
'\\'
,
'R'
,
'e'
,
'g'
,
'i'
,
's'
,
't'
,
'r'
,
'y'
,
'\\'
};
str
->
str
=
get_req_data
();
str
->
len
=
(
get_req_data_size
()
/
sizeof
(
WCHAR
))
*
sizeof
(
WCHAR
);
...
...
@@ -576,8 +580,38 @@ static struct key *find_subkey( const struct key *key, const struct unicode_str
return
NULL
;
}
/* 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
(
memicmpW
(
path
.
str
,
root_name
,
sizeof
(
root_name
)
/
sizeof
(
WCHAR
)
))
return
NULL
;
path
.
str
+=
sizeof
(
root_name
)
/
sizeof
(
WCHAR
);
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 subkey */
static
struct
key
*
open_key
(
struct
key
*
key
,
const
struct
unicode_str
*
name
)
static
struct
key
*
open_key
(
struct
key
*
key
,
const
struct
unicode_str
*
name
,
unsigned
int
attributes
)
{
int
index
;
struct
unicode_str
token
;
...
...
@@ -589,19 +623,31 @@ static struct key *open_key( struct key *key, const struct unicode_str *name )
if
(
!
(
key
=
find_subkey
(
key
,
&
token
,
&
index
)))
{
set_error
(
STATUS_OBJECT_NAME_NOT_FOUND
);
break
;
return
NULL
;
}
get_path_token
(
name
,
&
token
);
if
(
!
token
.
len
)
break
;
if
(
!
(
key
=
follow_symlink
(
key
,
0
)))
{
set_error
(
STATUS_OBJECT_NAME_NOT_FOUND
);
return
NULL
;
}
}
if
(
!
(
attributes
&
OBJ_OPENLINK
)
&&
!
(
key
=
follow_symlink
(
key
,
0
)))
{
set_error
(
STATUS_OBJECT_NAME_NOT_FOUND
);
return
NULL
;
}
if
(
debug_level
>
1
)
dump_operation
(
key
,
NULL
,
"Open"
);
if
(
key
)
grab_object
(
key
);
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
,
int
flags
,
timeout_t
modif
,
int
*
created
)
const
struct
unicode_str
*
class
,
int
flags
,
unsigned
int
options
,
unsigned
int
attributes
,
timeout_t
modif
,
int
*
created
)
{
struct
key
*
base
;
int
index
;
...
...
@@ -622,12 +668,35 @@ static struct key *create_key( struct key *key, const struct unicode_str *name,
if
(
!
(
subkey
=
find_subkey
(
key
,
&
token
,
&
index
)))
break
;
key
=
subkey
;
get_path_token
(
name
,
&
token
);
if
(
!
token
.
len
)
break
;
if
(
!
(
subkey
=
follow_symlink
(
subkey
,
0
)))
{
set_error
(
STATUS_OBJECT_NAME_NOT_FOUND
);
return
NULL
;
}
}
/* create the remaining part */
if
(
!
token
.
len
)
goto
done
;
if
(
!
(
flags
&
KEY_VOLATILE
)
&&
(
key
->
flags
&
KEY_VOLATILE
))
if
(
!
token
.
len
)
{
if
(
options
&
REG_OPTION_CREATE_LINK
)
{
set_error
(
STATUS_OBJECT_NAME_COLLISION
);
return
NULL
;
}
if
(
!
(
attributes
&
OBJ_OPENLINK
)
&&
!
(
key
=
follow_symlink
(
key
,
0
)))
{
set_error
(
STATUS_OBJECT_NAME_NOT_FOUND
);
return
NULL
;
}
goto
done
;
}
if
(
options
&
REG_OPTION_VOLATILE
)
{
flags
=
(
flags
&
~
KEY_DIRTY
)
|
KEY_VOLATILE
;
}
else
if
(
key
->
flags
&
KEY_VOLATILE
)
{
set_error
(
STATUS_CHILD_MUST_BE_VOLATILE
);
return
NULL
;
...
...
@@ -648,6 +717,8 @@ static struct key *create_key( struct key *key, const struct unicode_str *name,
return
NULL
;
}
}
/* FIXME: no saving of symlinks yet */
if
(
options
&
REG_OPTION_CREATE_LINK
)
key
->
flags
|=
KEY_SYMLINK
|
KEY_VOLATILE
;
done:
if
(
debug_level
>
1
)
dump_operation
(
key
,
NULL
,
"Create"
);
...
...
@@ -879,6 +950,16 @@ static void set_value( struct key *key, const struct unicode_str *name,
}
}
if
(
key
->
flags
&
KEY_SYMLINK
)
{
if
(
type
!=
REG_LINK
||
name
->
len
!=
symlink_str
.
len
||
memicmpW
(
name
->
str
,
symlink_str
.
str
,
name
->
len
/
sizeof
(
WCHAR
)
))
{
set_error
(
STATUS_ACCESS_DENIED
);
return
;
}
}
if
(
len
&&
!
(
ptr
=
memdup
(
data
,
len
)))
return
;
if
(
!
value
)
...
...
@@ -1140,7 +1221,7 @@ static struct key *load_key( struct key *base, const char *buffer, int flags,
}
name
.
str
=
p
;
name
.
len
=
len
-
(
p
-
info
->
tmp
+
1
)
*
sizeof
(
WCHAR
);
return
create_key
(
base
,
&
name
,
NULL
,
flags
,
modif
,
&
res
);
return
create_key
(
base
,
&
name
,
NULL
,
flags
,
0
,
0
,
modif
,
&
res
);
}
/* parse a comma-separated list of hex digits */
...
...
@@ -1448,7 +1529,7 @@ void init_registry(void)
/* load system.reg into Registry\Machine */
if
(
!
(
key
=
create_key
(
root_key
,
&
HKLM_name
,
NULL
,
0
,
current_time
,
&
dummy
)))
if
(
!
(
key
=
create_key
(
root_key
,
&
HKLM_name
,
NULL
,
0
,
0
,
0
,
current_time
,
&
dummy
)))
fatal_error
(
"could not create Machine registry key
\n
"
);
load_init_registry_from_file
(
"system.reg"
,
key
);
...
...
@@ -1456,7 +1537,7 @@ void init_registry(void)
/* load userdef.reg into Registry\User\.Default */
if
(
!
(
key
=
create_key
(
root_key
,
&
HKU_name
,
NULL
,
0
,
current_time
,
&
dummy
)))
if
(
!
(
key
=
create_key
(
root_key
,
&
HKU_name
,
NULL
,
0
,
0
,
0
,
current_time
,
&
dummy
)))
fatal_error
(
"could not create User
\\
.Default registry key
\n
"
);
load_init_registry_from_file
(
"userdef.reg"
,
key
);
...
...
@@ -1467,7 +1548,7 @@ void init_registry(void)
/* 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_str
);
if
(
!
current_user_path
||
!
(
key
=
create_key
(
root_key
,
&
current_user_str
,
NULL
,
0
,
current_time
,
&
dummy
)))
!
(
key
=
create_key
(
root_key
,
&
current_user_str
,
NULL
,
0
,
0
,
0
,
current_time
,
&
dummy
)))
fatal_error
(
"could not create HKEY_CURRENT_USER registry key
\n
"
);
free
(
current_user_path
);
load_init_registry_from_file
(
"user.reg"
,
key
);
...
...
@@ -1660,9 +1741,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
)))
{
int
flags
=
(
req
->
options
&
REG_OPTION_VOLATILE
)
?
KEY_VOLATILE
:
KEY_DIRTY
;
if
((
key
=
create_key
(
parent
,
&
name
,
&
class
,
flags
,
current_time
,
&
reply
->
created
)))
if
((
key
=
create_key
(
parent
,
&
name
,
&
class
,
KEY_DIRTY
,
req
->
options
,
req
->
attributes
,
current_time
,
&
reply
->
created
)))
{
reply
->
hkey
=
alloc_handle
(
current
->
process
,
key
,
access
,
req
->
attributes
);
release_object
(
key
);
...
...
@@ -1683,7 +1763,7 @@ DECL_HANDLER(open_key)
if
((
parent
=
get_parent_hkey_obj
(
req
->
parent
)))
{
get_req_path
(
&
name
,
!
req
->
parent
);
if
((
key
=
open_key
(
parent
,
&
name
)))
if
((
key
=
open_key
(
parent
,
&
name
,
req
->
attributes
)))
{
reply
->
hkey
=
alloc_handle
(
current
->
process
,
key
,
access
,
req
->
attributes
);
release_object
(
key
);
...
...
@@ -1817,7 +1897,7 @@ DECL_HANDLER(load_registry)
{
int
dummy
;
get_req_path
(
&
name
,
!
req
->
hkey
);
if
((
key
=
create_key
(
parent
,
&
name
,
NULL
,
KEY_DIRTY
,
current_time
,
&
dummy
)))
if
((
key
=
create_key
(
parent
,
&
name
,
NULL
,
KEY_DIRTY
,
0
,
0
,
current_time
,
&
dummy
)))
{
load_registry
(
key
,
req
->
file
);
release_object
(
key
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment