Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
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-cw
Commits
c377cc86
Commit
c377cc86
authored
Mar 11, 2005
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Get rid of the Windows registry loading on startup, this needs to be
done differently.
parent
e95de008
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
6 additions
and
1500 deletions
+6
-1500
config
documentation/samples/config
+0
-2
registry.c
misc/registry.c
+6
-1498
No files found.
documentation/samples/config
View file @
c377cc86
...
...
@@ -146,8 +146,6 @@ WINE REGISTRY Version 2
;"GlobalRegistryDir" = "/etc";
; Global registries (stored in /etc)
"LoadGlobalRegistryFiles" = "Y"
; Load Windows registries from the Windows directory
"LoadWindowsRegistryFiles" = "Y"
; Registry periodic save timeout in seconds
; "PeriodicSave" = "600"
; Save only modified keys
...
...
misc/registry.c
View file @
c377cc86
...
...
@@ -23,10 +23,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTES
* When changing this file, please re-run the regtest program to ensure
* the conditions are handled properly.
*
* TODO
* Security access
* Option handling
...
...
@@ -47,9 +43,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
...
...
@@ -66,7 +59,6 @@
#include "winioctl.h"
#include "ntddscsi.h"
#include "wine/winbase16.h"
#include "wine/library.h"
#include "wine/server.h"
#include "wine/unicode.h"
...
...
@@ -80,1009 +72,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(reg);
#define MAX_PATHNAME_LEN 1024
static
const
WCHAR
ClassesRootW
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'o'
,
'f'
,
't'
,
'w'
,
'a'
,
'r'
,
'e'
,
'\\'
,
'C'
,
'l'
,
'a'
,
's'
,
's'
,
'e'
,
's'
,
0
};
#define IS_OPTION_FALSE(ch) \
((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
/* _xmalloc [Internal] */
static
void
*
_xmalloc
(
size_t
size
)
{
void
*
res
;
res
=
malloc
(
size
?
size
:
1
);
if
(
res
==
NULL
)
{
WARN
(
"Virtual memory exhausted.
\n
"
);
exit
(
1
);
}
return
res
;
}
/* _xstrdup [Internal] */
static
LPSTR
_xstrdup
(
LPCSTR
str
)
{
LPSTR
ret
;
size_t
len
=
strlen
(
str
)
+
1
;
if
(
!
str
)
return
NULL
;
ret
=
_xmalloc
(
len
);
memcpy
(
ret
,
str
,
len
);
return
ret
;
}
/* convert ansi string to unicode [Internal] */
static
LPWSTR
_strdupnAtoW
(
LPCSTR
strA
,
size_t
lenA
)
{
LPWSTR
ret
;
DWORD
len
;
if
(
!
strA
)
return
NULL
;
if
(
RtlMultiByteToUnicodeSize
(
&
len
,
strA
,
lenA
)
!=
STATUS_SUCCESS
)
return
NULL
;
ret
=
_xmalloc
(
len
+
sizeof
(
WCHAR
));
RtlMultiByteToUnicodeN
(
ret
,
len
,
NULL
,
strA
,
lenA
);
ret
[
len
/
sizeof
(
WCHAR
)]
=
0
;
return
ret
;
}
/* dump a Unicode string with proper escaping [Internal] */
/* FIXME: this code duplicates server/unicode.c */
static
int
_dump_strW
(
const
WCHAR
*
str
,
size_t
len
,
FILE
*
f
,
const
char
escape
[
2
])
{
static
const
char
escapes
[
32
]
=
".......abtnvfr.............e...."
;
char
buffer
[
256
];
LPSTR
pos
=
buffer
;
int
count
=
0
;
for
(;
len
;
str
++
,
len
--
)
{
if
(
pos
>
buffer
+
sizeof
(
buffer
)
-
8
)
{
fwrite
(
buffer
,
pos
-
buffer
,
1
,
f
);
count
+=
pos
-
buffer
;
pos
=
buffer
;
}
if
(
*
str
>
127
)
/* hex escape */
{
if
(
len
>
1
&&
str
[
1
]
<
128
&&
isxdigit
((
char
)
str
[
1
]))
pos
+=
sprintf
(
pos
,
"
\\
x%04x"
,
*
str
);
else
pos
+=
sprintf
(
pos
,
"
\\
x%x"
,
*
str
);
continue
;
}
if
(
*
str
<
32
)
/* octal or C escape */
{
if
(
!*
str
&&
len
==
1
)
continue
;
/* do not output terminating NULL */
if
(
escapes
[
*
str
]
!=
'.'
)
pos
+=
sprintf
(
pos
,
"
\\
%c"
,
escapes
[
*
str
]
);
else
if
(
len
>
1
&&
str
[
1
]
>=
'0'
&&
str
[
1
]
<=
'7'
)
pos
+=
sprintf
(
pos
,
"
\\
%03o"
,
*
str
);
else
pos
+=
sprintf
(
pos
,
"
\\
%o"
,
*
str
);
continue
;
}
if
(
*
str
==
'\\'
||
*
str
==
escape
[
0
]
||
*
str
==
escape
[
1
])
*
pos
++
=
'\\'
;
*
pos
++
=
*
str
;
}
fwrite
(
buffer
,
pos
-
buffer
,
1
,
f
);
count
+=
pos
-
buffer
;
return
count
;
}
/* convert ansi string to unicode and dump with proper escaping [Internal] */
static
int
_dump_strAtoW
(
LPCSTR
strA
,
size_t
len
,
FILE
*
f
,
const
char
escape
[
2
])
{
WCHAR
*
strW
;
int
ret
;
if
(
strA
==
NULL
)
return
0
;
strW
=
_strdupnAtoW
(
strA
,
len
);
ret
=
_dump_strW
(
strW
,
len
,
f
,
escape
);
free
(
strW
);
return
ret
;
}
/* a key value */
/* FIXME: this code duplicates server/registry.c */
struct
key_value
{
WCHAR
*
nameW
;
/* value name */
int
type
;
/* value type */
size_t
len
;
/* value data length in bytes */
void
*
data
;
/* pointer to value data */
};
/* dump a value to a text file */
/* FIXME: this code duplicates server/registry.c */
static
void
_dump_value
(
struct
key_value
*
value
,
FILE
*
f
)
{
int
i
,
count
;
if
(
value
->
nameW
[
0
])
{
fputc
(
'\"'
,
f
);
count
=
1
+
_dump_strW
(
value
->
nameW
,
strlenW
(
value
->
nameW
),
f
,
"
\"\"
"
);
count
+=
fprintf
(
f
,
"
\"
="
);
}
else
count
=
fprintf
(
f
,
"@="
);
switch
(
value
->
type
)
{
case
REG_SZ
:
case
REG_EXPAND_SZ
:
case
REG_MULTI_SZ
:
if
(
value
->
type
!=
REG_SZ
)
fprintf
(
f
,
"str(%d):"
,
value
->
type
);
fputc
(
'\"'
,
f
);
if
(
value
->
data
)
_dump_strW
(
value
->
data
,
value
->
len
/
sizeof
(
WCHAR
),
f
,
"
\"\"
"
);
fputc
(
'\"'
,
f
);
break
;
case
REG_DWORD
:
if
(
value
->
len
==
sizeof
(
DWORD
))
{
DWORD
dw
;
memcpy
(
&
dw
,
value
->
data
,
sizeof
(
DWORD
)
);
fprintf
(
f
,
"dword:%08lx"
,
dw
);
break
;
}
/* else fall through */
default:
if
(
value
->
type
==
REG_BINARY
)
count
+=
fprintf
(
f
,
"hex:"
);
else
count
+=
fprintf
(
f
,
"hex(%x):"
,
value
->
type
);
for
(
i
=
0
;
i
<
value
->
len
;
i
++
)
{
count
+=
fprintf
(
f
,
"%02x"
,
*
((
unsigned
char
*
)
value
->
data
+
i
)
);
if
(
i
<
value
->
len
-
1
)
{
fputc
(
','
,
f
);
if
(
++
count
>
76
)
{
fprintf
(
f
,
"
\\\n
"
);
count
=
2
;
}
}
}
break
;
}
fputc
(
'\n'
,
f
);
}
/******************************************************************/
/* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjwall, tor@sn.no */
/*
reghack - windows 3.11 registry data format demo program.
The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
a combined hash table and tree description, and finally a text table.
The header is obvious from the struct header. The taboff1 and taboff2
fields are always 0x20, and their usage is unknown.
The 8-byte entry table has various entry types.
tabent[0] is a root index. The second word has the index of the root of
the directory.
tabent[1..hashsize] is a hash table. The first word in the hash entry is
the index of the key/value that has that hash. Data with the same
hash value are on a circular list. The other three words in the
hash entry are always zero.
tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
entry: dirent and keyent/valent. They are identified by context.
tabent[freeidx] is the first free entry. The first word in a free entry
is the index of the next free entry. The last has 0 as a link.
The other three words in the free list are probably irrelevant.
Entries in text table are preceded by a word at offset-2. This word
has the value (2*index)+1, where index is the referring keyent/valent
entry in the table. I have no suggestion for the 2* and the +1.
Following the word, there are N bytes of data, as per the keyent/valent
entry length. The offset of the keyent/valent entry is from the start
of the text table to the first data byte.
This information is not available from Microsoft. The data format is
deduced from the reg.dat file by me. Mistakes may
have been made. I claim no rights and give no guarantees for this program.
Tor Sjwall, tor@sn.no
*/
/* reg.dat header format */
struct
_w31_header
{
char
cookie
[
8
];
/* 'SHCC3.10' */
unsigned
long
taboff1
;
/* offset of hash table (??) = 0x20 */
unsigned
long
taboff2
;
/* offset of index table (??) = 0x20 */
unsigned
long
tabcnt
;
/* number of entries in index table */
unsigned
long
textoff
;
/* offset of text part */
unsigned
long
textsize
;
/* byte size of text part */
unsigned
short
hashsize
;
/* hash size */
unsigned
short
freeidx
;
/* free index */
};
/* generic format of table entries */
struct
_w31_tabent
{
unsigned
short
w0
,
w1
,
w2
,
w3
;
};
/* directory tabent: */
struct
_w31_dirent
{
unsigned
short
sibling_idx
;
/* table index of sibling dirent */
unsigned
short
child_idx
;
/* table index of child dirent */
unsigned
short
key_idx
;
/* table index of key keyent */
unsigned
short
value_idx
;
/* table index of value valent */
};
/* key tabent: */
struct
_w31_keyent
{
unsigned
short
hash_idx
;
/* hash chain index for string */
unsigned
short
refcnt
;
/* reference count */
unsigned
short
length
;
/* length of string */
unsigned
short
string_off
;
/* offset of string in text table */
};
/* value tabent: */
struct
_w31_valent
{
unsigned
short
hash_idx
;
/* hash chain index for string */
unsigned
short
refcnt
;
/* reference count */
unsigned
short
length
;
/* length of string */
unsigned
short
string_off
;
/* offset of string in text table */
};
/* recursive helper function to display a directory tree [Internal] */
static
void
_w31_dumptree
(
unsigned
short
idx
,
char
*
txt
,
struct
_w31_tabent
*
tab
,
struct
_w31_header
*
head
,
HKEY
hkey
,
ULONG
lastmodified
,
int
level
)
{
static
const
WCHAR
classesW
[]
=
{
'.'
,
'c'
,
'l'
,
'a'
,
's'
,
's'
,
'e'
,
's'
,
0
};
struct
_w31_dirent
*
dir
;
struct
_w31_keyent
*
key
;
struct
_w31_valent
*
val
;
HKEY
subkey
=
0
;
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
,
valueW
;
static
WCHAR
tail
[
400
];
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
hkey
;
attr
.
ObjectName
=
&
nameW
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
RtlInitUnicodeString
(
&
valueW
,
NULL
);
while
(
idx
!=
0
)
{
dir
=
(
struct
_w31_dirent
*
)
&
tab
[
idx
];
if
(
dir
->
key_idx
)
{
DWORD
len
;
key
=
(
struct
_w31_keyent
*
)
&
tab
[
dir
->
key_idx
];
RtlMultiByteToUnicodeN
(
tail
,
sizeof
(
tail
)
-
sizeof
(
WCHAR
),
&
len
,
&
txt
[
key
->
string_off
],
key
->
length
);
tail
[
len
/
sizeof
(
WCHAR
)]
=
0
;
/* all toplevel entries AND the entries in the
* toplevel subdirectory belong to \SOFTWARE\Classes
*/
if
(
!
level
&&
!
strcmpW
(
tail
,
classesW
))
{
_w31_dumptree
(
dir
->
child_idx
,
txt
,
tab
,
head
,
hkey
,
lastmodified
,
level
+
1
);
idx
=
dir
->
sibling_idx
;
continue
;
}
if
(
subkey
)
NtClose
(
subkey
);
RtlInitUnicodeString
(
&
nameW
,
tail
);
if
(
NtCreateKey
(
&
subkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
subkey
=
0
;
/* only add if leaf node or valued node */
if
(
dir
->
value_idx
!=
0
||
dir
->
child_idx
==
0
)
{
if
(
dir
->
value_idx
)
{
DWORD
len
;
val
=
(
struct
_w31_valent
*
)
&
tab
[
dir
->
value_idx
];
RtlMultiByteToUnicodeN
(
tail
,
sizeof
(
tail
)
-
sizeof
(
WCHAR
),
&
len
,
&
txt
[
val
->
string_off
],
val
->
length
);
tail
[
len
/
sizeof
(
WCHAR
)]
=
0
;
NtSetValueKey
(
subkey
,
&
valueW
,
0
,
REG_SZ
,
tail
,
len
+
sizeof
(
WCHAR
)
);
}
}
}
else
TRACE
(
"strange: no directory key name, idx=%04x
\n
"
,
idx
);
_w31_dumptree
(
dir
->
child_idx
,
txt
,
tab
,
head
,
subkey
,
lastmodified
,
level
+
1
);
idx
=
dir
->
sibling_idx
;
}
if
(
subkey
)
NtClose
(
subkey
);
}
/******************************************************************************
* _w31_loadreg [Internal]
*/
static
void
_w31_loadreg
(
const
WCHAR
*
path
)
{
HANDLE
hf
;
HKEY
root
;
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
;
struct
_w31_header
head
;
struct
_w31_tabent
*
tab
=
NULL
;
char
*
txt
=
NULL
;
unsigned
int
len
;
ULONG
lastmodified
;
NTSTATUS
status
;
IO_STATUS_BLOCK
iosb
;
FILE_POSITION_INFORMATION
fpi
;
FILE_BASIC_INFORMATION
fbi
;
TRACE
(
"(void)
\n
"
);
hf
=
CreateFileW
(
path
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
0
,
0
);
if
(
hf
==
INVALID_HANDLE_VALUE
)
return
;
/* read & dump header */
if
(
NtReadFile
(
hf
,
0
,
NULL
,
NULL
,
&
iosb
,
&
head
,
sizeof
(
head
),
NULL
,
NULL
)
!=
STATUS_SUCCESS
||
iosb
.
Information
!=
sizeof
(
head
))
{
ERR
(
"reg.dat is too short.
\n
"
);
goto
done
;
}
if
(
memcmp
(
head
.
cookie
,
"SHCC3.10"
,
sizeof
(
head
.
cookie
))
!=
0
)
{
ERR
(
"reg.dat has bad signature.
\n
"
);
goto
done
;
}
len
=
head
.
tabcnt
*
sizeof
(
struct
_w31_tabent
);
/* read and dump index table */
tab
=
_xmalloc
(
len
);
if
(
NtReadFile
(
hf
,
0
,
NULL
,
NULL
,
&
iosb
,
tab
,
len
,
NULL
,
NULL
)
!=
STATUS_SUCCESS
||
iosb
.
Information
!=
len
)
{
ERR
(
"couldn't read index table (%d bytes).
\n
"
,
len
);
goto
done
;
}
/* read text */
txt
=
_xmalloc
(
head
.
textsize
);
fpi
.
CurrentByteOffset
.
u
.
LowPart
=
head
.
textoff
;
fpi
.
CurrentByteOffset
.
u
.
HighPart
=
0
;
if
(
NtSetInformationFile
(
hf
,
&
iosb
,
&
fpi
,
sizeof
(
fpi
),
FilePositionInformation
)
!=
STATUS_SUCCESS
)
{
ERR
(
"couldn't seek to textblock.
\n
"
);
goto
done
;
}
status
=
NtReadFile
(
hf
,
0
,
NULL
,
NULL
,
&
iosb
,
txt
,
head
.
textsize
,
NULL
,
NULL
);
if
(
!
(
status
==
STATUS_SUCCESS
||
status
==
STATUS_END_OF_FILE
)
||
iosb
.
Information
!=
head
.
textsize
)
{
ERR
(
"textblock too short (%d instead of %ld).
\n
"
,
len
,
head
.
textsize
);
goto
done
;
}
if
(
NtQueryInformationFile
(
hf
,
&
iosb
,
&
fbi
,
sizeof
(
fbi
),
FileBasicInformation
)
!=
STATUS_SUCCESS
)
{
ERR
(
"Couldn't get basic information.
\n
"
);
goto
done
;
}
RtlTimeToSecondsSince1970
(
&
fbi
.
LastWriteTime
,
&
lastmodified
);
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
ObjectName
=
&
nameW
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
RtlInitUnicodeString
(
&
nameW
,
ClassesRootW
);
if
(
!
NtCreateKey
(
&
root
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
{
_w31_dumptree
(
tab
[
0
].
w1
,
txt
,
tab
,
&
head
,
root
,
lastmodified
,
0
);
NtClose
(
root
);
}
done:
if
(
tab
)
free
(
tab
);
if
(
txt
)
free
(
txt
);
NtClose
(
hf
);
return
;
}
/***********************************************************************************/
/* windows 95 registry loader */
/***********************************************************************************/
/* SECTION 1: main header
*
* once at offset 0
*/
#define W95_REG_CREG_ID 0x47455243
typedef
struct
{
DWORD
id
;
/* "CREG" = W95_REG_CREG_ID */
DWORD
version
;
/* ???? 0x00010000 */
DWORD
rgdb_off
;
/* 0x08 Offset of 1st RGDB-block */
DWORD
uk2
;
/* 0x0c */
WORD
rgdb_num
;
/* 0x10 # of RGDB-blocks */
WORD
uk3
;
DWORD
uk
[
3
];
/* rgkn */
}
_w95creg
;
/* SECTION 2: Directory information (tree structure)
*
* once on offset 0x20
*
* structure: [rgkn][dke]* (repeat till last_dke is reached)
*/
#define W95_REG_RGKN_ID 0x4e4b4752
typedef
struct
{
DWORD
id
;
/*"RGKN" = W95_REG_RGKN_ID */
DWORD
size
;
/* Size of the RGKN-block */
DWORD
root_off
;
/* Rel. Offset of the root-record */
DWORD
last_dke
;
/* Offset to last DKE ? */
DWORD
uk
[
4
];
}
_w95rgkn
;
/* Disk Key Entry Structure
*
* the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
* hive itself. It looks the same like other keys. Even the ID-number can
* be any value.
*
* The "hash"-value is a value representing the key's name. Windows will not
* search for the name, but for a matching hash-value. if it finds one, it
* will compare the actual string info, otherwise continue with the next key.
* To calculate the hash initialize a D-Word with 0 and add all ASCII-values
* of the string which are smaller than 0x80 (128) to this D-Word.
*
* If you want to modify key names, also modify the hash-values, since they
* cannot be found again (although they would be displayed in REGEDIT)
* End of list-pointers are filled with 0xFFFFFFFF
*
* Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
* 0xFFFF, which means skipping over nextkeyoffset bytes (including this
* structure) and reading another RGDB_section.
*
* The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
* 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
* The remaining space between last_dke and the offset calculated from
* rgkn->size seems to be free for use for more dke:s.
* So it seems if more dke:s are added, they are added to that space and
* last_dke is grown, and in case that "free" space is out, the space
* gets grown and rgkn->size gets adjusted.
*
* there is a one to one relationship between dke and dkh
*/
/* key struct, once per key */
typedef
struct
{
DWORD
x1
;
/* Free entry indicator(?) */
DWORD
hash
;
/* sum of bytes of keyname */
DWORD
x3
;
/* Root key indicator? usually 0xFFFFFFFF */
DWORD
prevlvl
;
/* offset of previous key */
DWORD
nextsub
;
/* offset of child key */
DWORD
next
;
/* offset of sibling key */
WORD
nrLS
;
/* id inside the rgdb block */
WORD
nrMS
;
/* number of the rgdb block */
}
_w95dke
;
/* SECTION 3: key information, values and data
*
* structure:
* section: [blocks]* (repeat creg->rgdb_num times)
* blocks: [rgdb] [subblocks]* (repeat till block size reached )
* subblocks: [dkh] [dkv]* (repeat dkh->values times )
*
* An interesting relationship exists in RGDB_section. The DWORD value
* at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
* I have no idea at the moment what this means. (Kevin Cozens)
*/
/* block header, once per block */
#define W95_REG_RGDB_ID 0x42444752
typedef
struct
{
DWORD
id
;
/* 0x00 'RGDB' = W95_REG_RGDB_ID */
DWORD
size
;
/* 0x04 */
DWORD
uk1
;
/* 0x08 */
DWORD
uk2
;
/* 0x0c */
DWORD
uk3
;
/* 0x10 */
DWORD
uk4
;
/* 0x14 */
DWORD
uk5
;
/* 0x18 */
DWORD
uk6
;
/* 0x1c */
/* dkh */
}
_w95rgdb
;
/* Disk Key Header structure (RGDB part), once per key */
typedef
struct
{
DWORD
nextkeyoff
;
/* 0x00 offset to next dkh */
WORD
nrLS
;
/* 0x04 id inside the rgdb block */
WORD
nrMS
;
/* 0x06 number of the rgdb block */
DWORD
bytesused
;
/* 0x08 */
WORD
keynamelen
;
/* 0x0c len of name */
WORD
values
;
/* 0x0e number of values */
DWORD
xx1
;
/* 0x10 */
char
name
[
1
];
/* 0x14 */
/* dkv */
/* 0x14 + keynamelen */
}
_w95dkh
;
/* Disk Key Value structure, once per value */
typedef
struct
{
DWORD
type
;
/* 0x00 */
DWORD
x1
;
/* 0x04 */
WORD
valnamelen
;
/* 0x08 length of name, 0 is default key */
WORD
valdatalen
;
/* 0x0A length of data */
char
name
[
1
];
/* 0x0c */
/* raw data */
/* 0x0c + valnamelen */
}
_w95dkv
;
/******************************************************************************
* _w95_lookup_dkh [Internal]
*
* seeks the dkh belonging to a dke
*/
static
_w95dkh
*
_w95_lookup_dkh
(
_w95creg
*
creg
,
int
nrLS
,
int
nrMS
)
{
_w95rgdb
*
rgdb
;
_w95dkh
*
dkh
;
int
i
;
/* get the beginning of the rgdb datastore */
rgdb
=
(
_w95rgdb
*
)((
char
*
)
creg
+
creg
->
rgdb_off
);
/* check: requested block < last_block) */
if
(
creg
->
rgdb_num
<=
nrMS
)
{
ERR
(
"registry file corrupt! requested block no. beyond end.
\n
"
);
goto
error
;
}
/* find the right block */
for
(
i
=
0
;
i
<
nrMS
;
i
++
)
{
if
(
rgdb
->
id
!=
W95_REG_RGDB_ID
)
{
/* check the magic */
ERR
(
"registry file corrupt! bad magic 0x%08lx
\n
"
,
rgdb
->
id
);
goto
error
;
}
rgdb
=
(
_w95rgdb
*
)
((
char
*
)
rgdb
+
rgdb
->
size
);
/* find next block */
}
dkh
=
(
_w95dkh
*
)(
rgdb
+
1
);
/* first sub block within the rgdb */
do
{
if
(
nrLS
==
dkh
->
nrLS
)
return
dkh
;
dkh
=
(
_w95dkh
*
)((
char
*
)
dkh
+
dkh
->
nextkeyoff
);
/* find next subblock */
}
while
((
char
*
)
dkh
<
((
char
*
)
rgdb
+
rgdb
->
size
));
error:
return
NULL
;
}
/******************************************************************************
* _w95_dump_dkv [Internal]
*/
static
int
_w95_dump_dkv
(
_w95dkh
*
dkh
,
int
nrLS
,
int
nrMS
,
FILE
*
f
)
{
_w95dkv
*
dkv
;
int
i
;
/* first value block */
dkv
=
(
_w95dkv
*
)((
char
*
)
dkh
+
dkh
->
keynamelen
+
0x14
);
/* loop through the values */
for
(
i
=
0
;
i
<
dkh
->
values
;
i
++
)
{
struct
key_value
value
;
WCHAR
*
pdata
;
value
.
nameW
=
_strdupnAtoW
(
dkv
->
name
,
dkv
->
valnamelen
);
value
.
type
=
dkv
->
type
;
value
.
len
=
dkv
->
valdatalen
;
value
.
data
=
&
(
dkv
->
name
[
dkv
->
valnamelen
]);
pdata
=
NULL
;
if
(
(
value
.
type
==
REG_SZ
)
||
(
value
.
type
==
REG_EXPAND_SZ
)
||
(
value
.
type
==
REG_MULTI_SZ
)
)
{
pdata
=
_strdupnAtoW
(
value
.
data
,
value
.
len
);
value
.
len
*=
2
;
}
if
(
pdata
!=
NULL
)
value
.
data
=
pdata
;
_dump_value
(
&
value
,
f
);
free
(
value
.
nameW
);
if
(
pdata
!=
NULL
)
free
(
pdata
);
/* next value */
dkv
=
(
_w95dkv
*
)((
char
*
)
dkv
+
dkv
->
valnamelen
+
dkv
->
valdatalen
+
0x0c
);
}
return
TRUE
;
}
static
int
_w95_dump_one_dke
(
LPCSTR
key_name
,
_w95creg
*
creg
,
_w95rgkn
*
rgkn
,
_w95dke
*
dke
,
FILE
*
f
,
int
level
);
static
int
_w95_dump_dke
(
LPCSTR
key_name
,
_w95creg
*
creg
,
_w95rgkn
*
rgkn
,
_w95dke
*
dke
,
FILE
*
f
,
int
level
)
{
while
(
1
)
{
if
(
!
_w95_dump_one_dke
(
key_name
,
creg
,
rgkn
,
dke
,
f
,
level
))
return
FALSE
;
if
(
dke
->
next
==
0xffffffff
)
return
TRUE
;
dke
=
(
_w95dke
*
)((
char
*
)
rgkn
+
dke
->
next
);
}
}
/******************************************************************************
* _w95_dump_dke [Internal]
*/
static
int
_w95_dump_one_dke
(
LPCSTR
key_name
,
_w95creg
*
creg
,
_w95rgkn
*
rgkn
,
_w95dke
*
dke
,
FILE
*
f
,
int
level
)
{
_w95dkh
*
dkh
;
LPSTR
new_key_name
=
NULL
;
/* special root key */
if
(
dke
->
nrLS
==
0xffff
||
dke
->
nrMS
==
0xffff
)
/* eg. the root key has no name */
{
/* parse the one subkey */
if
(
dke
->
nextsub
!=
0xffffffff
)
return
_w95_dump_dke
(
key_name
,
creg
,
rgkn
,
(
_w95dke
*
)((
char
*
)
rgkn
+
dke
->
nextsub
),
f
,
level
);
/* has no sibling keys */
return
FALSE
;
}
/* search subblock */
if
(
!
(
dkh
=
_w95_lookup_dkh
(
creg
,
dke
->
nrLS
,
dke
->
nrMS
)))
{
ERR
(
"dke pointing to missing dkh !
\n
"
);
return
FALSE
;
}
if
(
level
<=
0
)
{
/* create new subkey name */
size_t
len
=
strlen
(
key_name
);
new_key_name
=
_xmalloc
(
len
+
dkh
->
keynamelen
+
2
);
memcpy
(
new_key_name
,
key_name
,
len
);
if
(
len
)
new_key_name
[
len
++
]
=
'\\'
;
memcpy
(
new_key_name
+
len
,
dkh
->
name
,
dkh
->
keynamelen
);
new_key_name
[
len
+
dkh
->
keynamelen
]
=
0
;
/* write the key path (something like [Software\\Microsoft\\..]) only if:
1) key has some values
2) key has no values and no subkeys
*/
if
(
dkh
->
values
>
0
)
{
/* there are some values */
fprintf
(
f
,
"
\n
["
);
_dump_strAtoW
(
new_key_name
,
strlen
(
new_key_name
),
f
,
"[]"
);
fprintf
(
f
,
"]
\n
"
);
if
(
!
_w95_dump_dkv
(
dkh
,
dke
->
nrLS
,
dke
->
nrMS
,
f
))
{
free
(
new_key_name
);
return
FALSE
;
}
}
if
((
dke
->
nextsub
==
0xffffffff
)
&&
(
dkh
->
values
==
0
))
{
/* no subkeys and no values */
fprintf
(
f
,
"
\n
["
);
_dump_strAtoW
(
new_key_name
,
strlen
(
new_key_name
),
f
,
"[]"
);
fprintf
(
f
,
"]
\n
"
);
}
}
else
new_key_name
=
_xstrdup
(
key_name
);
/* next sub key */
if
(
dke
->
nextsub
!=
0xffffffff
)
{
if
(
!
_w95_dump_dke
(
new_key_name
,
creg
,
rgkn
,
(
_w95dke
*
)((
char
*
)
rgkn
+
dke
->
nextsub
),
f
,
level
-
1
))
{
free
(
new_key_name
);
return
FALSE
;
}
}
free
(
new_key_name
);
return
TRUE
;
}
/* end windows 95 loader */
/***********************************************************************************/
/* windows NT registry loader */
/***********************************************************************************/
/* NT REGISTRY LOADER */
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifndef MAP_FAILED
#define MAP_FAILED ((LPVOID)-1)
#endif
#define NT_REG_BLOCK_SIZE 0x1000
#define NT_REG_HEADER_BLOCK_ID 0x66676572
/* regf */
#define NT_REG_POOL_BLOCK_ID 0x6E696268
/* hbin */
#define NT_REG_KEY_BLOCK_ID 0x6b6e
/* nk */
#define NT_REG_VALUE_BLOCK_ID 0x6b76
/* vk */
/* subblocks of nk */
#define NT_REG_HASH_BLOCK_ID 0x666c
/* lf */
#define NT_REG_NOHASH_BLOCK_ID 0x696c
/* li */
#define NT_REG_RI_BLOCK_ID 0x6972
/* ri */
#define NT_REG_KEY_BLOCK_TYPE 0x20
#define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
typedef
struct
{
DWORD
id
;
/* 0x66676572 'regf'*/
DWORD
uk1
;
/* 0x04 */
DWORD
uk2
;
/* 0x08 */
FILETIME
DateModified
;
/* 0x0c */
DWORD
uk3
;
/* 0x14 */
DWORD
uk4
;
/* 0x18 */
DWORD
uk5
;
/* 0x1c */
DWORD
uk6
;
/* 0x20 */
DWORD
RootKeyBlock
;
/* 0x24 */
DWORD
BlockSize
;
/* 0x28 */
DWORD
uk7
[
116
];
DWORD
Checksum
;
/* at offset 0x1FC */
}
nt_regf
;
typedef
struct
{
DWORD
blocksize
;
BYTE
data
[
1
];
}
nt_hbin_sub
;
typedef
struct
{
DWORD
id
;
/* 0x6E696268 'hbin' */
DWORD
off_prev
;
DWORD
off_next
;
DWORD
uk1
;
DWORD
uk2
;
/* 0x10 */
DWORD
uk3
;
/* 0x14 */
DWORD
uk4
;
/* 0x18 */
DWORD
size
;
/* 0x1C */
nt_hbin_sub
hbin_sub
;
/* 0x20 */
}
nt_hbin
;
/*
* the value_list consists of offsets to the values (vk)
*/
typedef
struct
{
WORD
SubBlockId
;
/* 0x00 0x6B6E */
WORD
Type
;
/* 0x02 for the root-key: 0x2C, otherwise 0x20*/
FILETIME
writetime
;
/* 0x04 */
DWORD
uk1
;
/* 0x0C */
DWORD
parent_off
;
/* 0x10 Offset of Owner/Parent key */
DWORD
nr_subkeys
;
/* 0x14 number of sub-Keys */
DWORD
uk8
;
/* 0x18 */
DWORD
lf_off
;
/* 0x1C Offset of the sub-key lf-Records */
DWORD
uk2
;
/* 0x20 */
DWORD
nr_values
;
/* 0x24 number of values */
DWORD
valuelist_off
;
/* 0x28 Offset of the Value-List */
DWORD
off_sk
;
/* 0x2c Offset of the sk-Record */
DWORD
off_class
;
/* 0x30 Offset of the Class-Name */
DWORD
uk3
;
/* 0x34 */
DWORD
uk4
;
/* 0x38 */
DWORD
uk5
;
/* 0x3c */
DWORD
uk6
;
/* 0x40 */
DWORD
uk7
;
/* 0x44 */
WORD
name_len
;
/* 0x48 name-length */
WORD
class_len
;
/* 0x4a class-name length */
char
name
[
1
];
/* 0x4c key-name */
}
nt_nk
;
typedef
struct
{
DWORD
off_nk
;
/* 0x00 */
DWORD
name
;
/* 0x04 */
}
hash_rec
;
typedef
struct
{
WORD
id
;
/* 0x00 0x666c */
WORD
nr_keys
;
/* 0x06 */
hash_rec
hash_rec
[
1
];
}
nt_lf
;
/*
list of subkeys without hash
li --+-->nk
|
+-->nk
*/
typedef
struct
{
WORD
id
;
/* 0x00 0x696c */
WORD
nr_keys
;
DWORD
off_nk
[
1
];
}
nt_li
;
/*
this is a intermediate node
ri --+-->li--+-->nk
| +
| +-->nk
|
+-->li--+-->nk
+
+-->nk
*/
typedef
struct
{
WORD
id
;
/* 0x00 0x6972 */
WORD
nr_li
;
/* 0x02 number off offsets */
DWORD
off_li
[
1
];
/* 0x04 points to li */
}
nt_ri
;
typedef
struct
{
WORD
id
;
/* 0x00 'vk' */
WORD
nam_len
;
DWORD
data_len
;
DWORD
data_off
;
DWORD
type
;
WORD
flag
;
WORD
uk1
;
char
name
[
1
];
}
nt_vk
;
/*
* gets a value
*
* vk->flag:
* 0 value is a default value
* 1 the value has a name
*
* vk->data_len
* len of the whole data block
* - reg_sz (unicode)
* bytes including the terminating \0 = 2*(number_of_chars+1)
* - reg_dword, reg_binary:
* if highest bit of data_len is set data_off contains the value
*/
static
int
_nt_dump_vk
(
LPSTR
key_name
,
char
*
base
,
nt_vk
*
vk
,
FILE
*
f
)
{
BYTE
*
pdata
=
(
BYTE
*
)(
base
+
vk
->
data_off
+
4
);
/* start of data */
struct
key_value
value
;
if
(
vk
->
id
!=
NT_REG_VALUE_BLOCK_ID
)
{
ERR
(
"unknown block found (0x%04x), please report!
\n
"
,
vk
->
id
);
return
FALSE
;
}
value
.
nameW
=
_strdupnAtoW
(
vk
->
name
,
vk
->
nam_len
);
value
.
type
=
vk
->
type
;
value
.
len
=
(
vk
->
data_len
&
0x7fffffff
);
value
.
data
=
(
vk
->
data_len
&
0x80000000
)
?
(
LPBYTE
)
&
(
vk
->
data_off
)
:
pdata
;
_dump_value
(
&
value
,
f
);
free
(
value
.
nameW
);
return
TRUE
;
}
/* it's called from _nt_dump_lf() */
static
int
_nt_dump_nk
(
LPCSTR
key_name
,
char
*
base
,
nt_nk
*
nk
,
FILE
*
f
,
int
level
);
/*
* get the subkeys
*
* this structure contains the hash of a keyname and points to all
* subkeys
*
* exception: if the id is 'il' there are no hash values and every
* dword is a offset
*/
static
int
_nt_dump_lf
(
LPCSTR
key_name
,
char
*
base
,
int
subkeys
,
nt_lf
*
lf
,
FILE
*
f
,
int
level
)
{
int
i
;
if
(
lf
->
id
==
NT_REG_HASH_BLOCK_ID
)
{
if
(
subkeys
!=
lf
->
nr_keys
)
goto
error1
;
for
(
i
=
0
;
i
<
lf
->
nr_keys
;
i
++
)
if
(
!
_nt_dump_nk
(
key_name
,
base
,
(
nt_nk
*
)(
base
+
lf
->
hash_rec
[
i
].
off_nk
+
4
),
f
,
level
))
goto
error
;
}
else
if
(
lf
->
id
==
NT_REG_NOHASH_BLOCK_ID
)
{
nt_li
*
li
=
(
nt_li
*
)
lf
;
if
(
subkeys
!=
li
->
nr_keys
)
goto
error1
;
for
(
i
=
0
;
i
<
li
->
nr_keys
;
i
++
)
if
(
!
_nt_dump_nk
(
key_name
,
base
,
(
nt_nk
*
)(
base
+
li
->
off_nk
[
i
]
+
4
),
f
,
level
))
goto
error
;
}
else
if
(
lf
->
id
==
NT_REG_RI_BLOCK_ID
)
{
/* ri */
nt_ri
*
ri
=
(
nt_ri
*
)
lf
;
int
li_subkeys
=
0
;
/* count all subkeys */
for
(
i
=
0
;
i
<
ri
->
nr_li
;
i
++
)
{
nt_li
*
li
=
(
nt_li
*
)(
base
+
ri
->
off_li
[
i
]
+
4
);
if
(
li
->
id
!=
NT_REG_NOHASH_BLOCK_ID
)
goto
error2
;
li_subkeys
+=
li
->
nr_keys
;
}
/* check number */
if
(
subkeys
!=
li_subkeys
)
goto
error1
;
/* loop through the keys */
for
(
i
=
0
;
i
<
ri
->
nr_li
;
i
++
)
{
nt_li
*
li
=
(
nt_li
*
)(
base
+
ri
->
off_li
[
i
]
+
4
);
if
(
!
_nt_dump_lf
(
key_name
,
base
,
li
->
nr_keys
,
(
nt_lf
*
)
li
,
f
,
level
))
goto
error
;
}
}
else
goto
error2
;
return
TRUE
;
error2:
if
(
lf
->
id
==
0x686c
)
FIXME
(
"unknown Win XP node id 0x686c: do we need to add support for it ?
\n
"
);
else
ERR
(
"unknown node id 0x%04x, please report!
\n
"
,
lf
->
id
);
return
TRUE
;
error1:
ERR
(
"registry file corrupt! (inconsistent number of subkeys)
\n
"
);
return
FALSE
;
error:
ERR
(
"error reading lf block
\n
"
);
return
FALSE
;
}
/* _nt_dump_nk [Internal] */
static
int
_nt_dump_nk
(
LPCSTR
key_name
,
char
*
base
,
nt_nk
*
nk
,
FILE
*
f
,
int
level
)
{
unsigned
int
n
;
DWORD
*
vl
;
LPSTR
new_key_name
=
NULL
;
TRACE
(
"%s
\n
"
,
key_name
);
if
(
nk
->
SubBlockId
!=
NT_REG_KEY_BLOCK_ID
)
{
ERR
(
"unknown node id 0x%04x, please report!
\n
"
,
nk
->
SubBlockId
);
return
FALSE
;
}
if
((
nk
->
Type
!=
NT_REG_ROOT_KEY_BLOCK_TYPE
)
&&
(((
nt_nk
*
)(
base
+
nk
->
parent_off
+
4
))
->
SubBlockId
!=
NT_REG_KEY_BLOCK_ID
))
{
ERR
(
"registry file corrupt!
\n
"
);
return
FALSE
;
}
/* create the new key */
if
(
level
<=
0
)
{
/* create new subkey name */
size_t
len
=
strlen
(
key_name
);
new_key_name
=
_xmalloc
(
len
+
nk
->
name_len
+
2
);
memcpy
(
new_key_name
,
key_name
,
len
);
if
(
len
)
new_key_name
[
len
++
]
=
'\\'
;
memcpy
(
new_key_name
+
len
,
nk
->
name
,
nk
->
name_len
);
new_key_name
[
len
+
nk
->
name_len
]
=
0
;
/* write the key path (something like [Software\\Microsoft\\..]) only if:
1) key has some values
2) key has no values and no subkeys
*/
if
(
nk
->
nr_values
>
0
)
{
/* there are some values */
fprintf
(
f
,
"
\n
["
);
_dump_strAtoW
(
new_key_name
,
strlen
(
new_key_name
),
f
,
"[]"
);
fprintf
(
f
,
"]
\n
"
);
}
if
((
nk
->
nr_subkeys
==
0
)
&&
(
nk
->
nr_values
==
0
))
{
/* no subkeys and no values */
fprintf
(
f
,
"
\n
["
);
_dump_strAtoW
(
new_key_name
,
strlen
(
new_key_name
),
f
,
"[]"
);
fprintf
(
f
,
"]
\n
"
);
}
/* loop trough the value list */
vl
=
(
DWORD
*
)(
base
+
nk
->
valuelist_off
+
4
);
for
(
n
=
0
;
n
<
nk
->
nr_values
;
n
++
)
{
nt_vk
*
vk
=
(
nt_vk
*
)(
base
+
vl
[
n
]
+
4
);
if
(
!
_nt_dump_vk
(
new_key_name
,
base
,
vk
,
f
))
{
free
(
new_key_name
);
return
FALSE
;
}
}
}
else
new_key_name
=
_xstrdup
(
key_name
);
/* loop through the subkeys */
if
(
nk
->
nr_subkeys
)
{
nt_lf
*
lf
=
(
nt_lf
*
)(
base
+
nk
->
lf_off
+
4
);
if
(
!
_nt_dump_lf
(
new_key_name
,
base
,
nk
->
nr_subkeys
,
lf
,
f
,
level
-
1
))
{
free
(
new_key_name
);
return
FALSE
;
}
}
free
(
new_key_name
);
return
TRUE
;
}
/* end nt loader */
/******************************************************************************
* _allocate_default_keys [Internal]
* Registry initialisation, allocates some default keys.
*/
...
...
@@ -1094,6 +89,9 @@ static void _allocate_default_keys(void)
static
const
WCHAR
ConfigManagerW
[]
=
{
'D'
,
'y'
,
'n'
,
'D'
,
'a'
,
't'
,
'a'
,
'\\'
,
'C'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
' '
,
'M'
,
'a'
,
'n'
,
'a'
,
'g'
,
'e'
,
'r'
,
'\\'
,
'E'
,
'n'
,
'u'
,
'm'
,
0
};
static
const
WCHAR
Clone
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'\\'
,
'C'
,
'l'
,
'o'
,
'n'
,
'e'
,
0
};
HKEY
hkey
;
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
;
...
...
@@ -1112,74 +110,13 @@ static void _allocate_default_keys(void)
RtlInitUnicodeString
(
&
nameW
,
ConfigManagerW
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
NtClose
(
hkey
);
}
static
void
get_windows_dir
(
WCHAR
*
buffer
,
unsigned
len
)
{
static
const
WCHAR
windows_dir
[]
=
{
'c'
,
':'
,
'\\'
,
'w'
,
'i'
,
'n'
,
'd'
,
'o'
,
'w'
,
's'
,
0
};
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
,
keyW
;
HKEY
hkey
;
*
buffer
=
0
;
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
ObjectName
=
&
nameW
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
if
(
RtlCreateUnicodeStringFromAsciiz
(
&
nameW
,
"Machine
\\
Software
\\
Wine
\\
Wine
\\
Config
\\
wine"
))
{
if
(
!
NtOpenKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
))
{
char
tmp
[
MAX_PATHNAME_LEN
*
sizeof
(
WCHAR
)
+
sizeof
(
KEY_VALUE_PARTIAL_INFORMATION
)];
DWORD
count
;
RtlCreateUnicodeStringFromAsciiz
(
&
keyW
,
"Windows"
);
if
(
!
NtQueryValueKey
(
hkey
,
&
keyW
,
KeyValuePartialInformation
,
tmp
,
sizeof
(
tmp
),
&
count
))
{
WCHAR
*
str
=
(
WCHAR
*
)((
KEY_VALUE_PARTIAL_INFORMATION
*
)
tmp
)
->
Data
;
memcpy
(
buffer
,
str
,
min
(((
KEY_VALUE_PARTIAL_INFORMATION
*
)
tmp
)
->
DataLength
,
len
));
}
RtlFreeUnicodeString
(
&
keyW
);
}
RtlFreeUnicodeString
(
&
nameW
);
}
if
(
!*
buffer
)
lstrcpynW
(
buffer
,
windows_dir
,
len
);
/* this key is generated when the nt-core booted successfully */
RtlInitUnicodeString
(
&
nameW
,
Clone
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
NtClose
(
hkey
);
}
#define REG_DONTLOAD -1
#define REG_WIN31 0
#define REG_WIN95 1
#define REG_WINNT 2
/* return the type of native registry [Internal] */
static
int
_get_reg_type
(
const
WCHAR
*
windir
)
{
WCHAR
tmp
[
MAX_PATHNAME_LEN
];
int
ret
=
REG_WIN31
;
static
const
WCHAR
nt_reg_pathW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
0
};
static
const
WCHAR
win9x_reg_pathW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
/* test %windir%/system32/config/system --> winnt */
strcpyW
(
tmp
,
windir
);
strcatW
(
tmp
,
nt_reg_pathW
);
if
(
GetFileAttributesW
(
tmp
)
!=
INVALID_FILE_ATTRIBUTES
)
ret
=
REG_WINNT
;
else
{
/* test %windir%/system.dat --> win95 */
strcpyW
(
tmp
,
windir
);
strcatW
(
tmp
,
win9x_reg_pathW
);
if
(
GetFileAttributesW
(
tmp
)
!=
INVALID_FILE_ATTRIBUTES
)
ret
=
REG_WIN95
;
}
return
ret
;
}
/* load the registry file in wine format [Internal] */
static
void
load_wine_registry
(
HKEY
hkey
,
LPCSTR
fn
)
...
...
@@ -1218,422 +155,6 @@ static void load_wine_registry(HKEY hkey,LPCSTR fn)
HeapFree
(
GetProcessHeap
(),
0
,
buffer
);
}
/* generate and return the name of the tmp file and associated stream [Internal] */
static
LPSTR
_get_tmp_fn
(
FILE
**
f
)
{
LPSTR
ret
;
int
tmp_fd
,
count
;
ret
=
_xmalloc
(
50
);
for
(
count
=
0
;;)
{
sprintf
(
ret
,
"/tmp/reg%lx%04x.tmp"
,(
long
)
getpid
(),
count
++
);
if
((
tmp_fd
=
open
(
ret
,
O_CREAT
|
O_EXCL
|
O_WRONLY
,
0666
))
!=
-
1
)
break
;
if
(
errno
!=
EEXIST
)
{
ERR
(
"Unexpected error while open() call: %s
\n
"
,
strerror
(
errno
));
free
(
ret
);
*
f
=
NULL
;
return
NULL
;
}
}
if
((
*
f
=
fdopen
(
tmp_fd
,
"w"
))
==
NULL
)
{
ERR
(
"Unexpected error while fdopen() call: %s
\n
"
,
strerror
(
errno
));
close
(
tmp_fd
);
free
(
ret
);
return
NULL
;
}
return
ret
;
}
/* convert win95 native registry file to wine format [Internal] */
static
LPSTR
_convert_win95_registry_to_wine_format
(
LPCWSTR
fn
,
int
level
)
{
HANDLE
hFile
,
hMapping
;
FILE
*
f
;
void
*
base
;
LPSTR
ret
=
NULL
;
OBJECT_ATTRIBUTES
attr
;
LARGE_INTEGER
lg_int
;
NTSTATUS
nts
;
SIZE_T
len
;
_w95creg
*
creg
;
_w95rgkn
*
rgkn
;
_w95dke
*
dke
,
*
root_dke
;
hFile
=
CreateFileW
(
fn
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
0
,
0
);
if
(
hFile
==
INVALID_HANDLE_VALUE
)
return
NULL
;
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
ObjectName
=
NULL
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
lg_int
.
QuadPart
=
0
;
nts
=
NtCreateSection
(
&
hMapping
,
STANDARD_RIGHTS_REQUIRED
|
SECTION_QUERY
|
SECTION_MAP_READ
,
&
attr
,
&
lg_int
,
PAGE_READONLY
,
SEC_COMMIT
,
hFile
);
if
(
nts
!=
STATUS_SUCCESS
)
goto
error1
;
base
=
NULL
;
len
=
0
;
nts
=
NtMapViewOfSection
(
hMapping
,
GetCurrentProcess
(),
&
base
,
0
,
0
,
&
lg_int
,
&
len
,
ViewShare
,
0
,
PAGE_READONLY
);
NtClose
(
hMapping
);
if
(
nts
!=
STATUS_SUCCESS
)
goto
error1
;
/* control signature */
if
(
*
(
LPDWORD
)
base
!=
W95_REG_CREG_ID
)
{
ERR
(
"unable to load native win95 registry file %s: unknown signature.
\n
"
,
debugstr_w
(
fn
));
goto
error
;
}
creg
=
base
;
/* load the header (rgkn) */
rgkn
=
(
_w95rgkn
*
)(
creg
+
1
);
if
(
rgkn
->
id
!=
W95_REG_RGKN_ID
)
{
ERR
(
"second IFF header not RGKN, but %lx
\n
"
,
rgkn
->
id
);
goto
error
;
}
if
(
rgkn
->
root_off
!=
0x20
)
{
ERR
(
"rgkn->root_off not 0x20, please report !
\n
"
);
goto
error
;
}
if
(
rgkn
->
last_dke
>
rgkn
->
size
)
{
ERR
(
"registry file corrupt! last_dke > size!
\n
"
);
goto
error
;
}
/* verify last dke */
dke
=
(
_w95dke
*
)((
char
*
)
rgkn
+
rgkn
->
last_dke
);
if
(
dke
->
x1
!=
0x80000000
)
{
/* wrong magic */
ERR
(
"last dke invalid !
\n
"
);
goto
error
;
}
if
(
rgkn
->
size
>
creg
->
rgdb_off
)
{
ERR
(
"registry file corrupt! rgkn size > rgdb_off !
\n
"
);
goto
error
;
}
root_dke
=
(
_w95dke
*
)((
char
*
)
rgkn
+
rgkn
->
root_off
);
if
(
(
root_dke
->
prevlvl
!=
0xffffffff
)
||
(
root_dke
->
next
!=
0xffffffff
)
)
{
ERR
(
"registry file corrupt! invalid root dke !
\n
"
);
goto
error
;
}
if
(
(
ret
=
_get_tmp_fn
(
&
f
))
==
NULL
)
goto
error
;
fprintf
(
f
,
"WINE REGISTRY Version 2"
);
_w95_dump_dke
(
""
,
creg
,
rgkn
,
root_dke
,
f
,
level
);
fclose
(
f
);
error:
if
(
ret
==
NULL
)
{
ERR
(
"Unable to load native win95 registry file %s.
\n
"
,
debugstr_w
(
fn
));
ERR
(
"Please report this.
\n
"
);
ERR
(
"Make a backup of the file, run a good reg cleaner program and try again!
\n
"
);
}
NtUnmapViewOfSection
(
GetCurrentProcess
(),
base
);
error1:
NtClose
(
hFile
);
return
ret
;
}
/* convert winnt native registry file to wine format [Internal] */
static
LPSTR
_convert_winnt_registry_to_wine_format
(
LPCWSTR
fn
,
int
level
)
{
FILE
*
f
;
void
*
base
;
LPSTR
ret
=
NULL
;
HANDLE
hFile
;
HANDLE
hMapping
;
OBJECT_ATTRIBUTES
attr
;
LARGE_INTEGER
lg_int
;
NTSTATUS
nts
;
SIZE_T
len
;
nt_regf
*
regf
;
nt_hbin
*
hbin
;
nt_hbin_sub
*
hbin_sub
;
nt_nk
*
nk
;
TRACE
(
"%s
\n
"
,
debugstr_w
(
fn
));
hFile
=
CreateFileW
(
fn
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
0
,
0
);
if
(
hFile
==
INVALID_HANDLE_VALUE
)
return
NULL
;
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
ObjectName
=
NULL
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
lg_int
.
QuadPart
=
0
;
nts
=
NtCreateSection
(
&
hMapping
,
STANDARD_RIGHTS_REQUIRED
|
SECTION_QUERY
|
SECTION_MAP_READ
,
&
attr
,
&
lg_int
,
PAGE_READONLY
,
SEC_COMMIT
,
hFile
);
if
(
nts
!=
STATUS_SUCCESS
)
goto
error1
;
base
=
NULL
;
len
=
0
;
nts
=
NtMapViewOfSection
(
hMapping
,
GetCurrentProcess
(),
&
base
,
0
,
0
,
&
lg_int
,
&
len
,
ViewShare
,
0
,
PAGE_READONLY
);
NtClose
(
hMapping
);
if
(
nts
!=
STATUS_SUCCESS
)
goto
error1
;
/* control signature */
if
(
*
(
LPDWORD
)
base
!=
NT_REG_HEADER_BLOCK_ID
)
{
ERR
(
"unable to load native winnt registry file %s: unknown signature.
\n
"
,
debugstr_w
(
fn
));
goto
error
;
}
/* start block */
regf
=
base
;
/* hbin block */
hbin
=
(
nt_hbin
*
)((
char
*
)
base
+
0x1000
);
if
(
hbin
->
id
!=
NT_REG_POOL_BLOCK_ID
)
{
ERR
(
"hbin block invalid
\n
"
);
goto
error
;
}
/* hbin_sub block */
hbin_sub
=
(
nt_hbin_sub
*
)
&
(
hbin
->
hbin_sub
);
if
((
hbin_sub
->
data
[
0
]
!=
'n'
)
||
(
hbin_sub
->
data
[
1
]
!=
'k'
))
{
ERR
(
"hbin_sub block invalid
\n
"
);
goto
error
;
}
/* nk block */
nk
=
(
nt_nk
*
)
&
(
hbin_sub
->
data
[
0
]);
if
(
nk
->
Type
!=
NT_REG_ROOT_KEY_BLOCK_TYPE
)
{
ERR
(
"special nk block not found
\n
"
);
goto
error
;
}
if
(
(
ret
=
_get_tmp_fn
(
&
f
))
==
NULL
)
goto
error
;
fprintf
(
f
,
"WINE REGISTRY Version 2"
);
_nt_dump_nk
(
""
,(
char
*
)
base
+
0x1000
,
nk
,
f
,
level
);
fclose
(
f
);
error:
NtUnmapViewOfSection
(
GetCurrentProcess
(),
base
);
error1:
NtClose
(
hFile
);
return
ret
;
}
/* convert native registry to wine format and load it via server call [Internal] */
static
void
_convert_and_load_native_registry
(
LPCWSTR
fn
,
HKEY
hkey
,
int
reg_type
,
int
level
)
{
LPSTR
tmp
=
NULL
;
switch
(
reg_type
)
{
case
REG_WINNT
:
/* FIXME: following function doesn't really convert yet */
tmp
=
_convert_winnt_registry_to_wine_format
(
fn
,
level
);
break
;
case
REG_WIN95
:
tmp
=
_convert_win95_registry_to_wine_format
(
fn
,
level
);
break
;
case
REG_WIN31
:
ERR
(
"Don't know how to convert native 3.1 registry yet.
\n
"
);
break
;
default:
ERR
(
"Unknown registry format parameter (%d)
\n
"
,
reg_type
);
break
;
}
if
(
tmp
!=
NULL
)
{
load_wine_registry
(
hkey
,
tmp
);
TRACE
(
"File %s successfully converted to %s and loaded to registry.
\n
"
,
debugstr_w
(
fn
),
tmp
);
unlink
(
tmp
);
}
else
WARN
(
"Unable to convert %s (doesn't exist?)
\n
"
,
debugstr_w
(
fn
));
free
(
tmp
);
}
/* load all native windows registry files [Internal] */
static
void
_load_windows_registry
(
HKEY
hkey_local_machine
,
HKEY
hkey_current_user
,
HKEY
hkey_users_default
)
{
int
reg_type
;
WCHAR
windir
[
MAX_PATHNAME_LEN
];
WCHAR
path
[
MAX_PATHNAME_LEN
];
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
;
HKEY
hkey
,
profile_key
;
char
tmp
[
1024
];
DWORD
dummy
;
static
const
WCHAR
WineW
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'o'
,
'f'
,
't'
,
'w'
,
'a'
,
'r'
,
'e'
,
'\\'
,
'W'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'W'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'C'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
'W'
,
'i'
,
'n'
,
'e'
,
0
};
static
const
WCHAR
ProfileW
[]
=
{
'P'
,
'r'
,
'o'
,
'f'
,
'i'
,
'l'
,
'e'
,
0
};
static
const
WCHAR
System
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
0
};
static
const
WCHAR
Software
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'o'
,
'f'
,
't'
,
'w'
,
'a'
,
'r'
,
'e'
,
0
};
static
const
WCHAR
Clone
[]
=
{
'M'
,
'a'
,
'c'
,
'h'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'S'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'\\'
,
'C'
,
'l'
,
'o'
,
'n'
,
'e'
,
0
};
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
ObjectName
=
&
nameW
;
attr
.
Attributes
=
0
;
attr
.
SecurityDescriptor
=
NULL
;
attr
.
SecurityQualityOfService
=
NULL
;
RtlInitUnicodeString
(
&
nameW
,
WineW
);
if
(
NtCreateKey
(
&
profile_key
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
profile_key
=
0
;
get_windows_dir
(
windir
,
sizeof
(
windir
));
reg_type
=
_get_reg_type
(
windir
);
switch
(
reg_type
)
{
case
REG_WINNT
:
{
static
const
WCHAR
ntuser_datW
[]
=
{
'\\'
,
'n'
,
't'
,
'u'
,
's'
,
'e'
,
'r'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
static
const
WCHAR
defaultW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
'd'
,
'e'
,
'f'
,
'a'
,
'u'
,
'l'
,
't'
,
0
};
static
const
WCHAR
systemW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
0
};
static
const
WCHAR
softwareW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
's'
,
'o'
,
'f'
,
't'
,
'w'
,
'a'
,
'r'
,
'e'
,
0
};
static
const
WCHAR
samW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
's'
,
'a'
,
'm'
,
0
};
static
const
WCHAR
securityW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'3'
,
'2'
,
'\\'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
's'
,
'e'
,
'c'
,
'u'
,
'r'
,
'i'
,
't'
,
'y'
,
0
};
/* user specific ntuser.dat */
RtlInitUnicodeString
(
&
nameW
,
ProfileW
);
if
(
profile_key
&&
!
NtQueryValueKey
(
profile_key
,
&
nameW
,
KeyValuePartialInformation
,
tmp
,
sizeof
(
tmp
),
&
dummy
))
{
strcpyW
(
path
,
(
WCHAR
*
)((
KEY_VALUE_PARTIAL_INFORMATION
*
)
tmp
)
->
Data
);
strcatW
(
path
,
ntuser_datW
);
_convert_and_load_native_registry
(
path
,
hkey_current_user
,
REG_WINNT
,
1
);
}
else
{
MESSAGE
(
"When you are running with a native NT directory specify
\n
"
);
MESSAGE
(
"'Profile=<profiledirectory>' or disable loading of Windows
\n
"
);
MESSAGE
(
"registry (LoadWindowsRegistryFiles=N)
\n
"
);
break
;
}
/* default user.dat */
if
(
hkey_users_default
)
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
defaultW
);
_convert_and_load_native_registry
(
path
,
hkey_users_default
,
REG_WINNT
,
1
);
}
/*
* FIXME
* map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
*/
RtlInitUnicodeString
(
&
nameW
,
System
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
systemW
);
_convert_and_load_native_registry
(
path
,
hkey
,
REG_WINNT
,
1
);
NtClose
(
hkey
);
}
RtlInitUnicodeString
(
&
nameW
,
Software
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
softwareW
);
_convert_and_load_native_registry
(
path
,
hkey
,
REG_WINNT
,
1
);
NtClose
(
hkey
);
}
strcpyW
(
path
,
windir
);
strcatW
(
path
,
samW
);
_convert_and_load_native_registry
(
path
,
hkey_local_machine
,
REG_WINNT
,
0
);
strcpyW
(
path
,
windir
);
strcatW
(
path
,
securityW
);
_convert_and_load_native_registry
(
path
,
hkey_local_machine
,
REG_WINNT
,
0
);
/* this key is generated when the nt-core booted successfully */
RtlInitUnicodeString
(
&
nameW
,
Clone
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
NtClose
(
hkey
);
break
;
}
case
REG_WIN95
:
{
static
const
WCHAR
system_1stW
[]
=
{
'c'
,
':'
,
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'.'
,
'1'
,
's'
,
't'
,
0
};
static
const
WCHAR
system_datW
[]
=
{
'\\'
,
's'
,
'y'
,
's'
,
't'
,
'e'
,
'm'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
static
const
WCHAR
classes_datW
[]
=
{
'\\'
,
'c'
,
'l'
,
'a'
,
's'
,
's'
,
'e'
,
's'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
static
const
WCHAR
user_datW
[]
=
{
'\\'
,
'u'
,
's'
,
'e'
,
'r'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
_convert_and_load_native_registry
(
system_1stW
,
hkey_local_machine
,
REG_WIN95
,
0
);
strcpyW
(
path
,
windir
);
strcatW
(
path
,
system_datW
);
_convert_and_load_native_registry
(
path
,
hkey_local_machine
,
REG_WIN95
,
0
);
RtlInitUnicodeString
(
&
nameW
,
ClassesRootW
);
if
(
!
NtCreateKey
(
&
hkey
,
KEY_ALL_ACCESS
,
&
attr
,
0
,
NULL
,
0
,
NULL
))
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
classes_datW
);
_convert_and_load_native_registry
(
path
,
hkey
,
REG_WIN95
,
0
);
NtClose
(
hkey
);
}
RtlInitUnicodeString
(
&
nameW
,
ProfileW
);
if
(
profile_key
&&
!
NtQueryValueKey
(
profile_key
,
&
nameW
,
KeyValuePartialInformation
,
tmp
,
sizeof
(
tmp
),
&
dummy
))
{
/* user specific user.dat */
strcpyW
(
path
,
(
WCHAR
*
)((
KEY_VALUE_PARTIAL_INFORMATION
*
)
tmp
)
->
Data
);
strcatW
(
path
,
user_datW
);
_convert_and_load_native_registry
(
path
,
hkey_current_user
,
REG_WIN95
,
1
);
/* default user.dat */
if
(
hkey_users_default
)
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
user_datW
);
_convert_and_load_native_registry
(
path
,
hkey_users_default
,
REG_WIN95
,
1
);
}
}
else
{
strcpyW
(
path
,
windir
);
strcatW
(
path
,
user_datW
);
_convert_and_load_native_registry
(
path
,
hkey_current_user
,
REG_WIN95
,
1
);
}
break
;
}
case
REG_WIN31
:
{
static
const
WCHAR
reg_datW
[]
=
{
'\\'
,
'r'
,
'e'
,
'g'
,
'.'
,
'd'
,
'a'
,
't'
,
0
};
/* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
strcpyW
(
path
,
windir
);
strcatW
(
path
,
reg_datW
);
_w31_loadreg
(
path
);
break
;
}
case
REG_DONTLOAD
:
TRACE
(
"REG_DONTLOAD
\n
"
);
break
;
default:
ERR
(
"switch: no match (%d)
\n
"
,
reg_type
);
break
;
}
if
(
profile_key
)
NtClose
(
profile_key
);
}
/******************************************************************
* init_cdrom_registry
...
...
@@ -1998,7 +519,6 @@ void SHELL_LoadRegistry( void )
'W'
,
'i'
,
'n'
,
'e'
,
'\\'
,
'C'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'\\'
,
'R'
,
'e'
,
'g'
,
'i'
,
's'
,
't'
,
'r'
,
'y'
,
0
};
static
const
WCHAR
load_win_reg_filesW
[]
=
{
'L'
,
'o'
,
'a'
,
'd'
,
'W'
,
'i'
,
'n'
,
'd'
,
'o'
,
'w'
,
's'
,
'R'
,
'e'
,
'g'
,
'i'
,
's'
,
't'
,
'r'
,
'y'
,
'F'
,
'i'
,
'l'
,
'e'
,
's'
,
0
};
static
const
WCHAR
load_global_reg_filesW
[]
=
{
'L'
,
'o'
,
'a'
,
'd'
,
'G'
,
'l'
,
'o'
,
'b'
,
'a'
,
'l'
,
'R'
,
'e'
,
'g'
,
'i'
,
's'
,
't'
,
'r'
,
'y'
,
'F'
,
'i'
,
'l'
,
'e'
,
's'
,
0
};
static
const
WCHAR
SaveOnlyUpdatedKeysW
[]
=
{
'S'
,
'a'
,
'v'
,
'e'
,
'O'
,
'n'
,
'l'
,
'y'
,
'U'
,
'p'
,
'd'
,
'a'
,
't'
,
'e'
,
'd'
,
'K'
,
'e'
,
'y'
,
's'
,
0
};
static
const
WCHAR
PeriodicSaveW
[]
=
{
'P'
,
'e'
,
'r'
,
'i'
,
'o'
,
'd'
,
'i'
,
'c'
,
'S'
,
'a'
,
'v'
,
'e'
,
0
};
...
...
@@ -2040,18 +560,6 @@ void SHELL_LoadRegistry( void )
RtlInitUnicodeString
(
&
nameW
,
RegistryW
);
if
(
NtOpenKey
(
&
hkey_config
,
KEY_ALL_ACCESS
,
&
attr
))
hkey_config
=
0
;
/* load windows registry if required */
res
=
TRUE
;
attr
.
RootDirectory
=
hkey_config
;
RtlInitUnicodeString
(
&
nameW
,
load_win_reg_filesW
);
if
(
!
NtQueryValueKey
(
hkey_config
,
&
nameW
,
KeyValuePartialInformation
,
tmp
,
sizeof
(
tmp
),
&
count
))
{
WCHAR
*
str
=
(
WCHAR
*
)((
KEY_VALUE_PARTIAL_INFORMATION
*
)
tmp
)
->
Data
;
res
=
!
IS_OPTION_FALSE
(
str
[
0
]);
}
if
(
res
)
_load_windows_registry
(
hkey_local_machine
,
hkey_current_user
,
hkey_users_default
);
/* load global registry if required */
res
=
TRUE
;
...
...
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