4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * When changing this file, please re-run the regtest program to ensure
28 * the conditions are handled properly.
33 * Time for RegEnumKey*, RegQueryInfoKey*
37 #include "wine/port.h"
47 #include <sys/types.h>
50 #ifdef HAVE_SYS_MMAN_H
51 # include <sys/mman.h>
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
61 #include "wine/winbase16.h"
62 #include "wine/library.h"
63 #include "wine/server.h"
64 #include "wine/unicode.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
71 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
72 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
74 /* relative in ~user/.wine/ : */
75 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
76 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
77 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
79 static const WCHAR ClassesRootW
[] = {'M','a','c','h','i','n','e','\\',
80 'S','o','f','t','w','a','r','e','\\',
81 'C','l','a','s','s','e','s',0};
83 #define IS_OPTION_FALSE(ch) \
84 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
86 /* _xmalloc [Internal] */
87 static void *_xmalloc( size_t size
)
91 res
= malloc (size
? size
: 1);
93 WARN("Virtual memory exhausted.\n");
99 /* _xstrdup [Internal] */
100 static LPSTR
_xstrdup(LPCSTR str
)
103 size_t len
= strlen(str
) + 1;
105 if (!str
) return NULL
;
106 ret
= _xmalloc( len
);
107 memcpy( ret
, str
, len
);
111 /* convert ansi string to unicode [Internal] */
112 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
117 if (!strA
) return NULL
;
118 if (RtlMultiByteToUnicodeSize( &len
, strA
, lenA
) != STATUS_SUCCESS
) return NULL
;
120 ret
= _xmalloc(len
+sizeof(WCHAR
));
121 RtlMultiByteToUnicodeN(ret
, len
, NULL
, strA
, lenA
);
122 ret
[len
/ sizeof(WCHAR
)] = 0;
126 /* dump a Unicode string with proper escaping [Internal] */
127 /* FIXME: this code duplicates server/unicode.c */
128 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,const char escape
[2])
130 static const char escapes
[32] = ".......abtnvfr.............e....";
135 for (; len
; str
++, len
--)
137 if (pos
> buffer
+ sizeof(buffer
) - 8)
139 fwrite( buffer
, pos
- buffer
, 1, f
);
140 count
+= pos
- buffer
;
143 if (*str
> 127) /* hex escape */
145 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
146 pos
+= sprintf( pos
, "\\x%04x", *str
);
148 pos
+= sprintf( pos
, "\\x%x", *str
);
151 if (*str
< 32) /* octal or C escape */
153 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
154 if (escapes
[*str
] != '.')
155 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
156 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
157 pos
+= sprintf( pos
, "\\%03o", *str
);
159 pos
+= sprintf( pos
, "\\%o", *str
);
162 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
165 fwrite( buffer
, pos
- buffer
, 1, f
);
166 count
+= pos
- buffer
;
170 /* convert ansi string to unicode and dump with proper escaping [Internal] */
171 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,const char escape
[2])
176 if (strA
== NULL
) return 0;
177 strW
= _strdupnAtoW(strA
,len
);
178 ret
= _dump_strW(strW
,len
,f
,escape
);
184 /* FIXME: this code duplicates server/registry.c */
186 WCHAR
*nameW
; /* value name */
187 int type
; /* value type */
188 size_t len
; /* value data length in bytes */
189 void *data
; /* pointer to value data */
192 /* dump a value to a text file */
193 /* FIXME: this code duplicates server/registry.c */
194 static void _dump_value(struct key_value
*value
,FILE *f
)
198 if (value
->nameW
[0]) {
200 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
201 count
+= fprintf( f
, "\"=" );
203 else count
= fprintf( f
, "@=" );
205 switch(value
->type
) {
209 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
211 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
215 if (value
->len
== sizeof(DWORD
)) {
217 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
218 fprintf( f
, "dword:%08lx", dw
);
221 /* else fall through */
223 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
224 else count
+= fprintf( f
, "hex(%x):", value
->type
);
225 for (i
= 0; i
< value
->len
; i
++) {
226 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
227 if (i
< value
->len
-1) {
230 fprintf( f
, "\\\n " );
240 /******************************************************************/
241 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
243 reghack - windows 3.11 registry data format demo program.
245 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
246 a combined hash table and tree description, and finally a text table.
248 The header is obvious from the struct header. The taboff1 and taboff2
249 fields are always 0x20, and their usage is unknown.
251 The 8-byte entry table has various entry types.
253 tabent[0] is a root index. The second word has the index of the root of
255 tabent[1..hashsize] is a hash table. The first word in the hash entry is
256 the index of the key/value that has that hash. Data with the same
257 hash value are on a circular list. The other three words in the
258 hash entry are always zero.
259 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
260 entry: dirent and keyent/valent. They are identified by context.
261 tabent[freeidx] is the first free entry. The first word in a free entry
262 is the index of the next free entry. The last has 0 as a link.
263 The other three words in the free list are probably irrelevant.
265 Entries in text table are preceded by a word at offset-2. This word
266 has the value (2*index)+1, where index is the referring keyent/valent
267 entry in the table. I have no suggestion for the 2* and the +1.
268 Following the word, there are N bytes of data, as per the keyent/valent
269 entry length. The offset of the keyent/valent entry is from the start
270 of the text table to the first data byte.
272 This information is not available from Microsoft. The data format is
273 deduced from the reg.dat file by me. Mistakes may
274 have been made. I claim no rights and give no guarantees for this program.
276 Tor Sjøwall, tor@sn.no
279 /* reg.dat header format */
281 char cookie
[8]; /* 'SHCC3.10' */
282 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
283 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
284 unsigned long tabcnt
; /* number of entries in index table */
285 unsigned long textoff
; /* offset of text part */
286 unsigned long textsize
; /* byte size of text part */
287 unsigned short hashsize
; /* hash size */
288 unsigned short freeidx
; /* free index */
291 /* generic format of table entries */
293 unsigned short w0
, w1
, w2
, w3
;
296 /* directory tabent: */
298 unsigned short sibling_idx
; /* table index of sibling dirent */
299 unsigned short child_idx
; /* table index of child dirent */
300 unsigned short key_idx
; /* table index of key keyent */
301 unsigned short value_idx
; /* table index of value valent */
306 unsigned short hash_idx
; /* hash chain index for string */
307 unsigned short refcnt
; /* reference count */
308 unsigned short length
; /* length of string */
309 unsigned short string_off
; /* offset of string in text table */
314 unsigned short hash_idx
; /* hash chain index for string */
315 unsigned short refcnt
; /* reference count */
316 unsigned short length
; /* length of string */
317 unsigned short string_off
; /* offset of string in text table */
320 /* recursive helper function to display a directory tree [Internal] */
321 static void _w31_dumptree(unsigned short idx
, unsigned char *txt
,
322 struct _w31_tabent
*tab
, struct _w31_header
*head
,
323 HKEY hkey
, ULONG lastmodified
, int level
)
325 static const WCHAR classesW
[] = {'.','c','l','a','s','s','e','s',0};
326 struct _w31_dirent
*dir
;
327 struct _w31_keyent
*key
;
328 struct _w31_valent
*val
;
330 OBJECT_ATTRIBUTES attr
;
331 UNICODE_STRING nameW
, valueW
;
332 static WCHAR tail
[400];
334 attr
.Length
= sizeof(attr
);
335 attr
.RootDirectory
= hkey
;
336 attr
.ObjectName
= &nameW
;
338 attr
.SecurityDescriptor
= NULL
;
339 attr
.SecurityQualityOfService
= NULL
;
340 RtlInitUnicodeString( &valueW
, NULL
);
343 dir
=(struct _w31_dirent
*)&tab
[idx
];
347 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
349 RtlMultiByteToUnicodeN( tail
, sizeof(tail
)-sizeof(WCHAR
), &len
,
350 &txt
[key
->string_off
], key
->length
);
351 tail
[len
/sizeof(WCHAR
)] = 0;
353 /* all toplevel entries AND the entries in the
354 * toplevel subdirectory belong to \SOFTWARE\Classes
356 if (!level
&& !strcmpW(tail
,classesW
))
358 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
359 idx
=dir
->sibling_idx
;
363 if (subkey
) NtClose( subkey
);
364 RtlInitUnicodeString( &nameW
, tail
);
365 if (NtCreateKey( &subkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) subkey
= 0;
367 /* only add if leaf node or valued node */
368 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
369 if (dir
->value_idx
) {
371 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
372 RtlMultiByteToUnicodeN( tail
, sizeof(tail
) - sizeof(WCHAR
), &len
,
373 &txt
[val
->string_off
], val
->length
);
374 tail
[len
/sizeof(WCHAR
)] = 0;
375 NtSetValueKey( subkey
, &valueW
, 0, REG_SZ
, tail
, len
+ sizeof(WCHAR
) );
378 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
379 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
380 idx
=dir
->sibling_idx
;
382 if (subkey
) NtClose( subkey
);
386 /******************************************************************************
387 * _w31_loadreg [Internal]
389 static void _w31_loadreg(void)
393 OBJECT_ATTRIBUTES attr
;
394 UNICODE_STRING nameW
;
395 struct _w31_header head
;
396 struct _w31_tabent
* tab
= NULL
;
397 unsigned char* txt
= NULL
;
402 IO_STATUS_BLOCK iosb
;
403 FILE_POSITION_INFORMATION fpi
;
404 FILE_BASIC_INFORMATION fbi
;
408 hf
= (HANDLE
)OpenFile("reg.dat",&ofs
,OF_READ
);
409 if (hf
==(HANDLE
)HFILE_ERROR
) return;
411 /* read & dump header */
412 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
413 &head
, sizeof(head
), NULL
, NULL
) != STATUS_SUCCESS
||
414 iosb
.Information
!= sizeof(head
))
416 ERR("reg.dat is too short.\n");
419 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
)) != 0)
421 ERR("reg.dat has bad signature.\n");
425 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
426 /* read and dump index table */
428 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
429 tab
, len
, NULL
, NULL
) != STATUS_SUCCESS
||
430 iosb
.Information
!= len
)
432 ERR("couldn't read index table (%d bytes).\n",len
);
437 txt
= _xmalloc(head
.textsize
);
438 fpi
.CurrentByteOffset
.u
.LowPart
= head
.textoff
;
439 fpi
.CurrentByteOffset
.u
.HighPart
= 0;
440 if (NtSetInformationFile(hf
, &iosb
, &fpi
, sizeof(fpi
),
441 FilePositionInformation
) != STATUS_SUCCESS
)
443 ERR("couldn't seek to textblock.\n");
446 status
= NtReadFile(hf
, 0, NULL
, NULL
, &iosb
, txt
, head
.textsize
, NULL
, NULL
);
447 if (!(status
== STATUS_SUCCESS
|| status
== STATUS_END_OF_FILE
) ||
448 iosb
.Information
!= head
.textsize
)
450 ERR("textblock too short (%d instead of %ld).\n", len
, head
.textsize
);
453 if (NtQueryInformationFile(hf
, &iosb
, &fbi
, sizeof(fbi
),
454 FileBasicInformation
) != STATUS_SUCCESS
)
456 ERR("Couldn't get basic information.\n");
459 RtlTimeToSecondsSince1970(&fbi
.LastWriteTime
, &lastmodified
);
461 attr
.Length
= sizeof(attr
);
462 attr
.RootDirectory
= 0;
463 attr
.ObjectName
= &nameW
;
465 attr
.SecurityDescriptor
= NULL
;
466 attr
.SecurityQualityOfService
= NULL
;
467 RtlInitUnicodeString( &nameW
, ClassesRootW
);
469 if (!NtCreateKey( &root
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
471 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,root
,lastmodified
,0);
481 /***********************************************************************************/
482 /* windows 95 registry loader */
483 /***********************************************************************************/
485 /* SECTION 1: main header
489 #define W95_REG_CREG_ID 0x47455243
492 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
493 DWORD version
; /* ???? 0x00010000 */
494 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
495 DWORD uk2
; /* 0x0c */
496 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
502 /* SECTION 2: Directory information (tree structure)
504 * once on offset 0x20
506 * structure: [rgkn][dke]* (repeat till last_dke is reached)
508 #define W95_REG_RGKN_ID 0x4e4b4752
511 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
512 DWORD size
; /* Size of the RGKN-block */
513 DWORD root_off
; /* Rel. Offset of the root-record */
514 DWORD last_dke
; /* Offset to last DKE ? */
518 /* Disk Key Entry Structure
520 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
521 * hive itself. It looks the same like other keys. Even the ID-number can
524 * The "hash"-value is a value representing the key's name. Windows will not
525 * search for the name, but for a matching hash-value. if it finds one, it
526 * will compare the actual string info, otherwise continue with the next key.
527 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
528 * of the string which are smaller than 0x80 (128) to this D-Word.
530 * If you want to modify key names, also modify the hash-values, since they
531 * cannot be found again (although they would be displayed in REGEDIT)
532 * End of list-pointers are filled with 0xFFFFFFFF
534 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
535 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
536 * structure) and reading another RGDB_section.
538 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
539 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
540 * The remaining space between last_dke and the offset calculated from
541 * rgkn->size seems to be free for use for more dke:s.
542 * So it seems if more dke:s are added, they are added to that space and
543 * last_dke is grown, and in case that "free" space is out, the space
544 * gets grown and rgkn->size gets adjusted.
546 * there is a one to one relationship between dke and dkh
548 /* key struct, once per key */
550 DWORD x1
; /* Free entry indicator(?) */
551 DWORD hash
; /* sum of bytes of keyname */
552 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
553 DWORD prevlvl
; /* offset of previous key */
554 DWORD nextsub
; /* offset of child key */
555 DWORD next
; /* offset of sibling key */
556 WORD nrLS
; /* id inside the rgdb block */
557 WORD nrMS
; /* number of the rgdb block */
560 /* SECTION 3: key information, values and data
563 * section: [blocks]* (repeat creg->rgdb_num times)
564 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
565 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
567 * An interesting relationship exists in RGDB_section. The DWORD value
568 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
569 * I have no idea at the moment what this means. (Kevin Cozens)
572 /* block header, once per block */
573 #define W95_REG_RGDB_ID 0x42444752
576 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
577 DWORD size
; /* 0x04 */
578 DWORD uk1
; /* 0x08 */
579 DWORD uk2
; /* 0x0c */
580 DWORD uk3
; /* 0x10 */
581 DWORD uk4
; /* 0x14 */
582 DWORD uk5
; /* 0x18 */
583 DWORD uk6
; /* 0x1c */
587 /* Disk Key Header structure (RGDB part), once per key */
589 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
590 WORD nrLS
; /* 0x04 id inside the rgdb block */
591 WORD nrMS
; /* 0x06 number of the rgdb block */
592 DWORD bytesused
; /* 0x08 */
593 WORD keynamelen
; /* 0x0c len of name */
594 WORD values
; /* 0x0e number of values */
595 DWORD xx1
; /* 0x10 */
596 char name
[1]; /* 0x14 */
597 /* dkv */ /* 0x14 + keynamelen */
600 /* Disk Key Value structure, once per value */
602 DWORD type
; /* 0x00 */
604 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
605 WORD valdatalen
; /* 0x0A length of data */
606 char name
[1]; /* 0x0c */
607 /* raw data */ /* 0x0c + valnamelen */
610 /******************************************************************************
611 * _w95_lookup_dkh [Internal]
613 * seeks the dkh belonging to a dke
615 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
621 /* get the beginning of the rgdb datastore */
622 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
624 /* check: requested block < last_block) */
625 if (creg
->rgdb_num
<= nrMS
) {
626 ERR("registry file corrupt! requested block no. beyond end.\n");
630 /* find the right block */
631 for(i
=0; i
<nrMS
;i
++) {
632 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
633 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
636 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
639 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
642 if(nrLS
==dkh
->nrLS
) return dkh
;
643 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
644 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
650 /******************************************************************************
651 * _w95_dump_dkv [Internal]
653 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
658 /* first value block */
659 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
661 /* loop through the values */
662 for (i
=0; i
< dkh
->values
; i
++) {
663 struct key_value value
;
666 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
667 value
.type
= dkv
->type
;
668 value
.len
= dkv
->valdatalen
;
670 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
672 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
673 pdata
= _strdupnAtoW(value
.data
,value
.len
);
676 if (pdata
!= NULL
) value
.data
= pdata
;
678 _dump_value(&value
,f
);
680 if (pdata
!= NULL
) free(pdata
);
683 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
688 /******************************************************************************
689 * _w95_dump_dke [Internal]
691 static int _w95_dump_dke(LPCSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
694 LPSTR new_key_name
= NULL
;
696 /* special root key */
697 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
699 /* parse the one subkey */
700 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
701 /* has no sibling keys */
705 /* search subblock */
706 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
707 ERR("dke pointing to missing dkh !\n");
712 /* create new subkey name */
713 size_t len
= strlen(key_name
);
714 new_key_name
= _xmalloc(len
+dkh
->keynamelen
+2);
715 memcpy( new_key_name
, key_name
, len
);
716 if (len
) new_key_name
[len
++] = '\\';
717 memcpy( new_key_name
+ len
, dkh
->name
, dkh
->keynamelen
);
718 new_key_name
[len
+ dkh
->keynamelen
] = 0;
720 /* walk sibling keys */
721 if (dke
->next
!= 0xffffffff ) {
722 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
728 /* write the key path (something like [Software\\Microsoft\\..]) only if:
729 1) key has some values
730 2) key has no values and no subkeys
732 if (dkh
->values
> 0) {
733 /* there are some values */
735 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
737 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
742 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
743 /* no subkeys and no values */
745 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
748 } else new_key_name
= _xstrdup(key_name
);
751 if (dke
->nextsub
!= 0xffffffff) {
752 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
761 /* end windows 95 loader */
763 /***********************************************************************************/
764 /* windows NT registry loader */
765 /***********************************************************************************/
767 /* NT REGISTRY LOADER */
769 #ifdef HAVE_SYS_MMAN_H
770 # include <sys/mman.h>
774 #define MAP_FAILED ((LPVOID)-1)
777 #define NT_REG_BLOCK_SIZE 0x1000
779 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
780 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
781 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
782 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
784 /* subblocks of nk */
785 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
786 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
787 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
789 #define NT_REG_KEY_BLOCK_TYPE 0x20
790 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
793 DWORD id
; /* 0x66676572 'regf'*/
794 DWORD uk1
; /* 0x04 */
795 DWORD uk2
; /* 0x08 */
796 FILETIME DateModified
; /* 0x0c */
797 DWORD uk3
; /* 0x14 */
798 DWORD uk4
; /* 0x18 */
799 DWORD uk5
; /* 0x1c */
800 DWORD uk6
; /* 0x20 */
801 DWORD RootKeyBlock
; /* 0x24 */
802 DWORD BlockSize
; /* 0x28 */
804 DWORD Checksum
; /* at offset 0x1FC */
813 DWORD id
; /* 0x6E696268 'hbin' */
817 DWORD uk2
; /* 0x10 */
818 DWORD uk3
; /* 0x14 */
819 DWORD uk4
; /* 0x18 */
820 DWORD size
; /* 0x1C */
821 nt_hbin_sub hbin_sub
; /* 0x20 */
825 * the value_list consists of offsets to the values (vk)
828 WORD SubBlockId
; /* 0x00 0x6B6E */
829 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
830 FILETIME writetime
; /* 0x04 */
831 DWORD uk1
; /* 0x0C */
832 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
833 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
834 DWORD uk8
; /* 0x18 */
835 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
836 DWORD uk2
; /* 0x20 */
837 DWORD nr_values
; /* 0x24 number of values */
838 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
839 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
840 DWORD off_class
; /* 0x30 Offset of the Class-Name */
841 DWORD uk3
; /* 0x34 */
842 DWORD uk4
; /* 0x38 */
843 DWORD uk5
; /* 0x3c */
844 DWORD uk6
; /* 0x40 */
845 DWORD uk7
; /* 0x44 */
846 WORD name_len
; /* 0x48 name-length */
847 WORD class_len
; /* 0x4a class-name length */
848 char name
[1]; /* 0x4c key-name */
852 DWORD off_nk
; /* 0x00 */
853 DWORD name
; /* 0x04 */
857 WORD id
; /* 0x00 0x666c */
858 WORD nr_keys
; /* 0x06 */
859 hash_rec hash_rec
[1];
863 list of subkeys without hash
870 WORD id
; /* 0x00 0x696c */
876 this is a intermediate node
887 WORD id
; /* 0x00 0x6972 */
888 WORD nr_li
; /* 0x02 number off offsets */
889 DWORD off_li
[1]; /* 0x04 points to li */
893 WORD id
; /* 0x00 'vk' */
907 * 0 value is a default value
908 * 1 the value has a name
911 * len of the whole data block
913 * bytes including the terminating \0 = 2*(number_of_chars+1)
914 * - reg_dword, reg_binary:
915 * if highest bit of data_len is set data_off contains the value
917 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
919 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
920 struct key_value value
;
922 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
923 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
927 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
928 value
.type
= vk
->type
;
929 value
.len
= (vk
->data_len
& 0x7fffffff);
930 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
932 _dump_value(&value
,f
);
938 /* it's called from _nt_dump_lf() */
939 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
944 * this structure contains the hash of a keyname and points to all
947 * exception: if the id is 'il' there are no hash values and every
950 static int _nt_dump_lf(LPCSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
954 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
955 if (subkeys
!= lf
->nr_keys
) goto error1
;
957 for (i
=0; i
<lf
->nr_keys
; i
++)
958 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
959 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
960 nt_li
* li
= (nt_li
*)lf
;
961 if (subkeys
!= li
->nr_keys
) goto error1
;
963 for (i
=0; i
<li
->nr_keys
; i
++)
964 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
965 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
966 nt_ri
* ri
= (nt_ri
*)lf
;
969 /* count all subkeys */
970 for (i
=0; i
<ri
->nr_li
; i
++) {
971 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
972 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
973 li_subkeys
+= li
->nr_keys
;
977 if (subkeys
!= li_subkeys
) goto error1
;
979 /* loop through the keys */
980 for (i
=0; i
<ri
->nr_li
; i
++) {
981 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
982 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
989 if (lf
->id
== 0x686c)
990 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
992 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
996 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
1000 ERR("error reading lf block\n");
1004 /* _nt_dump_nk [Internal] */
1005 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
1009 LPSTR new_key_name
= NULL
;
1011 TRACE("%s\n", key_name
);
1013 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
1014 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
1018 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
1019 ERR("registry file corrupt!\n");
1023 /* create the new key */
1025 /* create new subkey name */
1026 size_t len
= strlen(key_name
);
1027 new_key_name
= _xmalloc( len
+nk
->name_len
+2 );
1028 memcpy( new_key_name
, key_name
, len
);
1029 if (len
) new_key_name
[len
++] = '\\';
1030 memcpy( new_key_name
+ len
, nk
->name
, nk
->name_len
);
1031 new_key_name
[len
+ nk
->name_len
] = 0;
1033 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1034 1) key has some values
1035 2) key has no values and no subkeys
1037 if (nk
->nr_values
> 0) {
1038 /* there are some values */
1040 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1043 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
1044 /* no subkeys and no values */
1046 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1050 /* loop trough the value list */
1051 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
1052 for (n
=0; n
<nk
->nr_values
; n
++) {
1053 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
1054 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
1059 } else new_key_name
= _xstrdup(key_name
);
1061 /* loop through the subkeys */
1062 if (nk
->nr_subkeys
) {
1063 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
1064 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
1076 /**********************************************************************************
1077 * _set_registry_levels [Internal]
1079 * set level to 0 for loading system files
1080 * set level to 1 for loading user files
1082 static void _set_registry_levels(int level
,int saving
,int period
)
1084 SERVER_START_REQ( set_registry_levels
)
1086 req
->current
= level
;
1087 req
->saving
= saving
;
1088 req
->period
= period
;
1089 wine_server_call( req
);
1094 /* _save_at_exit [Internal] */
1095 static void _save_at_exit(HKEY hkey
,LPCSTR path
)
1097 LPCSTR confdir
= wine_get_config_dir();
1099 SERVER_START_REQ( save_registry_atexit
)
1102 wine_server_add_data( req
, confdir
, strlen(confdir
) );
1103 wine_server_add_data( req
, path
, strlen(path
)+1 );
1104 wine_server_call( req
);
1109 /******************************************************************************
1110 * _allocate_default_keys [Internal]
1111 * Registry initialisation, allocates some default keys.
1113 static void _allocate_default_keys(void)
1115 static const WCHAR StatDataW
[] = {'D','y','n','D','a','t','a','\\',
1116 'P','e','r','f','S','t','a','t','s','\\',
1117 'S','t','a','t','D','a','t','a',0};
1119 OBJECT_ATTRIBUTES attr
;
1120 UNICODE_STRING nameW
;
1124 attr
.Length
= sizeof(attr
);
1125 attr
.RootDirectory
= 0;
1126 attr
.ObjectName
= &nameW
;
1127 attr
.Attributes
= 0;
1128 attr
.SecurityDescriptor
= NULL
;
1129 attr
.SecurityQualityOfService
= NULL
;
1131 RtlInitUnicodeString( &nameW
, StatDataW
);
1132 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1135 static void get_windows_dir(WCHAR
* buffer
, unsigned len
)
1137 OBJECT_ATTRIBUTES attr
;
1138 UNICODE_STRING nameW
, keyW
;
1141 attr
.Length
= sizeof(attr
);
1142 attr
.RootDirectory
= 0;
1143 attr
.ObjectName
= &nameW
;
1144 attr
.Attributes
= 0;
1145 attr
.SecurityDescriptor
= NULL
;
1146 attr
.SecurityQualityOfService
= NULL
;
1148 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1150 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
1152 char tmp
[MAX_PATHNAME_LEN
*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1155 RtlCreateUnicodeStringFromAsciiz( &keyW
, "Windows");
1156 if (!NtQueryValueKey( hkey
, &keyW
, KeyValuePartialInformation
,
1157 tmp
, sizeof(tmp
), &count
))
1159 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1160 memcpy(buffer
, str
, min(((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->DataLength
, len
));
1162 RtlFreeUnicodeString( &keyW
);
1164 RtlFreeUnicodeString( &nameW
);
1169 #define REG_DONTLOAD -1
1174 /* return the type of native registry [Internal] */
1175 static int _get_reg_type(const WCHAR
* windir
)
1177 WCHAR tmp
[MAX_PATHNAME_LEN
];
1178 int ret
= REG_WIN31
;
1179 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};
1180 static const WCHAR win9x_reg_pathW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1182 /* test %windir%/system32/config/system --> winnt */
1183 strcpyW(tmp
, windir
);
1184 strcatW(tmp
, nt_reg_pathW
);
1185 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1189 /* test %windir%/system.dat --> win95 */
1190 strcpyW(tmp
, windir
);
1191 strcatW(tmp
, win9x_reg_pathW
);
1192 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1199 /* load the registry file in wine format [Internal] */
1200 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1203 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1204 FILE_ATTRIBUTE_NORMAL
, 0, TRUE
, DRIVE_UNKNOWN
)))
1206 SERVER_START_REQ( load_registry
)
1210 wine_server_call( req
);
1213 CloseHandle( file
);
1217 /* generate and return the name of the tmp file and associated stream [Internal] */
1218 static LPSTR
_get_tmp_fn(FILE **f
)
1225 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1226 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1227 if (errno
!= EEXIST
) {
1228 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1235 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1236 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1245 /* convert win95 native registry file to wine format [Internal] */
1246 static LPSTR
_convert_win95_registry_to_wine_format(LPCWSTR fn
, int level
)
1248 HANDLE hFile
, hMapping
;
1252 OBJECT_ATTRIBUTES attr
;
1253 LARGE_INTEGER lg_int
;
1259 _w95dke
*dke
, *root_dke
;
1261 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1262 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1264 attr
.Length
= sizeof(attr
);
1265 attr
.RootDirectory
= 0;
1266 attr
.ObjectName
= NULL
;
1267 attr
.Attributes
= 0;
1268 attr
.SecurityDescriptor
= NULL
;
1269 attr
.SecurityQualityOfService
= NULL
;
1271 lg_int
.QuadPart
= 0;
1272 nts
= NtCreateSection( &hMapping
,
1273 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1274 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1275 if (nts
!= STATUS_SUCCESS
) goto error1
;
1277 base
= NULL
; len
= 0;
1278 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1279 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1281 NtClose( hMapping
);
1282 if (nts
!= STATUS_SUCCESS
) goto error1
;
1284 /* control signature */
1285 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1286 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1292 /* load the header (rgkn) */
1293 rgkn
= (_w95rgkn
*)(creg
+ 1);
1294 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1295 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1298 if (rgkn
->root_off
!= 0x20) {
1299 ERR("rgkn->root_off not 0x20, please report !\n");
1302 if (rgkn
->last_dke
> rgkn
->size
)
1304 ERR("registry file corrupt! last_dke > size!\n");
1307 /* verify last dke */
1308 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1309 if (dke
->x1
!= 0x80000000)
1311 ERR("last dke invalid !\n");
1314 if (rgkn
->size
> creg
->rgdb_off
)
1316 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1319 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1320 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1322 ERR("registry file corrupt! invalid root dke !\n");
1326 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1327 fprintf(f
,"WINE REGISTRY Version 2");
1328 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1333 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn
));
1334 ERR("Please report this.\n");
1335 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1338 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1344 /* convert winnt native registry file to wine format [Internal] */
1345 static LPSTR
_convert_winnt_registry_to_wine_format(LPCWSTR fn
, int level
)
1352 OBJECT_ATTRIBUTES attr
;
1353 LARGE_INTEGER lg_int
;
1359 nt_hbin_sub
*hbin_sub
;
1362 TRACE("%s\n", debugstr_w(fn
));
1364 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1365 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1366 attr
.Length
= sizeof(attr
);
1367 attr
.RootDirectory
= 0;
1368 attr
.ObjectName
= NULL
;
1369 attr
.Attributes
= 0;
1370 attr
.SecurityDescriptor
= NULL
;
1371 attr
.SecurityQualityOfService
= NULL
;
1373 lg_int
.QuadPart
= 0;
1374 nts
= NtCreateSection( &hMapping
,
1375 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1376 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1377 if (nts
!= STATUS_SUCCESS
) goto error1
;
1379 base
= NULL
; len
= 0;
1380 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1381 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1383 NtClose( hMapping
);
1384 if (nts
!= STATUS_SUCCESS
) goto error1
;
1386 /* control signature */
1387 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1388 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1397 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1398 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1399 ERR( "hbin block invalid\n");
1403 /* hbin_sub block */
1404 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1405 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1406 ERR( "hbin_sub block invalid\n");
1411 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1412 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1413 ERR( "special nk block not found\n");
1417 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1418 fprintf(f
,"WINE REGISTRY Version 2");
1419 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1423 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1429 /* convert native registry to wine format and load it via server call [Internal] */
1430 static void _convert_and_load_native_registry(LPCWSTR fn
, HKEY hkey
, int reg_type
, int level
)
1436 /* FIXME: following function doesn't really convert yet */
1437 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1440 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1443 ERR("Don't know how to convert native 3.1 registry yet.\n");
1446 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1451 load_wine_registry(hkey
,tmp
);
1452 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1453 debugstr_w(fn
), tmp
);
1456 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn
));
1460 /* load all native windows registry files [Internal] */
1461 static void _load_windows_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1462 HKEY hkey_users_default
)
1465 WCHAR windir
[MAX_PATHNAME_LEN
];
1466 WCHAR path
[MAX_PATHNAME_LEN
];
1467 OBJECT_ATTRIBUTES attr
;
1468 UNICODE_STRING nameW
;
1469 HKEY hkey
, profile_key
;
1473 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
1474 'S','o','f','t','w','a','r','e','\\',
1475 'W','i','n','e','\\','W','i','n','e','\\',
1476 'C','o','n','f','i','g','\\','W','i','n','e',0};
1477 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1478 static const WCHAR System
[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1479 static const WCHAR Software
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1480 static const WCHAR Clone
[] = {'M','a','c','h','i','n','e','\\',
1481 'S','y','s','t','e','m','\\',
1482 'C','l','o','n','e',0};
1484 attr
.Length
= sizeof(attr
);
1485 attr
.RootDirectory
= 0;
1486 attr
.ObjectName
= &nameW
;
1487 attr
.Attributes
= 0;
1488 attr
.SecurityDescriptor
= NULL
;
1489 attr
.SecurityQualityOfService
= NULL
;
1491 RtlInitUnicodeString( &nameW
, WineW
);
1492 if (NtCreateKey( &profile_key
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) profile_key
= 0;
1494 get_windows_dir(windir
, sizeof(windir
));
1496 reg_type
= _get_reg_type(windir
);
1499 static const WCHAR ntuser_datW
[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1500 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};
1501 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};
1502 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};
1503 static const WCHAR samW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1504 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};
1506 /* user specific ntuser.dat */
1507 RtlInitUnicodeString( &nameW
, ProfileW
);
1508 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1509 tmp
, sizeof(tmp
), &dummy
))
1511 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1512 strcatW(path
, ntuser_datW
);
1513 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WINNT
,1);
1517 MESSAGE("When you are running with a native NT directory specify\n");
1518 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1519 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1523 /* default user.dat */
1524 if (hkey_users_default
) {
1525 strcpyW(path
, windir
);
1526 strcatW(path
, defaultW
);
1527 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1532 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1534 RtlInitUnicodeString( &nameW
, System
);
1535 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1537 strcpyW(path
, windir
);
1538 strcatW(path
, systemW
);
1539 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1542 RtlInitUnicodeString( &nameW
, Software
);
1543 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1545 strcpyW(path
, windir
);
1546 strcatW(path
, softwareW
);
1547 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1551 strcpyW(path
, windir
);
1552 strcatW(path
, samW
);
1553 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1555 strcpyW(path
,windir
);
1556 strcatW(path
, securityW
);
1557 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1559 /* this key is generated when the nt-core booted successfully */
1560 RtlInitUnicodeString( &nameW
, Clone
);
1561 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1567 static const WCHAR system_1stW
[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1568 static const WCHAR system_datW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1569 static const WCHAR classes_datW
[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1570 static const WCHAR user_datW
[] = {'\\','u','s','e','r','.','d','a','t',0};
1572 _convert_and_load_native_registry(system_1stW
,hkey_local_machine
,REG_WIN95
,0);
1574 strcpyW(path
, windir
);
1575 strcatW(path
, system_datW
);
1576 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WIN95
,0);
1578 RtlInitUnicodeString( &nameW
, ClassesRootW
);
1579 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1581 strcpyW(path
, windir
);
1582 strcatW(path
, classes_datW
);
1583 _convert_and_load_native_registry(path
,hkey
,REG_WIN95
,0);
1587 RtlInitUnicodeString( &nameW
, ProfileW
);
1588 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1589 tmp
, sizeof(tmp
), &dummy
))
1591 /* user specific user.dat */
1592 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1593 strcatW(path
, user_datW
);
1594 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1596 /* default user.dat */
1597 if (hkey_users_default
) {
1598 strcpyW(path
, windir
);
1599 strcatW(path
, user_datW
);
1600 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1603 strcpyW(path
, windir
);
1604 strcatW(path
, user_datW
);
1605 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1611 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1616 TRACE("REG_DONTLOAD\n");
1620 ERR("switch: no match (%d)\n",reg_type
);
1624 if (profile_key
) NtClose( profile_key
);
1627 /* load home registry files (stored in ~/.wine) [Internal] */
1628 static void _load_home_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1629 HKEY hkey_users_default
)
1631 LPCSTR confdir
= wine_get_config_dir();
1632 LPSTR tmp
= _xmalloc(strlen(confdir
)+20);
1634 strcpy(tmp
,confdir
);
1635 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1636 load_wine_registry(hkey_users_default
,tmp
);
1638 strcpy(tmp
,confdir
);
1639 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1640 load_wine_registry(hkey_current_user
,tmp
);
1642 strcpy(tmp
,confdir
);
1643 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1644 load_wine_registry(hkey_local_machine
,tmp
);
1650 /* load all registry (native and global and home) */
1651 void SHELL_LoadRegistry( void )
1653 HKEY hkey_local_machine
, hkey_users
, hkey_users_default
, hkey_current_user
, hkey_config
;
1654 OBJECT_ATTRIBUTES attr
;
1655 UNICODE_STRING nameW
;
1662 static const WCHAR MachineW
[] = {'M','a','c','h','i','n','e',0};
1663 static const WCHAR UserW
[] = {'U','s','e','r',0};
1664 static const WCHAR DefaultW
[] = {'.','D','e','f','a','u','l','t',0};
1665 static const WCHAR RegistryW
[] = {'M','a','c','h','i','n','e','\\',
1666 'S','o','f','t','w','a','r','e','\\',
1667 'W','i','n','e','\\',
1668 'W','i','n','e','\\',
1669 'C','o','n','f','i','g','\\',
1670 'R','e','g','i','s','t','r','y',0};
1671 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};
1672 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};
1673 static const WCHAR load_home_reg_filesW
[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1674 static const WCHAR SaveOnlyUpdatedKeysW
[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1675 static const WCHAR PeriodicSaveW
[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1676 static const WCHAR WritetoHomeRegistryFilesW
[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1677 static const WCHAR GlobalRegistryDirW
[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1681 attr
.Length
= sizeof(attr
);
1682 attr
.RootDirectory
= 0;
1683 attr
.ObjectName
= &nameW
;
1684 attr
.Attributes
= 0;
1685 attr
.SecurityDescriptor
= NULL
;
1686 attr
.SecurityQualityOfService
= NULL
;
1688 RtlInitUnicodeString( &nameW
, UserW
);
1689 NtCreateKey( &hkey_users
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &dispos
);
1690 if (dispos
== REG_OPENED_EXISTING_KEY
)
1692 /* someone else already loaded the registry */
1693 NtClose( hkey_users
);
1697 RtlInitUnicodeString( &nameW
, MachineW
);
1698 NtCreateKey( &hkey_local_machine
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
1700 attr
.RootDirectory
= hkey_users
;
1701 RtlInitUnicodeString( &nameW
, DefaultW
);
1702 if (NtCreateKey( &hkey_users_default
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1704 ERR("Cannot create HKEY_USERS/.Default\n" );
1707 RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey_current_user
);
1709 _set_registry_levels(0,0,0);
1710 _allocate_default_keys();
1712 attr
.RootDirectory
= 0;
1713 RtlInitUnicodeString( &nameW
, RegistryW
);
1714 if (NtOpenKey( &hkey_config
, KEY_ALL_ACCESS
, &attr
)) hkey_config
= 0;
1716 /* load windows registry if required */
1719 attr
.RootDirectory
= hkey_config
;
1720 RtlInitUnicodeString( &nameW
, load_win_reg_filesW
);
1721 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1723 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1724 res
= !IS_OPTION_FALSE(str
[0]);
1726 if (res
) _load_windows_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
1728 /* load global registry if required */
1731 RtlInitUnicodeString( &nameW
, load_global_reg_filesW
);
1732 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1734 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1735 res
= !IS_OPTION_FALSE(str
[0]);
1739 /* load global registry files (stored in /etc/wine) */
1740 char *p
, configfile
[MAX_PATHNAME_LEN
];
1742 /* Override ETCDIR? */
1744 RtlInitUnicodeString( &nameW
, GlobalRegistryDirW
);
1745 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1747 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1748 RtlUnicodeToMultiByteN( configfile
, sizeof(configfile
), NULL
,
1749 str
, (strlenW(str
) + 1) * sizeof(WCHAR
));
1751 if (configfile
[0] != '/') strcpy(configfile
, ETCDIR
);
1753 TRACE("GlobalRegistryDir is '%s'.\n", configfile
);
1755 /* Load the global HKU hive directly from sysconfdir */
1756 p
= configfile
+ strlen(configfile
);
1757 strcpy(p
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
1758 load_wine_registry( hkey_users
, configfile
);
1760 /* Load the global machine defaults directly from sysconfdir */
1761 strcpy(p
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
1762 load_wine_registry( hkey_local_machine
, configfile
);
1765 _set_registry_levels(1,0,0);
1767 /* load home registry if required */
1770 RtlInitUnicodeString( &nameW
, load_home_reg_filesW
);
1771 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1773 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1774 res
= !IS_OPTION_FALSE(str
[0]);
1776 if (res
) _load_home_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
1778 /* setup registry saving */
1781 RtlInitUnicodeString( &nameW
, SaveOnlyUpdatedKeysW
);
1782 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1784 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1785 all
= IS_OPTION_FALSE(str
[0]);
1789 RtlInitUnicodeString( &nameW
, PeriodicSaveW
);
1790 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1792 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1793 period
= (int)strtolW(str
, NULL
, 10);
1796 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1797 _set_registry_levels(1,!all
,period
*1000);
1799 /* setup keys to save */
1802 RtlInitUnicodeString( &nameW
, WritetoHomeRegistryFilesW
);
1803 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1805 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1806 res
= !IS_OPTION_FALSE(str
[0]);
1810 _save_at_exit(hkey_current_user
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1811 _save_at_exit(hkey_local_machine
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1812 _save_at_exit(hkey_users_default
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1815 NtClose(hkey_users_default
);
1816 NtClose(hkey_current_user
);
1817 NtClose(hkey_users
);
1818 NtClose(hkey_local_machine
);
1819 NtClose(hkey_config
);