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"
46 #include <sys/types.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
58 #include "wine/winbase16.h"
59 #include "wine/library.h"
60 #include "wine/server.h"
61 #include "wine/unicode.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
71 /* relative in ~user/.wine/ : */
72 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
73 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
74 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
76 static const WCHAR ClassesRootW
[] = {'M','a','c','h','i','n','e','\\',
77 'S','o','f','t','w','a','r','e','\\',
78 'C','l','a','s','s','e','s',0};
80 #define IS_OPTION_FALSE(ch) \
81 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
83 /* _xmalloc [Internal] */
84 static void *_xmalloc( size_t size
)
88 res
= malloc (size
? size
: 1);
90 WARN("Virtual memory exhausted.\n");
96 /* _xstrdup [Internal] */
97 static LPSTR
_xstrdup(LPCSTR str
)
100 size_t len
= strlen(str
) + 1;
102 if (!str
) return NULL
;
103 ret
= _xmalloc( len
);
104 memcpy( ret
, str
, len
);
108 /* convert ansi string to unicode [Internal] */
109 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
114 if (!strA
) return NULL
;
115 if (RtlMultiByteToUnicodeSize( &len
, strA
, lenA
) != STATUS_SUCCESS
) return NULL
;
117 ret
= _xmalloc(len
+sizeof(WCHAR
));
118 RtlMultiByteToUnicodeN(ret
, len
, NULL
, strA
, lenA
);
119 ret
[len
/ sizeof(WCHAR
)] = 0;
123 /* dump a Unicode string with proper escaping [Internal] */
124 /* FIXME: this code duplicates server/unicode.c */
125 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,char escape
[2])
127 static const char escapes
[32] = ".......abtnvfr.............e....";
132 for (; len
; str
++, len
--)
134 if (pos
> buffer
+ sizeof(buffer
) - 8)
136 fwrite( buffer
, pos
- buffer
, 1, f
);
137 count
+= pos
- buffer
;
140 if (*str
> 127) /* hex escape */
142 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
143 pos
+= sprintf( pos
, "\\x%04x", *str
);
145 pos
+= sprintf( pos
, "\\x%x", *str
);
148 if (*str
< 32) /* octal or C escape */
150 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
151 if (escapes
[*str
] != '.')
152 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
153 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
154 pos
+= sprintf( pos
, "\\%03o", *str
);
156 pos
+= sprintf( pos
, "\\%o", *str
);
159 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
162 fwrite( buffer
, pos
- buffer
, 1, f
);
163 count
+= pos
- buffer
;
167 /* convert ansi string to unicode and dump with proper escaping [Internal] */
168 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,char escape
[2])
173 if (strA
== NULL
) return 0;
174 strW
= _strdupnAtoW(strA
,len
);
175 ret
= _dump_strW(strW
,len
,f
,escape
);
181 /* FIXME: this code duplicates server/registry.c */
183 WCHAR
*nameW
; /* value name */
184 int type
; /* value type */
185 size_t len
; /* value data length in bytes */
186 void *data
; /* pointer to value data */
189 /* dump a value to a text file */
190 /* FIXME: this code duplicates server/registry.c */
191 static void _dump_value(struct key_value
*value
,FILE *f
)
195 if (value
->nameW
[0]) {
197 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
198 count
+= fprintf( f
, "\"=" );
200 else count
= fprintf( f
, "@=" );
202 switch(value
->type
) {
206 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
208 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
212 if (value
->len
== sizeof(DWORD
)) {
214 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
215 fprintf( f
, "dword:%08lx", dw
);
218 /* else fall through */
220 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
221 else count
+= fprintf( f
, "hex(%x):", value
->type
);
222 for (i
= 0; i
< value
->len
; i
++) {
223 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
224 if (i
< value
->len
-1) {
227 fprintf( f
, "\\\n " );
237 /******************************************************************/
238 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
240 reghack - windows 3.11 registry data format demo program.
242 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
243 a combined hash table and tree description, and finally a text table.
245 The header is obvious from the struct header. The taboff1 and taboff2
246 fields are always 0x20, and their usage is unknown.
248 The 8-byte entry table has various entry types.
250 tabent[0] is a root index. The second word has the index of the root of
252 tabent[1..hashsize] is a hash table. The first word in the hash entry is
253 the index of the key/value that has that hash. Data with the same
254 hash value are on a circular list. The other three words in the
255 hash entry are always zero.
256 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
257 entry: dirent and keyent/valent. They are identified by context.
258 tabent[freeidx] is the first free entry. The first word in a free entry
259 is the index of the next free entry. The last has 0 as a link.
260 The other three words in the free list are probably irrelevant.
262 Entries in text table are preceded by a word at offset-2. This word
263 has the value (2*index)+1, where index is the referring keyent/valent
264 entry in the table. I have no suggestion for the 2* and the +1.
265 Following the word, there are N bytes of data, as per the keyent/valent
266 entry length. The offset of the keyent/valent entry is from the start
267 of the text table to the first data byte.
269 This information is not available from Microsoft. The data format is
270 deduced from the reg.dat file by me. Mistakes may
271 have been made. I claim no rights and give no guarantees for this program.
273 Tor Sjøwall, tor@sn.no
276 /* reg.dat header format */
278 char cookie
[8]; /* 'SHCC3.10' */
279 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
280 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
281 unsigned long tabcnt
; /* number of entries in index table */
282 unsigned long textoff
; /* offset of text part */
283 unsigned long textsize
; /* byte size of text part */
284 unsigned short hashsize
; /* hash size */
285 unsigned short freeidx
; /* free index */
288 /* generic format of table entries */
290 unsigned short w0
, w1
, w2
, w3
;
293 /* directory tabent: */
295 unsigned short sibling_idx
; /* table index of sibling dirent */
296 unsigned short child_idx
; /* table index of child dirent */
297 unsigned short key_idx
; /* table index of key keyent */
298 unsigned short value_idx
; /* table index of value valent */
303 unsigned short hash_idx
; /* hash chain index for string */
304 unsigned short refcnt
; /* reference count */
305 unsigned short length
; /* length of string */
306 unsigned short string_off
; /* offset of string in text table */
311 unsigned short hash_idx
; /* hash chain index for string */
312 unsigned short refcnt
; /* reference count */
313 unsigned short length
; /* length of string */
314 unsigned short string_off
; /* offset of string in text table */
317 /* recursive helper function to display a directory tree [Internal] */
318 static void _w31_dumptree(unsigned short idx
, unsigned char *txt
,
319 struct _w31_tabent
*tab
, struct _w31_header
*head
,
320 HKEY hkey
, ULONG lastmodified
, int level
)
322 static const WCHAR classesW
[] = {'.','c','l','a','s','s','e','s',0};
323 struct _w31_dirent
*dir
;
324 struct _w31_keyent
*key
;
325 struct _w31_valent
*val
;
327 OBJECT_ATTRIBUTES attr
;
328 UNICODE_STRING nameW
, valueW
;
329 static WCHAR tail
[400];
331 attr
.Length
= sizeof(attr
);
332 attr
.RootDirectory
= hkey
;
333 attr
.ObjectName
= &nameW
;
335 attr
.SecurityDescriptor
= NULL
;
336 attr
.SecurityQualityOfService
= NULL
;
337 RtlInitUnicodeString( &valueW
, NULL
);
340 dir
=(struct _w31_dirent
*)&tab
[idx
];
344 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
346 RtlMultiByteToUnicodeN( tail
, sizeof(tail
)-sizeof(WCHAR
), &len
,
347 &txt
[key
->string_off
], key
->length
);
348 tail
[len
/sizeof(WCHAR
)] = 0;
350 /* all toplevel entries AND the entries in the
351 * toplevel subdirectory belong to \SOFTWARE\Classes
353 if (!level
&& !strcmpW(tail
,classesW
))
355 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
356 idx
=dir
->sibling_idx
;
360 if (subkey
) NtClose( subkey
);
361 RtlInitUnicodeString( &nameW
, tail
);
362 if (NtCreateKey( &subkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) subkey
= 0;
364 /* only add if leaf node or valued node */
365 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
366 if (dir
->value_idx
) {
368 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
369 RtlMultiByteToUnicodeN( tail
, sizeof(tail
) - sizeof(WCHAR
), &len
,
370 &txt
[val
->string_off
], val
->length
);
371 tail
[len
/sizeof(WCHAR
)] = 0;
372 NtSetValueKey( subkey
, &valueW
, 0, REG_SZ
, tail
, len
+ sizeof(WCHAR
) );
375 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
376 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
377 idx
=dir
->sibling_idx
;
379 if (subkey
) NtClose( subkey
);
383 /******************************************************************************
384 * _w31_loadreg [Internal]
386 static void _w31_loadreg(void)
390 OBJECT_ATTRIBUTES attr
;
391 UNICODE_STRING nameW
;
392 struct _w31_header head
;
393 struct _w31_tabent
* tab
= NULL
;
394 unsigned char* txt
= NULL
;
399 IO_STATUS_BLOCK iosb
;
400 FILE_POSITION_INFORMATION fpi
;
401 FILE_BASIC_INFORMATION fbi
;
405 hf
= (HANDLE
)OpenFile("reg.dat",&ofs
,OF_READ
);
406 if (hf
==(HANDLE
)HFILE_ERROR
) return;
408 /* read & dump header */
409 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
410 &head
, sizeof(head
), NULL
, NULL
) != STATUS_SUCCESS
||
411 iosb
.Information
!= sizeof(head
))
413 ERR("reg.dat is too short.\n");
416 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
)) != 0)
418 ERR("reg.dat has bad signature.\n");
422 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
423 /* read and dump index table */
425 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
426 tab
, len
, NULL
, NULL
) != STATUS_SUCCESS
||
427 iosb
.Information
!= len
)
429 ERR("couldn't read index table (%d bytes).\n",len
);
434 txt
= _xmalloc(head
.textsize
);
435 fpi
.CurrentByteOffset
.s
.LowPart
= head
.textoff
;
436 fpi
.CurrentByteOffset
.s
.HighPart
= 0;
437 if (NtSetInformationFile(hf
, &iosb
, &fpi
, sizeof(fpi
),
438 FilePositionInformation
) != STATUS_SUCCESS
)
440 ERR("couldn't seek to textblock.\n");
443 status
= NtReadFile(hf
, 0, NULL
, NULL
, &iosb
, txt
, head
.textsize
, NULL
, NULL
);
444 if (!(status
== STATUS_SUCCESS
|| status
== STATUS_END_OF_FILE
) ||
445 iosb
.Information
!= head
.textsize
)
447 ERR("textblock too short (%d instead of %ld).\n", len
, head
.textsize
);
450 if (NtQueryInformationFile(hf
, &iosb
, &fbi
, sizeof(fbi
),
451 FileBasicInformation
) != STATUS_SUCCESS
)
453 ERR("Couldn't get basic information.\n");
456 RtlTimeToSecondsSince1970(&fbi
.LastWriteTime
, &lastmodified
);
458 attr
.Length
= sizeof(attr
);
459 attr
.RootDirectory
= 0;
460 attr
.ObjectName
= &nameW
;
462 attr
.SecurityDescriptor
= NULL
;
463 attr
.SecurityQualityOfService
= NULL
;
464 RtlInitUnicodeString( &nameW
, ClassesRootW
);
466 if (!NtCreateKey( &root
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
468 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,root
,lastmodified
,0);
478 /***********************************************************************************/
479 /* windows 95 registry loader */
480 /***********************************************************************************/
482 /* SECTION 1: main header
486 #define W95_REG_CREG_ID 0x47455243
489 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
490 DWORD version
; /* ???? 0x00010000 */
491 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
492 DWORD uk2
; /* 0x0c */
493 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
499 /* SECTION 2: Directory information (tree structure)
501 * once on offset 0x20
503 * structure: [rgkn][dke]* (repeat till last_dke is reached)
505 #define W95_REG_RGKN_ID 0x4e4b4752
508 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
509 DWORD size
; /* Size of the RGKN-block */
510 DWORD root_off
; /* Rel. Offset of the root-record */
511 DWORD last_dke
; /* Offset to last DKE ? */
515 /* Disk Key Entry Structure
517 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
518 * hive itself. It looks the same like other keys. Even the ID-number can
521 * The "hash"-value is a value representing the key's name. Windows will not
522 * search for the name, but for a matching hash-value. if it finds one, it
523 * will compare the actual string info, otherwise continue with the next key.
524 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
525 * of the string which are smaller than 0x80 (128) to this D-Word.
527 * If you want to modify key names, also modify the hash-values, since they
528 * cannot be found again (although they would be displayed in REGEDIT)
529 * End of list-pointers are filled with 0xFFFFFFFF
531 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
532 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
533 * structure) and reading another RGDB_section.
535 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
536 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
537 * The remaining space between last_dke and the offset calculated from
538 * rgkn->size seems to be free for use for more dke:s.
539 * So it seems if more dke:s are added, they are added to that space and
540 * last_dke is grown, and in case that "free" space is out, the space
541 * gets grown and rgkn->size gets adjusted.
543 * there is a one to one relationship between dke and dkh
545 /* key struct, once per key */
547 DWORD x1
; /* Free entry indicator(?) */
548 DWORD hash
; /* sum of bytes of keyname */
549 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
550 DWORD prevlvl
; /* offset of previous key */
551 DWORD nextsub
; /* offset of child key */
552 DWORD next
; /* offset of sibling key */
553 WORD nrLS
; /* id inside the rgdb block */
554 WORD nrMS
; /* number of the rgdb block */
557 /* SECTION 3: key information, values and data
560 * section: [blocks]* (repeat creg->rgdb_num times)
561 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
562 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
564 * An interesting relationship exists in RGDB_section. The DWORD value
565 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
566 * I have no idea at the moment what this means. (Kevin Cozens)
569 /* block header, once per block */
570 #define W95_REG_RGDB_ID 0x42444752
573 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
574 DWORD size
; /* 0x04 */
575 DWORD uk1
; /* 0x08 */
576 DWORD uk2
; /* 0x0c */
577 DWORD uk3
; /* 0x10 */
578 DWORD uk4
; /* 0x14 */
579 DWORD uk5
; /* 0x18 */
580 DWORD uk6
; /* 0x1c */
584 /* Disk Key Header structure (RGDB part), once per key */
586 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
587 WORD nrLS
; /* 0x04 id inside the rgdb block */
588 WORD nrMS
; /* 0x06 number of the rgdb block */
589 DWORD bytesused
; /* 0x08 */
590 WORD keynamelen
; /* 0x0c len of name */
591 WORD values
; /* 0x0e number of values */
592 DWORD xx1
; /* 0x10 */
593 char name
[1]; /* 0x14 */
594 /* dkv */ /* 0x14 + keynamelen */
597 /* Disk Key Value structure, once per value */
599 DWORD type
; /* 0x00 */
601 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
602 WORD valdatalen
; /* 0x0A length of data */
603 char name
[1]; /* 0x0c */
604 /* raw data */ /* 0x0c + valnamelen */
607 /******************************************************************************
608 * _w95_lookup_dkh [Internal]
610 * seeks the dkh belonging to a dke
612 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
618 /* get the beginning of the rgdb datastore */
619 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
621 /* check: requested block < last_block) */
622 if (creg
->rgdb_num
<= nrMS
) {
623 ERR("registry file corrupt! requested block no. beyond end.\n");
627 /* find the right block */
628 for(i
=0; i
<nrMS
;i
++) {
629 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
630 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
633 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
636 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
639 if(nrLS
==dkh
->nrLS
) return dkh
;
640 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
641 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
647 /******************************************************************************
648 * _w95_dump_dkv [Internal]
650 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
655 /* first value block */
656 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
658 /* loop through the values */
659 for (i
=0; i
< dkh
->values
; i
++) {
660 struct key_value value
;
663 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
664 value
.type
= dkv
->type
;
665 value
.len
= dkv
->valdatalen
;
667 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
669 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
670 pdata
= _strdupnAtoW(value
.data
,value
.len
);
673 if (pdata
!= NULL
) value
.data
= pdata
;
675 _dump_value(&value
,f
);
677 if (pdata
!= NULL
) free(pdata
);
680 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
685 /******************************************************************************
686 * _w95_dump_dke [Internal]
688 static int _w95_dump_dke(LPSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
691 LPSTR new_key_name
= NULL
;
693 /* special root key */
694 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
696 /* parse the one subkey */
697 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
698 /* has no sibling keys */
702 /* search subblock */
703 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
704 ERR("dke pointing to missing dkh !\n");
709 /* create new subkey name */
710 size_t len
= strlen(key_name
);
711 new_key_name
= _xmalloc(len
+dkh
->keynamelen
+2);
712 memcpy( new_key_name
, key_name
, len
);
713 if (len
) new_key_name
[len
++] = '\\';
714 memcpy( new_key_name
+ len
, dkh
->name
, dkh
->keynamelen
);
715 new_key_name
[len
+ dkh
->keynamelen
] = 0;
717 /* walk sibling keys */
718 if (dke
->next
!= 0xffffffff ) {
719 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
725 /* write the key path (something like [Software\\Microsoft\\..]) only if:
726 1) key has some values
727 2) key has no values and no subkeys
729 if (dkh
->values
> 0) {
730 /* there are some values */
732 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
734 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
739 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
740 /* no subkeys and no values */
742 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
745 } else new_key_name
= _xstrdup(key_name
);
748 if (dke
->nextsub
!= 0xffffffff) {
749 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
758 /* end windows 95 loader */
760 /***********************************************************************************/
761 /* windows NT registry loader */
762 /***********************************************************************************/
764 /* NT REGISTRY LOADER */
766 #ifdef HAVE_SYS_MMAN_H
767 # include <sys/mman.h>
771 #define MAP_FAILED ((LPVOID)-1)
774 #define NT_REG_BLOCK_SIZE 0x1000
776 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
777 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
778 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
779 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
781 /* subblocks of nk */
782 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
783 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
784 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
786 #define NT_REG_KEY_BLOCK_TYPE 0x20
787 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
790 DWORD id
; /* 0x66676572 'regf'*/
791 DWORD uk1
; /* 0x04 */
792 DWORD uk2
; /* 0x08 */
793 FILETIME DateModified
; /* 0x0c */
794 DWORD uk3
; /* 0x14 */
795 DWORD uk4
; /* 0x18 */
796 DWORD uk5
; /* 0x1c */
797 DWORD uk6
; /* 0x20 */
798 DWORD RootKeyBlock
; /* 0x24 */
799 DWORD BlockSize
; /* 0x28 */
801 DWORD Checksum
; /* at offset 0x1FC */
810 DWORD id
; /* 0x6E696268 'hbin' */
814 DWORD uk2
; /* 0x10 */
815 DWORD uk3
; /* 0x14 */
816 DWORD uk4
; /* 0x18 */
817 DWORD size
; /* 0x1C */
818 nt_hbin_sub hbin_sub
; /* 0x20 */
822 * the value_list consists of offsets to the values (vk)
825 WORD SubBlockId
; /* 0x00 0x6B6E */
826 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
827 FILETIME writetime
; /* 0x04 */
828 DWORD uk1
; /* 0x0C */
829 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
830 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
831 DWORD uk8
; /* 0x18 */
832 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
833 DWORD uk2
; /* 0x20 */
834 DWORD nr_values
; /* 0x24 number of values */
835 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
836 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
837 DWORD off_class
; /* 0x30 Offset of the Class-Name */
838 DWORD uk3
; /* 0x34 */
839 DWORD uk4
; /* 0x38 */
840 DWORD uk5
; /* 0x3c */
841 DWORD uk6
; /* 0x40 */
842 DWORD uk7
; /* 0x44 */
843 WORD name_len
; /* 0x48 name-length */
844 WORD class_len
; /* 0x4a class-name length */
845 char name
[1]; /* 0x4c key-name */
849 DWORD off_nk
; /* 0x00 */
850 DWORD name
; /* 0x04 */
854 WORD id
; /* 0x00 0x666c */
855 WORD nr_keys
; /* 0x06 */
856 hash_rec hash_rec
[1];
860 list of subkeys without hash
867 WORD id
; /* 0x00 0x696c */
873 this is a intermediate node
884 WORD id
; /* 0x00 0x6972 */
885 WORD nr_li
; /* 0x02 number off offsets */
886 DWORD off_li
[1]; /* 0x04 points to li */
890 WORD id
; /* 0x00 'vk' */
904 * 0 value is a default value
905 * 1 the value has a name
908 * len of the whole data block
910 * bytes including the terminating \0 = 2*(number_of_chars+1)
911 * - reg_dword, reg_binary:
912 * if highest bit of data_len is set data_off contains the value
914 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
916 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
917 struct key_value value
;
919 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
920 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
924 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
925 value
.type
= vk
->type
;
926 value
.len
= (vk
->data_len
& 0x7fffffff);
927 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
929 _dump_value(&value
,f
);
935 /* it's called from _nt_dump_lf() */
936 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
941 * this structure contains the hash of a keyname and points to all
944 * exception: if the id is 'il' there are no hash values and every
947 static int _nt_dump_lf(LPSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
951 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
952 if (subkeys
!= lf
->nr_keys
) goto error1
;
954 for (i
=0; i
<lf
->nr_keys
; i
++)
955 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
956 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
957 nt_li
* li
= (nt_li
*)lf
;
958 if (subkeys
!= li
->nr_keys
) goto error1
;
960 for (i
=0; i
<li
->nr_keys
; i
++)
961 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
962 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
963 nt_ri
* ri
= (nt_ri
*)lf
;
966 /* count all subkeys */
967 for (i
=0; i
<ri
->nr_li
; i
++) {
968 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
969 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
970 li_subkeys
+= li
->nr_keys
;
974 if (subkeys
!= li_subkeys
) goto error1
;
976 /* loop through the keys */
977 for (i
=0; i
<ri
->nr_li
; i
++) {
978 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
979 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
986 if (lf
->id
== 0x686c)
987 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
989 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
993 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
997 ERR("error reading lf block\n");
1001 /* _nt_dump_nk [Internal] */
1002 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
1006 LPSTR new_key_name
= NULL
;
1008 TRACE("%s\n", key_name
);
1010 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
1011 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
1015 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
1016 ERR("registry file corrupt!\n");
1020 /* create the new key */
1022 /* create new subkey name */
1023 size_t len
= strlen(key_name
);
1024 new_key_name
= _xmalloc( len
+nk
->name_len
+2 );
1025 memcpy( new_key_name
, key_name
, len
);
1026 if (len
) new_key_name
[len
++] = '\\';
1027 memcpy( new_key_name
+ len
, nk
->name
, nk
->name_len
);
1028 new_key_name
[len
+ nk
->name_len
] = 0;
1030 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1031 1) key has some values
1032 2) key has no values and no subkeys
1034 if (nk
->nr_values
> 0) {
1035 /* there are some values */
1037 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1040 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
1041 /* no subkeys and no values */
1043 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1047 /* loop trough the value list */
1048 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
1049 for (n
=0; n
<nk
->nr_values
; n
++) {
1050 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
1051 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
1056 } else new_key_name
= _xstrdup(key_name
);
1058 /* loop through the subkeys */
1059 if (nk
->nr_subkeys
) {
1060 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
1061 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
1073 /**********************************************************************************
1074 * _set_registry_levels [Internal]
1076 * set level to 0 for loading system files
1077 * set level to 1 for loading user files
1079 static void _set_registry_levels(int level
,int saving
,int period
)
1081 SERVER_START_REQ( set_registry_levels
)
1083 req
->current
= level
;
1084 req
->saving
= saving
;
1085 req
->period
= period
;
1086 wine_server_call( req
);
1091 /* _save_at_exit [Internal] */
1092 static void _save_at_exit(HKEY hkey
,LPCSTR path
)
1094 LPCSTR confdir
= wine_get_config_dir();
1096 SERVER_START_REQ( save_registry_atexit
)
1099 wine_server_add_data( req
, confdir
, strlen(confdir
) );
1100 wine_server_add_data( req
, path
, strlen(path
)+1 );
1101 wine_server_call( req
);
1106 /******************************************************************************
1107 * _allocate_default_keys [Internal]
1108 * Registry initialisation, allocates some default keys.
1110 static void _allocate_default_keys(void)
1112 static const WCHAR StatDataW
[] = {'D','y','n','D','a','t','a','\\',
1113 'P','e','r','f','S','t','a','t','s','\\',
1114 'S','t','a','t','D','a','t','a',0};
1116 OBJECT_ATTRIBUTES attr
;
1117 UNICODE_STRING nameW
;
1121 attr
.Length
= sizeof(attr
);
1122 attr
.RootDirectory
= 0;
1123 attr
.ObjectName
= &nameW
;
1124 attr
.Attributes
= 0;
1125 attr
.SecurityDescriptor
= NULL
;
1126 attr
.SecurityQualityOfService
= NULL
;
1128 RtlInitUnicodeString( &nameW
, StatDataW
);
1129 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1132 static void get_windows_dir(WCHAR
* buffer
, unsigned len
)
1134 OBJECT_ATTRIBUTES attr
;
1135 UNICODE_STRING nameW
, keyW
;
1138 attr
.Length
= sizeof(attr
);
1139 attr
.RootDirectory
= 0;
1140 attr
.ObjectName
= &nameW
;
1141 attr
.Attributes
= 0;
1142 attr
.SecurityDescriptor
= NULL
;
1143 attr
.SecurityQualityOfService
= NULL
;
1145 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1147 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
1149 char tmp
[MAX_PATHNAME_LEN
*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1152 RtlCreateUnicodeStringFromAsciiz( &keyW
, "Windows");
1153 if (!NtQueryValueKey( hkey
, &keyW
, KeyValuePartialInformation
,
1154 tmp
, sizeof(tmp
), &count
))
1156 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1157 memcpy(buffer
, str
, min(((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->DataLength
, len
));
1159 RtlFreeUnicodeString( &keyW
);
1161 RtlFreeUnicodeString( &nameW
);
1166 #define REG_DONTLOAD -1
1171 /* return the type of native registry [Internal] */
1172 static int _get_reg_type(const WCHAR
* windir
)
1174 WCHAR tmp
[MAX_PATHNAME_LEN
];
1175 int ret
= REG_WIN31
;
1176 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};
1177 static const WCHAR win9x_reg_pathW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1179 /* test %windir%/system32/config/system --> winnt */
1180 strcpyW(tmp
, windir
);
1181 strcatW(tmp
, nt_reg_pathW
);
1182 if(GetFileAttributesW(tmp
) != (DWORD
)-1)
1186 /* test %windir%/system.dat --> win95 */
1187 strcpyW(tmp
, windir
);
1188 strcatW(tmp
, win9x_reg_pathW
);
1189 if(GetFileAttributesW(tmp
) != (DWORD
)-1)
1196 /* load the registry file in wine format [Internal] */
1197 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1200 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1201 FILE_ATTRIBUTE_NORMAL
, 0, TRUE
, DRIVE_UNKNOWN
)))
1203 SERVER_START_REQ( load_registry
)
1207 wine_server_call( req
);
1210 CloseHandle( file
);
1214 /* generate and return the name of the tmp file and associated stream [Internal] */
1215 static LPSTR
_get_tmp_fn(FILE **f
)
1222 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1223 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1224 if (errno
!= EEXIST
) {
1225 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1232 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1233 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1242 /* convert win95 native registry file to wine format [Internal] */
1243 static LPSTR
_convert_win95_registry_to_wine_format(LPCWSTR fn
, int level
)
1245 HANDLE hFile
, hMapping
;
1249 OBJECT_ATTRIBUTES attr
;
1250 LARGE_INTEGER lg_int
;
1256 _w95dke
*dke
, *root_dke
;
1258 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1259 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1261 attr
.Length
= sizeof(attr
);
1262 attr
.RootDirectory
= 0;
1263 attr
.ObjectName
= NULL
;
1264 attr
.Attributes
= 0;
1265 attr
.SecurityDescriptor
= NULL
;
1266 attr
.SecurityQualityOfService
= NULL
;
1268 lg_int
.QuadPart
= 0;
1269 nts
= NtCreateSection( &hMapping
,
1270 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1271 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1272 if (nts
!= STATUS_SUCCESS
) goto error1
;
1274 base
= NULL
; len
= 0;
1275 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1276 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1278 NtClose( hMapping
);
1279 if (nts
!= STATUS_SUCCESS
) goto error1
;
1281 /* control signature */
1282 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1283 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1289 /* load the header (rgkn) */
1290 rgkn
= (_w95rgkn
*)(creg
+ 1);
1291 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1292 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1295 if (rgkn
->root_off
!= 0x20) {
1296 ERR("rgkn->root_off not 0x20, please report !\n");
1299 if (rgkn
->last_dke
> rgkn
->size
)
1301 ERR("registry file corrupt! last_dke > size!\n");
1304 /* verify last dke */
1305 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1306 if (dke
->x1
!= 0x80000000)
1308 ERR("last dke invalid !\n");
1311 if (rgkn
->size
> creg
->rgdb_off
)
1313 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1316 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1317 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1319 ERR("registry file corrupt! invalid root dke !\n");
1323 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1324 fprintf(f
,"WINE REGISTRY Version 2");
1325 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1330 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn
));
1331 ERR("Please report this.\n");
1332 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1335 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1341 /* convert winnt native registry file to wine format [Internal] */
1342 static LPSTR
_convert_winnt_registry_to_wine_format(LPCWSTR fn
, int level
)
1349 OBJECT_ATTRIBUTES attr
;
1350 LARGE_INTEGER lg_int
;
1356 nt_hbin_sub
*hbin_sub
;
1359 TRACE("%s\n", debugstr_w(fn
));
1361 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1362 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1363 attr
.Length
= sizeof(attr
);
1364 attr
.RootDirectory
= 0;
1365 attr
.ObjectName
= NULL
;
1366 attr
.Attributes
= 0;
1367 attr
.SecurityDescriptor
= NULL
;
1368 attr
.SecurityQualityOfService
= NULL
;
1370 lg_int
.QuadPart
= 0;
1371 nts
= NtCreateSection( &hMapping
,
1372 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1373 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1374 if (nts
!= STATUS_SUCCESS
) goto error1
;
1376 base
= NULL
; len
= 0;
1377 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1378 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1380 NtClose( hMapping
);
1381 if (nts
!= STATUS_SUCCESS
) goto error1
;
1383 /* control signature */
1384 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1385 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1394 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1395 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1396 ERR( "hbin block invalid\n");
1400 /* hbin_sub block */
1401 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1402 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1403 ERR( "hbin_sub block invalid\n");
1408 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1409 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1410 ERR( "special nk block not found\n");
1414 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1415 fprintf(f
,"WINE REGISTRY Version 2");
1416 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1420 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1426 /* convert native registry to wine format and load it via server call [Internal] */
1427 static void _convert_and_load_native_registry(LPCWSTR fn
, HKEY hkey
, int reg_type
, int level
)
1433 /* FIXME: following function doesn't really convert yet */
1434 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1437 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1440 ERR("Don't know how to convert native 3.1 registry yet.\n");
1443 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1448 load_wine_registry(hkey
,tmp
);
1449 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1450 debugstr_w(fn
), tmp
);
1453 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn
));
1457 /* load all native windows registry files [Internal] */
1458 static void _load_windows_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1459 HKEY hkey_users_default
)
1462 WCHAR windir
[MAX_PATHNAME_LEN
];
1463 WCHAR path
[MAX_PATHNAME_LEN
];
1464 OBJECT_ATTRIBUTES attr
;
1465 UNICODE_STRING nameW
;
1466 HKEY hkey
, profile_key
;
1470 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
1471 'S','o','f','t','w','a','r','e','\\',
1472 'W','i','n','e','\\','W','i','n','e','\\',
1473 'C','o','n','f','i','g','\\','W','i','n','e',0};
1474 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1475 static const WCHAR System
[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1476 static const WCHAR Software
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1477 static const WCHAR Clone
[] = {'M','a','c','h','i','n','e','\\',
1478 'S','y','s','t','e','m','\\',
1479 'C','l','o','n','e',0};
1481 attr
.Length
= sizeof(attr
);
1482 attr
.RootDirectory
= 0;
1483 attr
.ObjectName
= &nameW
;
1484 attr
.Attributes
= 0;
1485 attr
.SecurityDescriptor
= NULL
;
1486 attr
.SecurityQualityOfService
= NULL
;
1488 RtlInitUnicodeString( &nameW
, WineW
);
1489 if (NtCreateKey( &profile_key
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) profile_key
= 0;
1491 get_windows_dir(windir
, sizeof(windir
));
1493 reg_type
= _get_reg_type(windir
);
1496 static const WCHAR ntuser_datW
[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1497 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};
1498 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};
1499 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};
1500 static const WCHAR samW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1501 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};
1503 /* user specific ntuser.dat */
1504 RtlInitUnicodeString( &nameW
, ProfileW
);
1505 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1506 tmp
, sizeof(tmp
), &dummy
))
1508 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1509 strcatW(path
, ntuser_datW
);
1510 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WINNT
,1);
1514 MESSAGE("When you are running with a native NT directory specify\n");
1515 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1516 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1520 /* default user.dat */
1521 if (hkey_users_default
) {
1522 strcpyW(path
, windir
);
1523 strcatW(path
, defaultW
);
1524 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1529 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1531 RtlInitUnicodeString( &nameW
, System
);
1532 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1534 strcpyW(path
, windir
);
1535 strcatW(path
, systemW
);
1536 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1539 RtlInitUnicodeString( &nameW
, Software
);
1540 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1542 strcpyW(path
, windir
);
1543 strcatW(path
, softwareW
);
1544 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1548 strcpyW(path
, windir
);
1549 strcatW(path
, samW
);
1550 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1552 strcpyW(path
,windir
);
1553 strcatW(path
, securityW
);
1554 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1556 /* this key is generated when the nt-core booted successfully */
1557 RtlInitUnicodeString( &nameW
, Clone
);
1558 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1564 static const WCHAR system_1stW
[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1565 static const WCHAR system_datW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1566 static const WCHAR classes_datW
[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1567 static const WCHAR user_datW
[] = {'\\','u','s','e','r','.','d','a','t',0};
1569 _convert_and_load_native_registry(system_1stW
,hkey_local_machine
,REG_WIN95
,0);
1571 strcpyW(path
, windir
);
1572 strcatW(path
, system_datW
);
1573 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WIN95
,0);
1575 RtlInitUnicodeString( &nameW
, ClassesRootW
);
1576 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1578 strcpyW(path
, windir
);
1579 strcatW(path
, classes_datW
);
1580 _convert_and_load_native_registry(path
,hkey
,REG_WIN95
,0);
1584 RtlInitUnicodeString( &nameW
, ProfileW
);
1585 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1586 tmp
, sizeof(tmp
), &dummy
))
1588 /* user specific user.dat */
1589 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1590 strcatW(path
, user_datW
);
1591 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1593 /* default user.dat */
1594 if (hkey_users_default
) {
1595 strcpyW(path
, windir
);
1596 strcatW(path
, user_datW
);
1597 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1600 strcpyW(path
, windir
);
1601 strcatW(path
, user_datW
);
1602 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1608 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1613 TRACE("REG_DONTLOAD\n");
1617 ERR("switch: no match (%d)\n",reg_type
);
1621 if (profile_key
) NtClose( profile_key
);
1624 /* load home registry files (stored in ~/.wine) [Internal] */
1625 static void _load_home_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1626 HKEY hkey_users_default
)
1628 LPCSTR confdir
= wine_get_config_dir();
1629 LPSTR tmp
= _xmalloc(strlen(confdir
)+20);
1631 strcpy(tmp
,confdir
);
1632 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1633 load_wine_registry(hkey_users_default
,tmp
);
1635 strcpy(tmp
,confdir
);
1636 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1637 load_wine_registry(hkey_current_user
,tmp
);
1639 strcpy(tmp
,confdir
);
1640 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1641 load_wine_registry(hkey_local_machine
,tmp
);
1647 /* load all registry (native and global and home) */
1648 void SHELL_LoadRegistry( void )
1650 HKEY hkey_local_machine
, hkey_users
, hkey_users_default
, hkey_current_user
, hkey_config
;
1651 OBJECT_ATTRIBUTES attr
;
1652 UNICODE_STRING nameW
;
1658 static const WCHAR MachineW
[] = {'M','a','c','h','i','n','e',0};
1659 static const WCHAR UserW
[] = {'U','s','e','r',0};
1660 static const WCHAR DefaultW
[] = {'.','D','e','f','a','u','l','t',0};
1661 static const WCHAR RegistryW
[] = {'M','a','c','h','i','n','e','\\',
1662 'S','o','f','t','w','a','r','e','\\',
1663 'W','i','n','e','\\',
1664 'W','i','n','e','\\',
1665 'C','o','n','f','i','g','\\',
1666 'R','e','g','i','s','t','r','y',0};
1667 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};
1668 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};
1669 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};
1670 static const WCHAR SaveOnlyUpdatedKeysW
[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1671 static const WCHAR PeriodicSaveW
[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1672 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};
1673 static const WCHAR GlobalRegistryDirW
[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1677 if (!CLIENT_IsBootThread()) return; /* already loaded */
1679 attr
.Length
= sizeof(attr
);
1680 attr
.RootDirectory
= 0;
1681 attr
.ObjectName
= &nameW
;
1682 attr
.Attributes
= 0;
1683 attr
.SecurityDescriptor
= NULL
;
1684 attr
.SecurityQualityOfService
= NULL
;
1686 RtlInitUnicodeString( &nameW
, MachineW
);
1687 NtCreateKey( &hkey_local_machine
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
1688 RtlInitUnicodeString( &nameW
, UserW
);
1689 NtCreateKey( &hkey_users
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
1691 attr
.RootDirectory
= hkey_users
;
1692 RtlInitUnicodeString( &nameW
, DefaultW
);
1693 if (NtCreateKey( &hkey_users_default
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1695 ERR("Cannot create HKEY_USERS/.Default\n" );
1698 RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey_current_user
);
1700 _set_registry_levels(0,0,0);
1701 _allocate_default_keys();
1703 attr
.RootDirectory
= 0;
1704 RtlInitUnicodeString( &nameW
, RegistryW
);
1705 if (NtOpenKey( &hkey_config
, KEY_ALL_ACCESS
, &attr
)) hkey_config
= 0;
1707 /* load windows registry if required */
1710 attr
.RootDirectory
= hkey_config
;
1711 RtlInitUnicodeString( &nameW
, load_win_reg_filesW
);
1712 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1714 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1715 res
= !IS_OPTION_FALSE(str
[0]);
1717 if (res
) _load_windows_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
1719 /* load global registry if required */
1722 RtlInitUnicodeString( &nameW
, load_global_reg_filesW
);
1723 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1725 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1726 res
= !IS_OPTION_FALSE(str
[0]);
1730 /* load global registry files (stored in /etc/wine) */
1731 char *p
, configfile
[MAX_PATHNAME_LEN
];
1733 /* Override ETCDIR? */
1735 RtlInitUnicodeString( &nameW
, GlobalRegistryDirW
);
1736 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1738 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1739 RtlUnicodeToMultiByteN( configfile
, sizeof(configfile
), NULL
,
1740 str
, (strlenW(str
) + 1) * sizeof(WCHAR
));
1742 if (configfile
[0] != '/') strcpy(configfile
, ETCDIR
);
1744 TRACE("GlobalRegistryDir is '%s'.\n", configfile
);
1746 /* Load the global HKU hive directly from sysconfdir */
1747 p
= configfile
+ strlen(configfile
);
1748 strcpy(p
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
1749 load_wine_registry( hkey_users
, configfile
);
1751 /* Load the global machine defaults directly from sysconfdir */
1752 strcpy(p
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
1753 load_wine_registry( hkey_local_machine
, configfile
);
1756 _set_registry_levels(1,0,0);
1758 /* load home registry if required */
1761 RtlInitUnicodeString( &nameW
, load_home_reg_filesW
);
1762 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1764 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1765 res
= !IS_OPTION_FALSE(str
[0]);
1767 if (res
) _load_home_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
1769 /* setup registry saving */
1772 RtlInitUnicodeString( &nameW
, SaveOnlyUpdatedKeysW
);
1773 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1775 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1776 all
= IS_OPTION_FALSE(str
[0]);
1780 RtlInitUnicodeString( &nameW
, PeriodicSaveW
);
1781 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1783 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1784 period
= (int)strtolW(str
, NULL
, 10);
1787 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1788 _set_registry_levels(1,!all
,period
*1000);
1790 /* setup keys to save */
1793 RtlInitUnicodeString( &nameW
, WritetoHomeRegistryFilesW
);
1794 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1796 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1797 res
= !IS_OPTION_FALSE(str
[0]);
1801 _save_at_exit(hkey_current_user
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1802 _save_at_exit(hkey_local_machine
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1803 _save_at_exit(hkey_users_default
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1806 NtClose(hkey_users_default
);
1807 NtClose(hkey_current_user
);
1808 NtClose(hkey_users
);
1809 NtClose(hkey_local_machine
);
1810 NtClose(hkey_config
);