Implemented DllCanUnloadNow.
[wine/multimedia.git] / misc / registry.c
blob614b0a49ff15355272ff30f7a3b39122c5e99d6d
1 /*
2 * Registry Functions
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
26 * NOTES
27 * When changing this file, please re-run the regtest program to ensure
28 * the conditions are handled properly.
30 * TODO
31 * Security access
32 * Option handling
33 * Time for RegEnumKey*, RegQueryInfoKey*
36 #include "config.h"
37 #include "wine/port.h"
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #ifdef HAVE_SYS_MMAN_H
51 # include <sys/mman.h>
52 #endif
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
55 #endif
56 #ifdef HAVE_LINUX_HDREG_H
57 # include <linux/hdreg.h>
58 #endif
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winerror.h"
66 #include "winioctl.h"
67 #include "ntddscsi.h"
69 #include "wine/winbase16.h"
70 #include "wine/library.h"
71 #include "wine/server.h"
72 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(reg);
78 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
79 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
81 #define MAX_PATHNAME_LEN 1024
83 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
84 'S','o','f','t','w','a','r','e','\\',
85 'C','l','a','s','s','e','s',0};
87 #define IS_OPTION_FALSE(ch) \
88 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
90 /* _xmalloc [Internal] */
91 static void *_xmalloc( size_t size )
93 void *res;
95 res = malloc (size ? size : 1);
96 if (res == NULL) {
97 WARN("Virtual memory exhausted.\n");
98 exit (1);
100 return res;
103 /* _xstrdup [Internal] */
104 static LPSTR _xstrdup(LPCSTR str)
106 LPSTR ret;
107 size_t len = strlen(str) + 1;
109 if (!str) return NULL;
110 ret = _xmalloc( len );
111 memcpy( ret, str, len );
112 return ret;
115 /* convert ansi string to unicode [Internal] */
116 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
118 LPWSTR ret;
119 DWORD len;
121 if (!strA) return NULL;
122 if (RtlMultiByteToUnicodeSize( &len, strA, lenA ) != STATUS_SUCCESS) return NULL;
124 ret = _xmalloc(len+sizeof(WCHAR));
125 RtlMultiByteToUnicodeN(ret, len, NULL, strA, lenA);
126 ret[len / sizeof(WCHAR)] = 0;
127 return ret;
130 /* dump a Unicode string with proper escaping [Internal] */
131 /* FIXME: this code duplicates server/unicode.c */
132 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,const char escape[2])
134 static const char escapes[32] = ".......abtnvfr.............e....";
135 char buffer[256];
136 LPSTR pos = buffer;
137 int count = 0;
139 for (; len; str++, len--)
141 if (pos > buffer + sizeof(buffer) - 8)
143 fwrite( buffer, pos - buffer, 1, f );
144 count += pos - buffer;
145 pos = buffer;
147 if (*str > 127) /* hex escape */
149 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
150 pos += sprintf( pos, "\\x%04x", *str );
151 else
152 pos += sprintf( pos, "\\x%x", *str );
153 continue;
155 if (*str < 32) /* octal or C escape */
157 if (!*str && len == 1) continue; /* do not output terminating NULL */
158 if (escapes[*str] != '.')
159 pos += sprintf( pos, "\\%c", escapes[*str] );
160 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
161 pos += sprintf( pos, "\\%03o", *str );
162 else
163 pos += sprintf( pos, "\\%o", *str );
164 continue;
166 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
167 *pos++ = *str;
169 fwrite( buffer, pos - buffer, 1, f );
170 count += pos - buffer;
171 return count;
174 /* convert ansi string to unicode and dump with proper escaping [Internal] */
175 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,const char escape[2])
177 WCHAR *strW;
178 int ret;
180 if (strA == NULL) return 0;
181 strW = _strdupnAtoW(strA,len);
182 ret = _dump_strW(strW,len,f,escape);
183 free(strW);
184 return ret;
187 /* a key value */
188 /* FIXME: this code duplicates server/registry.c */
189 struct key_value {
190 WCHAR *nameW; /* value name */
191 int type; /* value type */
192 size_t len; /* value data length in bytes */
193 void *data; /* pointer to value data */
196 /* dump a value to a text file */
197 /* FIXME: this code duplicates server/registry.c */
198 static void _dump_value(struct key_value *value,FILE *f)
200 int i, count;
202 if (value->nameW[0]) {
203 fputc( '\"', f );
204 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
205 count += fprintf( f, "\"=" );
207 else count = fprintf( f, "@=" );
209 switch(value->type) {
210 case REG_SZ:
211 case REG_EXPAND_SZ:
212 case REG_MULTI_SZ:
213 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
214 fputc( '\"', f );
215 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
216 fputc( '\"', f );
217 break;
218 case REG_DWORD:
219 if (value->len == sizeof(DWORD)) {
220 DWORD dw;
221 memcpy( &dw, value->data, sizeof(DWORD) );
222 fprintf( f, "dword:%08lx", dw );
223 break;
225 /* else fall through */
226 default:
227 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
228 else count += fprintf( f, "hex(%x):", value->type );
229 for (i = 0; i < value->len; i++) {
230 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
231 if (i < value->len-1) {
232 fputc( ',', f );
233 if (++count > 76) {
234 fprintf( f, "\\\n " );
235 count = 2;
239 break;
241 fputc( '\n', f );
244 /******************************************************************/
245 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
247 reghack - windows 3.11 registry data format demo program.
249 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
250 a combined hash table and tree description, and finally a text table.
252 The header is obvious from the struct header. The taboff1 and taboff2
253 fields are always 0x20, and their usage is unknown.
255 The 8-byte entry table has various entry types.
257 tabent[0] is a root index. The second word has the index of the root of
258 the directory.
259 tabent[1..hashsize] is a hash table. The first word in the hash entry is
260 the index of the key/value that has that hash. Data with the same
261 hash value are on a circular list. The other three words in the
262 hash entry are always zero.
263 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
264 entry: dirent and keyent/valent. They are identified by context.
265 tabent[freeidx] is the first free entry. The first word in a free entry
266 is the index of the next free entry. The last has 0 as a link.
267 The other three words in the free list are probably irrelevant.
269 Entries in text table are preceded by a word at offset-2. This word
270 has the value (2*index)+1, where index is the referring keyent/valent
271 entry in the table. I have no suggestion for the 2* and the +1.
272 Following the word, there are N bytes of data, as per the keyent/valent
273 entry length. The offset of the keyent/valent entry is from the start
274 of the text table to the first data byte.
276 This information is not available from Microsoft. The data format is
277 deduced from the reg.dat file by me. Mistakes may
278 have been made. I claim no rights and give no guarantees for this program.
280 Tor Sjøwall, tor@sn.no
283 /* reg.dat header format */
284 struct _w31_header {
285 char cookie[8]; /* 'SHCC3.10' */
286 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
287 unsigned long taboff2; /* offset of index table (??) = 0x20 */
288 unsigned long tabcnt; /* number of entries in index table */
289 unsigned long textoff; /* offset of text part */
290 unsigned long textsize; /* byte size of text part */
291 unsigned short hashsize; /* hash size */
292 unsigned short freeidx; /* free index */
295 /* generic format of table entries */
296 struct _w31_tabent {
297 unsigned short w0, w1, w2, w3;
300 /* directory tabent: */
301 struct _w31_dirent {
302 unsigned short sibling_idx; /* table index of sibling dirent */
303 unsigned short child_idx; /* table index of child dirent */
304 unsigned short key_idx; /* table index of key keyent */
305 unsigned short value_idx; /* table index of value valent */
308 /* key tabent: */
309 struct _w31_keyent {
310 unsigned short hash_idx; /* hash chain index for string */
311 unsigned short refcnt; /* reference count */
312 unsigned short length; /* length of string */
313 unsigned short string_off; /* offset of string in text table */
316 /* value tabent: */
317 struct _w31_valent {
318 unsigned short hash_idx; /* hash chain index for string */
319 unsigned short refcnt; /* reference count */
320 unsigned short length; /* length of string */
321 unsigned short string_off; /* offset of string in text table */
324 /* recursive helper function to display a directory tree [Internal] */
325 static void _w31_dumptree(unsigned short idx, char *txt,
326 struct _w31_tabent *tab, struct _w31_header *head,
327 HKEY hkey, ULONG lastmodified, int level)
329 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
330 struct _w31_dirent *dir;
331 struct _w31_keyent *key;
332 struct _w31_valent *val;
333 HKEY subkey = 0;
334 OBJECT_ATTRIBUTES attr;
335 UNICODE_STRING nameW, valueW;
336 static WCHAR tail[400];
338 attr.Length = sizeof(attr);
339 attr.RootDirectory = hkey;
340 attr.ObjectName = &nameW;
341 attr.Attributes = 0;
342 attr.SecurityDescriptor = NULL;
343 attr.SecurityQualityOfService = NULL;
344 RtlInitUnicodeString( &valueW, NULL );
346 while (idx!=0) {
347 dir=(struct _w31_dirent*)&tab[idx];
349 if (dir->key_idx) {
350 DWORD len;
351 key = (struct _w31_keyent*)&tab[dir->key_idx];
353 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
354 &txt[key->string_off], key->length);
355 tail[len/sizeof(WCHAR)] = 0;
357 /* all toplevel entries AND the entries in the
358 * toplevel subdirectory belong to \SOFTWARE\Classes
360 if (!level && !strcmpW(tail,classesW))
362 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
363 idx=dir->sibling_idx;
364 continue;
367 if (subkey) NtClose( subkey );
368 RtlInitUnicodeString( &nameW, tail );
369 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
371 /* only add if leaf node or valued node */
372 if (dir->value_idx!=0||dir->child_idx==0) {
373 if (dir->value_idx) {
374 DWORD len;
375 val=(struct _w31_valent*)&tab[dir->value_idx];
376 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
377 &txt[val->string_off], val->length);
378 tail[len/sizeof(WCHAR)] = 0;
379 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
382 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
383 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
384 idx=dir->sibling_idx;
386 if (subkey) NtClose( subkey );
390 /******************************************************************************
391 * _w31_loadreg [Internal]
393 static void _w31_loadreg( const WCHAR *path )
395 HANDLE hf;
396 HKEY root;
397 OBJECT_ATTRIBUTES attr;
398 UNICODE_STRING nameW;
399 struct _w31_header head;
400 struct _w31_tabent* tab = NULL;
401 char* txt = NULL;
402 unsigned int len;
403 ULONG lastmodified;
404 NTSTATUS status;
405 IO_STATUS_BLOCK iosb;
406 FILE_POSITION_INFORMATION fpi;
407 FILE_BASIC_INFORMATION fbi;
409 TRACE("(void)\n");
411 hf = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
412 if (hf==INVALID_HANDLE_VALUE) return;
414 /* read & dump header */
415 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
416 &head, sizeof(head), NULL, NULL) != STATUS_SUCCESS ||
417 iosb.Information != sizeof(head))
419 ERR("reg.dat is too short.\n");
420 goto done;
422 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie)) != 0)
424 ERR("reg.dat has bad signature.\n");
425 goto done;
428 len = head.tabcnt * sizeof(struct _w31_tabent);
429 /* read and dump index table */
430 tab = _xmalloc(len);
431 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
432 tab, len, NULL, NULL) != STATUS_SUCCESS ||
433 iosb.Information != len)
435 ERR("couldn't read index table (%d bytes).\n",len);
436 goto done;
439 /* read text */
440 txt = _xmalloc(head.textsize);
441 fpi.CurrentByteOffset.u.LowPart = head.textoff;
442 fpi.CurrentByteOffset.u.HighPart = 0;
443 if (NtSetInformationFile(hf, &iosb, &fpi, sizeof(fpi),
444 FilePositionInformation) != STATUS_SUCCESS)
446 ERR("couldn't seek to textblock.\n");
447 goto done;
449 status = NtReadFile(hf, 0, NULL, NULL, &iosb, txt, head.textsize, NULL, NULL);
450 if (!(status == STATUS_SUCCESS || status == STATUS_END_OF_FILE) ||
451 iosb.Information != head.textsize)
453 ERR("textblock too short (%d instead of %ld).\n", len, head.textsize);
454 goto done;
456 if (NtQueryInformationFile(hf, &iosb, &fbi, sizeof(fbi),
457 FileBasicInformation) != STATUS_SUCCESS)
459 ERR("Couldn't get basic information.\n");
460 goto done;
462 RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &lastmodified);
464 attr.Length = sizeof(attr);
465 attr.RootDirectory = 0;
466 attr.ObjectName = &nameW;
467 attr.Attributes = 0;
468 attr.SecurityDescriptor = NULL;
469 attr.SecurityQualityOfService = NULL;
470 RtlInitUnicodeString( &nameW, ClassesRootW );
472 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
474 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
475 NtClose( root );
477 done:
478 if (tab) free(tab);
479 if (txt) free(txt);
480 NtClose(hf);
481 return;
484 /***********************************************************************************/
485 /* windows 95 registry loader */
486 /***********************************************************************************/
488 /* SECTION 1: main header
490 * once at offset 0
492 #define W95_REG_CREG_ID 0x47455243
494 typedef struct {
495 DWORD id; /* "CREG" = W95_REG_CREG_ID */
496 DWORD version; /* ???? 0x00010000 */
497 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
498 DWORD uk2; /* 0x0c */
499 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
500 WORD uk3;
501 DWORD uk[3];
502 /* rgkn */
503 } _w95creg;
505 /* SECTION 2: Directory information (tree structure)
507 * once on offset 0x20
509 * structure: [rgkn][dke]* (repeat till last_dke is reached)
511 #define W95_REG_RGKN_ID 0x4e4b4752
513 typedef struct {
514 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
515 DWORD size; /* Size of the RGKN-block */
516 DWORD root_off; /* Rel. Offset of the root-record */
517 DWORD last_dke; /* Offset to last DKE ? */
518 DWORD uk[4];
519 } _w95rgkn;
521 /* Disk Key Entry Structure
523 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
524 * hive itself. It looks the same like other keys. Even the ID-number can
525 * be any value.
527 * The "hash"-value is a value representing the key's name. Windows will not
528 * search for the name, but for a matching hash-value. if it finds one, it
529 * will compare the actual string info, otherwise continue with the next key.
530 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
531 * of the string which are smaller than 0x80 (128) to this D-Word.
533 * If you want to modify key names, also modify the hash-values, since they
534 * cannot be found again (although they would be displayed in REGEDIT)
535 * End of list-pointers are filled with 0xFFFFFFFF
537 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
538 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
539 * structure) and reading another RGDB_section.
541 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
542 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
543 * The remaining space between last_dke and the offset calculated from
544 * rgkn->size seems to be free for use for more dke:s.
545 * So it seems if more dke:s are added, they are added to that space and
546 * last_dke is grown, and in case that "free" space is out, the space
547 * gets grown and rgkn->size gets adjusted.
549 * there is a one to one relationship between dke and dkh
551 /* key struct, once per key */
552 typedef struct {
553 DWORD x1; /* Free entry indicator(?) */
554 DWORD hash; /* sum of bytes of keyname */
555 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
556 DWORD prevlvl; /* offset of previous key */
557 DWORD nextsub; /* offset of child key */
558 DWORD next; /* offset of sibling key */
559 WORD nrLS; /* id inside the rgdb block */
560 WORD nrMS; /* number of the rgdb block */
561 } _w95dke;
563 /* SECTION 3: key information, values and data
565 * structure:
566 * section: [blocks]* (repeat creg->rgdb_num times)
567 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
568 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
570 * An interesting relationship exists in RGDB_section. The DWORD value
571 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
572 * I have no idea at the moment what this means. (Kevin Cozens)
575 /* block header, once per block */
576 #define W95_REG_RGDB_ID 0x42444752
578 typedef struct {
579 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
580 DWORD size; /* 0x04 */
581 DWORD uk1; /* 0x08 */
582 DWORD uk2; /* 0x0c */
583 DWORD uk3; /* 0x10 */
584 DWORD uk4; /* 0x14 */
585 DWORD uk5; /* 0x18 */
586 DWORD uk6; /* 0x1c */
587 /* dkh */
588 } _w95rgdb;
590 /* Disk Key Header structure (RGDB part), once per key */
591 typedef struct {
592 DWORD nextkeyoff; /* 0x00 offset to next dkh */
593 WORD nrLS; /* 0x04 id inside the rgdb block */
594 WORD nrMS; /* 0x06 number of the rgdb block */
595 DWORD bytesused; /* 0x08 */
596 WORD keynamelen; /* 0x0c len of name */
597 WORD values; /* 0x0e number of values */
598 DWORD xx1; /* 0x10 */
599 char name[1]; /* 0x14 */
600 /* dkv */ /* 0x14 + keynamelen */
601 } _w95dkh;
603 /* Disk Key Value structure, once per value */
604 typedef struct {
605 DWORD type; /* 0x00 */
606 DWORD x1; /* 0x04 */
607 WORD valnamelen; /* 0x08 length of name, 0 is default key */
608 WORD valdatalen; /* 0x0A length of data */
609 char name[1]; /* 0x0c */
610 /* raw data */ /* 0x0c + valnamelen */
611 } _w95dkv;
613 /******************************************************************************
614 * _w95_lookup_dkh [Internal]
616 * seeks the dkh belonging to a dke
618 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
620 _w95rgdb * rgdb;
621 _w95dkh * dkh;
622 int i;
624 /* get the beginning of the rgdb datastore */
625 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
627 /* check: requested block < last_block) */
628 if (creg->rgdb_num <= nrMS) {
629 ERR("registry file corrupt! requested block no. beyond end.\n");
630 goto error;
633 /* find the right block */
634 for(i=0; i<nrMS ;i++) {
635 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
636 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
637 goto error;
639 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
642 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
644 do {
645 if(nrLS==dkh->nrLS ) return dkh;
646 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
647 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
649 error:
650 return NULL;
653 /******************************************************************************
654 * _w95_dump_dkv [Internal]
656 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
658 _w95dkv * dkv;
659 int i;
661 /* first value block */
662 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
664 /* loop through the values */
665 for (i=0; i< dkh->values; i++) {
666 struct key_value value;
667 WCHAR *pdata;
669 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
670 value.type = dkv->type;
671 value.len = dkv->valdatalen;
673 value.data = &(dkv->name[dkv->valnamelen]);
674 pdata = NULL;
675 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
676 pdata = _strdupnAtoW(value.data,value.len);
677 value.len *= 2;
679 if (pdata != NULL) value.data = pdata;
681 _dump_value(&value,f);
682 free(value.nameW);
683 if (pdata != NULL) free(pdata);
685 /* next value */
686 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
688 return TRUE;
691 static int _w95_dump_one_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level);
693 static int _w95_dump_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
695 while (1)
697 if (!_w95_dump_one_dke(key_name, creg, rgkn, dke, f, level))
698 return FALSE;
699 if (dke->next == 0xffffffff)
700 return TRUE;
701 dke = (_w95dke*)((char*)rgkn+dke->next);
705 /******************************************************************************
706 * _w95_dump_dke [Internal]
708 static int _w95_dump_one_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
710 _w95dkh * dkh;
711 LPSTR new_key_name = NULL;
713 /* special root key */
714 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
716 /* parse the one subkey */
717 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
718 /* has no sibling keys */
719 return FALSE;
722 /* search subblock */
723 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
724 ERR("dke pointing to missing dkh !\n");
725 return FALSE;
728 if (level <= 0) {
729 /* create new subkey name */
730 size_t len = strlen(key_name);
731 new_key_name = _xmalloc(len+dkh->keynamelen+2);
732 memcpy( new_key_name, key_name, len );
733 if (len) new_key_name[len++] = '\\';
734 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
735 new_key_name[len + dkh->keynamelen] = 0;
737 /* write the key path (something like [Software\\Microsoft\\..]) only if:
738 1) key has some values
739 2) key has no values and no subkeys
741 if (dkh->values > 0) {
742 /* there are some values */
743 fprintf(f,"\n[");
744 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
745 fprintf(f,"]\n");
746 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
747 free(new_key_name);
748 return FALSE;
751 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
752 /* no subkeys and no values */
753 fprintf(f,"\n[");
754 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
755 fprintf(f,"]\n");
757 } else new_key_name = _xstrdup(key_name);
759 /* next sub key */
760 if (dke->nextsub != 0xffffffff) {
761 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
762 free(new_key_name);
763 return FALSE;
767 free(new_key_name);
768 return TRUE;
770 /* end windows 95 loader */
772 /***********************************************************************************/
773 /* windows NT registry loader */
774 /***********************************************************************************/
776 /* NT REGISTRY LOADER */
778 #ifdef HAVE_SYS_MMAN_H
779 # include <sys/mman.h>
780 #endif
782 #ifndef MAP_FAILED
783 #define MAP_FAILED ((LPVOID)-1)
784 #endif
786 #define NT_REG_BLOCK_SIZE 0x1000
788 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
789 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
790 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
791 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
793 /* subblocks of nk */
794 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
795 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
796 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
798 #define NT_REG_KEY_BLOCK_TYPE 0x20
799 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
801 typedef struct {
802 DWORD id; /* 0x66676572 'regf'*/
803 DWORD uk1; /* 0x04 */
804 DWORD uk2; /* 0x08 */
805 FILETIME DateModified; /* 0x0c */
806 DWORD uk3; /* 0x14 */
807 DWORD uk4; /* 0x18 */
808 DWORD uk5; /* 0x1c */
809 DWORD uk6; /* 0x20 */
810 DWORD RootKeyBlock; /* 0x24 */
811 DWORD BlockSize; /* 0x28 */
812 DWORD uk7[116];
813 DWORD Checksum; /* at offset 0x1FC */
814 } nt_regf;
816 typedef struct {
817 DWORD blocksize;
818 BYTE data[1];
819 } nt_hbin_sub;
821 typedef struct {
822 DWORD id; /* 0x6E696268 'hbin' */
823 DWORD off_prev;
824 DWORD off_next;
825 DWORD uk1;
826 DWORD uk2; /* 0x10 */
827 DWORD uk3; /* 0x14 */
828 DWORD uk4; /* 0x18 */
829 DWORD size; /* 0x1C */
830 nt_hbin_sub hbin_sub; /* 0x20 */
831 } nt_hbin;
834 * the value_list consists of offsets to the values (vk)
836 typedef struct {
837 WORD SubBlockId; /* 0x00 0x6B6E */
838 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
839 FILETIME writetime; /* 0x04 */
840 DWORD uk1; /* 0x0C */
841 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
842 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
843 DWORD uk8; /* 0x18 */
844 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
845 DWORD uk2; /* 0x20 */
846 DWORD nr_values; /* 0x24 number of values */
847 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
848 DWORD off_sk; /* 0x2c Offset of the sk-Record */
849 DWORD off_class; /* 0x30 Offset of the Class-Name */
850 DWORD uk3; /* 0x34 */
851 DWORD uk4; /* 0x38 */
852 DWORD uk5; /* 0x3c */
853 DWORD uk6; /* 0x40 */
854 DWORD uk7; /* 0x44 */
855 WORD name_len; /* 0x48 name-length */
856 WORD class_len; /* 0x4a class-name length */
857 char name[1]; /* 0x4c key-name */
858 } nt_nk;
860 typedef struct {
861 DWORD off_nk; /* 0x00 */
862 DWORD name; /* 0x04 */
863 } hash_rec;
865 typedef struct {
866 WORD id; /* 0x00 0x666c */
867 WORD nr_keys; /* 0x06 */
868 hash_rec hash_rec[1];
869 } nt_lf;
872 list of subkeys without hash
874 li --+-->nk
876 +-->nk
878 typedef struct {
879 WORD id; /* 0x00 0x696c */
880 WORD nr_keys;
881 DWORD off_nk[1];
882 } nt_li;
885 this is a intermediate node
887 ri --+-->li--+-->nk
889 | +-->nk
891 +-->li--+-->nk
893 +-->nk
895 typedef struct {
896 WORD id; /* 0x00 0x6972 */
897 WORD nr_li; /* 0x02 number off offsets */
898 DWORD off_li[1]; /* 0x04 points to li */
899 } nt_ri;
901 typedef struct {
902 WORD id; /* 0x00 'vk' */
903 WORD nam_len;
904 DWORD data_len;
905 DWORD data_off;
906 DWORD type;
907 WORD flag;
908 WORD uk1;
909 char name[1];
910 } nt_vk;
913 * gets a value
915 * vk->flag:
916 * 0 value is a default value
917 * 1 the value has a name
919 * vk->data_len
920 * len of the whole data block
921 * - reg_sz (unicode)
922 * bytes including the terminating \0 = 2*(number_of_chars+1)
923 * - reg_dword, reg_binary:
924 * if highest bit of data_len is set data_off contains the value
926 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
928 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
929 struct key_value value;
931 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
932 ERR("unknown block found (0x%04x), please report!\n", vk->id);
933 return FALSE;
936 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
937 value.type = vk->type;
938 value.len = (vk->data_len & 0x7fffffff);
939 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
941 _dump_value(&value,f);
942 free(value.nameW);
944 return TRUE;
947 /* it's called from _nt_dump_lf() */
948 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
951 * get the subkeys
953 * this structure contains the hash of a keyname and points to all
954 * subkeys
956 * exception: if the id is 'il' there are no hash values and every
957 * dword is a offset
959 static int _nt_dump_lf(LPCSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
961 int i;
963 if (lf->id == NT_REG_HASH_BLOCK_ID) {
964 if (subkeys != lf->nr_keys) goto error1;
966 for (i=0; i<lf->nr_keys; i++)
967 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
968 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
969 nt_li * li = (nt_li*)lf;
970 if (subkeys != li->nr_keys) goto error1;
972 for (i=0; i<li->nr_keys; i++)
973 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
974 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
975 nt_ri * ri = (nt_ri*)lf;
976 int li_subkeys = 0;
978 /* count all subkeys */
979 for (i=0; i<ri->nr_li; i++) {
980 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
981 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
982 li_subkeys += li->nr_keys;
985 /* check number */
986 if (subkeys != li_subkeys) goto error1;
988 /* loop through the keys */
989 for (i=0; i<ri->nr_li; i++) {
990 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
991 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
993 } else goto error2;
995 return TRUE;
997 error2:
998 if (lf->id == 0x686c)
999 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
1000 else
1001 ERR("unknown node id 0x%04x, please report!\n", lf->id);
1002 return TRUE;
1004 error1:
1005 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
1006 return FALSE;
1008 error:
1009 ERR("error reading lf block\n");
1010 return FALSE;
1013 /* _nt_dump_nk [Internal] */
1014 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
1016 unsigned int n;
1017 DWORD *vl;
1018 LPSTR new_key_name = NULL;
1020 TRACE("%s\n", key_name);
1022 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
1023 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1024 return FALSE;
1027 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1028 ERR("registry file corrupt!\n");
1029 return FALSE;
1032 /* create the new key */
1033 if (level <= 0) {
1034 /* create new subkey name */
1035 size_t len = strlen(key_name);
1036 new_key_name = _xmalloc( len+nk->name_len+2 );
1037 memcpy( new_key_name, key_name, len );
1038 if (len) new_key_name[len++] = '\\';
1039 memcpy( new_key_name + len, nk->name, nk->name_len );
1040 new_key_name[len + nk->name_len] = 0;
1042 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1043 1) key has some values
1044 2) key has no values and no subkeys
1046 if (nk->nr_values > 0) {
1047 /* there are some values */
1048 fprintf(f,"\n[");
1049 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1050 fprintf(f,"]\n");
1052 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1053 /* no subkeys and no values */
1054 fprintf(f,"\n[");
1055 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1056 fprintf(f,"]\n");
1059 /* loop trough the value list */
1060 vl = (DWORD *)(base+nk->valuelist_off+4);
1061 for (n=0; n<nk->nr_values; n++) {
1062 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1063 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1064 free(new_key_name);
1065 return FALSE;
1068 } else new_key_name = _xstrdup(key_name);
1070 /* loop through the subkeys */
1071 if (nk->nr_subkeys) {
1072 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1073 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1074 free(new_key_name);
1075 return FALSE;
1079 free(new_key_name);
1080 return TRUE;
1083 /* end nt loader */
1085 /******************************************************************************
1086 * _allocate_default_keys [Internal]
1087 * Registry initialisation, allocates some default keys.
1089 static void _allocate_default_keys(void)
1091 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1092 'P','e','r','f','S','t','a','t','s','\\',
1093 'S','t','a','t','D','a','t','a',0};
1094 static const WCHAR ConfigManagerW[] = {'D','y','n','D','a','t','a','\\',
1095 'C','o','n','f','i','g',' ','M','a','n','a','g','e','r','\\',
1096 'E','n','u','m',0};
1097 HKEY hkey;
1098 OBJECT_ATTRIBUTES attr;
1099 UNICODE_STRING nameW;
1101 TRACE("(void)\n");
1103 attr.Length = sizeof(attr);
1104 attr.RootDirectory = 0;
1105 attr.ObjectName = &nameW;
1106 attr.Attributes = 0;
1107 attr.SecurityDescriptor = NULL;
1108 attr.SecurityQualityOfService = NULL;
1110 RtlInitUnicodeString( &nameW, StatDataW );
1111 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1113 RtlInitUnicodeString( &nameW, ConfigManagerW );
1114 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1117 static void get_windows_dir(WCHAR* buffer, unsigned len)
1119 static const WCHAR windows_dir[] = {'c',':','\\','w','i','n','d','o','w','s',0};
1120 OBJECT_ATTRIBUTES attr;
1121 UNICODE_STRING nameW, keyW;
1122 HKEY hkey;
1124 *buffer = 0;
1125 attr.Length = sizeof(attr);
1126 attr.RootDirectory = 0;
1127 attr.ObjectName = &nameW;
1128 attr.Attributes = 0;
1129 attr.SecurityDescriptor = NULL;
1130 attr.SecurityQualityOfService = NULL;
1132 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1134 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1136 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1137 DWORD count;
1139 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1140 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1141 tmp, sizeof(tmp), &count ))
1143 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1144 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1146 RtlFreeUnicodeString( &keyW );
1148 RtlFreeUnicodeString( &nameW );
1150 if (!*buffer) lstrcpynW(buffer, windows_dir, len);
1154 #define REG_DONTLOAD -1
1155 #define REG_WIN31 0
1156 #define REG_WIN95 1
1157 #define REG_WINNT 2
1159 /* return the type of native registry [Internal] */
1160 static int _get_reg_type(const WCHAR* windir)
1162 WCHAR tmp[MAX_PATHNAME_LEN];
1163 int ret = REG_WIN31;
1164 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};
1165 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1167 /* test %windir%/system32/config/system --> winnt */
1168 strcpyW(tmp, windir);
1169 strcatW(tmp, nt_reg_pathW);
1170 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1171 ret = REG_WINNT;
1172 else
1174 /* test %windir%/system.dat --> win95 */
1175 strcpyW(tmp, windir);
1176 strcatW(tmp, win9x_reg_pathW);
1177 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1178 ret = REG_WIN95;
1181 return ret;
1184 /* load the registry file in wine format [Internal] */
1185 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1187 WCHAR *buffer;
1188 HANDLE file;
1189 DWORD len;
1190 UNICODE_STRING name;
1191 OBJECT_ATTRIBUTES attr;
1192 IO_STATUS_BLOCK io;
1194 len = MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, NULL, 0 );
1195 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
1196 MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, buffer, len );
1197 RtlInitUnicodeString( &name, buffer );
1199 attr.Length = sizeof(attr);
1200 attr.RootDirectory = 0;
1201 attr.Attributes = 0;
1202 attr.ObjectName = &name;
1203 attr.SecurityDescriptor = NULL;
1204 attr.SecurityQualityOfService = NULL;
1206 if (!NtOpenFile( &file, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
1207 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
1209 SERVER_START_REQ( load_registry )
1211 req->hkey = hkey;
1212 req->file = file;
1213 wine_server_call( req );
1215 SERVER_END_REQ;
1216 CloseHandle( file );
1218 HeapFree( GetProcessHeap(), 0, buffer );
1221 /* generate and return the name of the tmp file and associated stream [Internal] */
1222 static LPSTR _get_tmp_fn(FILE **f)
1224 LPSTR ret;
1225 int tmp_fd,count;
1227 ret = _xmalloc(50);
1228 for (count = 0;;) {
1229 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1230 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1231 if (errno != EEXIST) {
1232 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1233 free(ret);
1234 *f = NULL;
1235 return NULL;
1239 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1240 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1241 close(tmp_fd);
1242 free(ret);
1243 return NULL;
1246 return ret;
1249 /* convert win95 native registry file to wine format [Internal] */
1250 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1252 HANDLE hFile, hMapping;
1253 FILE *f;
1254 void *base;
1255 LPSTR ret = NULL;
1256 OBJECT_ATTRIBUTES attr;
1257 LARGE_INTEGER lg_int;
1258 NTSTATUS nts;
1259 SIZE_T len;
1261 _w95creg *creg;
1262 _w95rgkn *rgkn;
1263 _w95dke *dke, *root_dke;
1265 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1266 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1268 attr.Length = sizeof(attr);
1269 attr.RootDirectory = 0;
1270 attr.ObjectName = NULL;
1271 attr.Attributes = 0;
1272 attr.SecurityDescriptor = NULL;
1273 attr.SecurityQualityOfService = NULL;
1275 lg_int.QuadPart = 0;
1276 nts = NtCreateSection( &hMapping,
1277 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1278 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1279 if (nts != STATUS_SUCCESS) goto error1;
1281 base = NULL; len = 0;
1282 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1283 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1284 PAGE_READONLY);
1285 NtClose( hMapping );
1286 if (nts != STATUS_SUCCESS) goto error1;
1288 /* control signature */
1289 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1290 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1291 debugstr_w(fn));
1292 goto error;
1295 creg = base;
1296 /* load the header (rgkn) */
1297 rgkn = (_w95rgkn*)(creg + 1);
1298 if (rgkn->id != W95_REG_RGKN_ID) {
1299 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1300 goto error;
1302 if (rgkn->root_off != 0x20) {
1303 ERR("rgkn->root_off not 0x20, please report !\n");
1304 goto error;
1306 if (rgkn->last_dke > rgkn->size)
1308 ERR("registry file corrupt! last_dke > size!\n");
1309 goto error;
1311 /* verify last dke */
1312 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1313 if (dke->x1 != 0x80000000)
1314 { /* wrong magic */
1315 ERR("last dke invalid !\n");
1316 goto error;
1318 if (rgkn->size > creg->rgdb_off)
1320 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1321 goto error;
1323 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1324 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1326 ERR("registry file corrupt! invalid root dke !\n");
1327 goto error;
1330 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1331 fprintf(f,"WINE REGISTRY Version 2");
1332 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1333 fclose(f);
1335 error:
1336 if(ret == NULL) {
1337 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1338 ERR("Please report this.\n");
1339 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1342 NtUnmapViewOfSection( GetCurrentProcess(), base );
1343 error1:
1344 NtClose(hFile);
1345 return ret;
1348 /* convert winnt native registry file to wine format [Internal] */
1349 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1351 FILE *f;
1352 void *base;
1353 LPSTR ret = NULL;
1354 HANDLE hFile;
1355 HANDLE hMapping;
1356 OBJECT_ATTRIBUTES attr;
1357 LARGE_INTEGER lg_int;
1358 NTSTATUS nts;
1359 SIZE_T len;
1361 nt_regf *regf;
1362 nt_hbin *hbin;
1363 nt_hbin_sub *hbin_sub;
1364 nt_nk *nk;
1366 TRACE("%s\n", debugstr_w(fn));
1368 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1369 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1370 attr.Length = sizeof(attr);
1371 attr.RootDirectory = 0;
1372 attr.ObjectName = NULL;
1373 attr.Attributes = 0;
1374 attr.SecurityDescriptor = NULL;
1375 attr.SecurityQualityOfService = NULL;
1377 lg_int.QuadPart = 0;
1378 nts = NtCreateSection( &hMapping,
1379 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1380 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1381 if (nts != STATUS_SUCCESS) goto error1;
1383 base = NULL; len = 0;
1384 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1385 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1386 PAGE_READONLY);
1387 NtClose( hMapping );
1388 if (nts != STATUS_SUCCESS) goto error1;
1390 /* control signature */
1391 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1392 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1393 debugstr_w(fn));
1394 goto error;
1397 /* start block */
1398 regf = base;
1400 /* hbin block */
1401 hbin = (nt_hbin*)((char*) base + 0x1000);
1402 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1403 ERR( "hbin block invalid\n");
1404 goto error;
1407 /* hbin_sub block */
1408 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1409 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1410 ERR( "hbin_sub block invalid\n");
1411 goto error;
1414 /* nk block */
1415 nk = (nt_nk*)&(hbin_sub->data[0]);
1416 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1417 ERR( "special nk block not found\n");
1418 goto error;
1421 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1422 fprintf(f,"WINE REGISTRY Version 2");
1423 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1424 fclose(f);
1426 error:
1427 NtUnmapViewOfSection( GetCurrentProcess(), base );
1428 error1:
1429 NtClose(hFile);
1430 return ret;
1433 /* convert native registry to wine format and load it via server call [Internal] */
1434 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1436 LPSTR tmp = NULL;
1438 switch (reg_type) {
1439 case REG_WINNT:
1440 /* FIXME: following function doesn't really convert yet */
1441 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1442 break;
1443 case REG_WIN95:
1444 tmp = _convert_win95_registry_to_wine_format(fn,level);
1445 break;
1446 case REG_WIN31:
1447 ERR("Don't know how to convert native 3.1 registry yet.\n");
1448 break;
1449 default:
1450 ERR("Unknown registry format parameter (%d)\n",reg_type);
1451 break;
1454 if (tmp != NULL) {
1455 load_wine_registry(hkey,tmp);
1456 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1457 debugstr_w(fn), tmp);
1458 unlink(tmp);
1460 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1461 free(tmp);
1464 /* load all native windows registry files [Internal] */
1465 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1466 HKEY hkey_users_default )
1468 int reg_type;
1469 WCHAR windir[MAX_PATHNAME_LEN];
1470 WCHAR path[MAX_PATHNAME_LEN];
1471 OBJECT_ATTRIBUTES attr;
1472 UNICODE_STRING nameW;
1473 HKEY hkey, profile_key;
1474 char tmp[1024];
1475 DWORD dummy;
1477 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1478 'S','o','f','t','w','a','r','e','\\',
1479 'W','i','n','e','\\','W','i','n','e','\\',
1480 'C','o','n','f','i','g','\\','W','i','n','e',0};
1481 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1482 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1483 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1484 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1485 'S','y','s','t','e','m','\\',
1486 'C','l','o','n','e',0};
1488 attr.Length = sizeof(attr);
1489 attr.RootDirectory = 0;
1490 attr.ObjectName = &nameW;
1491 attr.Attributes = 0;
1492 attr.SecurityDescriptor = NULL;
1493 attr.SecurityQualityOfService = NULL;
1495 RtlInitUnicodeString( &nameW, WineW );
1496 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1498 get_windows_dir(windir, sizeof(windir));
1500 reg_type = _get_reg_type(windir);
1501 switch (reg_type) {
1502 case REG_WINNT: {
1503 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1504 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};
1505 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};
1506 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};
1507 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1508 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};
1510 /* user specific ntuser.dat */
1511 RtlInitUnicodeString( &nameW, ProfileW );
1512 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1513 tmp, sizeof(tmp), &dummy ))
1515 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1516 strcatW(path, ntuser_datW);
1517 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1519 else
1521 MESSAGE("When you are running with a native NT directory specify\n");
1522 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1523 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1524 break;
1527 /* default user.dat */
1528 if (hkey_users_default) {
1529 strcpyW(path, windir);
1530 strcatW(path, defaultW);
1531 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1535 * FIXME
1536 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1538 RtlInitUnicodeString( &nameW, System );
1539 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1541 strcpyW(path, windir);
1542 strcatW(path, systemW);
1543 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1544 NtClose( hkey );
1546 RtlInitUnicodeString( &nameW, Software );
1547 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1549 strcpyW(path, windir);
1550 strcatW(path, softwareW);
1551 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1552 NtClose( hkey );
1555 strcpyW(path, windir);
1556 strcatW(path, samW);
1557 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1559 strcpyW(path,windir);
1560 strcatW(path, securityW);
1561 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1563 /* this key is generated when the nt-core booted successfully */
1564 RtlInitUnicodeString( &nameW, Clone );
1565 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1566 break;
1569 case REG_WIN95:
1571 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1572 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1573 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1574 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1576 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1578 strcpyW(path, windir);
1579 strcatW(path, system_datW);
1580 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1582 RtlInitUnicodeString( &nameW, ClassesRootW );
1583 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1585 strcpyW(path, windir);
1586 strcatW(path, classes_datW);
1587 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1588 NtClose( hkey );
1591 RtlInitUnicodeString( &nameW, ProfileW );
1592 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1593 tmp, sizeof(tmp), &dummy ))
1595 /* user specific user.dat */
1596 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1597 strcatW(path, user_datW);
1598 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1600 /* default user.dat */
1601 if (hkey_users_default) {
1602 strcpyW(path, windir);
1603 strcatW(path, user_datW);
1604 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1606 } else {
1607 strcpyW(path, windir);
1608 strcatW(path, user_datW);
1609 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1611 break;
1614 case REG_WIN31:
1616 static const WCHAR reg_datW[] = {'\\','r','e','g','.','d','a','t',0};
1617 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1618 strcpyW(path, windir);
1619 strcatW(path, reg_datW);
1620 _w31_loadreg( path );
1621 break;
1624 case REG_DONTLOAD:
1625 TRACE("REG_DONTLOAD\n");
1626 break;
1628 default:
1629 ERR("switch: no match (%d)\n",reg_type);
1630 break;
1633 if (profile_key) NtClose( profile_key );
1638 /******************************************************************
1639 * init_cdrom_registry
1641 * Initializes registry to contain scsi info about the cdrom in NT.
1642 * All devices (even not real scsi ones) have this info in NT.
1643 * TODO: for now it only works for non scsi devices
1644 * NOTE: programs usually read these registry entries after sending the
1645 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1647 static void init_cdrom_registry( HANDLE handle )
1649 OBJECT_ATTRIBUTES attr;
1650 UNICODE_STRING nameW;
1651 WCHAR dataW[50];
1652 DWORD lenW;
1653 char buffer[40];
1654 DWORD value;
1655 const char *data;
1656 HKEY scsiKey;
1657 HKEY portKey;
1658 HKEY busKey;
1659 HKEY targetKey;
1660 DWORD disp;
1661 IO_STATUS_BLOCK io;
1662 SCSI_ADDRESS scsi_addr;
1664 if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS,
1665 NULL, 0, &scsi_addr, sizeof(scsi_addr) ))
1666 return;
1668 attr.Length = sizeof(attr);
1669 attr.RootDirectory = 0;
1670 attr.ObjectName = &nameW;
1671 attr.Attributes = 0;
1672 attr.SecurityDescriptor = NULL;
1673 attr.SecurityQualityOfService = NULL;
1675 /* Ensure there is Scsi key */
1676 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1677 NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
1678 NULL, REG_OPTION_VOLATILE, &disp ))
1680 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1681 return;
1683 RtlFreeUnicodeString( &nameW );
1685 snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber);
1686 attr.RootDirectory = scsiKey;
1687 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1688 NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
1689 NULL, REG_OPTION_VOLATILE, &disp ))
1691 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1692 return;
1694 RtlFreeUnicodeString( &nameW );
1696 RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
1697 data = "atapi";
1698 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1699 NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1700 RtlFreeUnicodeString( &nameW );
1701 value = 10;
1702 RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
1703 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1704 RtlFreeUnicodeString( &nameW );
1705 value = 0;
1706 #ifdef HDIO_GET_DMA
1708 int fd, dma;
1709 if (!wine_server_handle_to_fd( handle, 0, &fd, NULL ))
1711 if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma;
1712 wine_server_release_fd( handle, fd );
1715 #endif
1716 RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
1717 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1718 RtlFreeUnicodeString( &nameW );
1720 snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId);
1721 attr.RootDirectory = portKey;
1722 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1723 NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
1724 NULL, REG_OPTION_VOLATILE, &disp ))
1726 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1727 return;
1729 RtlFreeUnicodeString( &nameW );
1731 attr.RootDirectory = busKey;
1732 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
1733 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1734 NULL, REG_OPTION_VOLATILE, &disp ))
1736 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1737 return;
1739 RtlFreeUnicodeString( &nameW );
1740 NtClose( targetKey );
1742 snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId);
1743 attr.RootDirectory = busKey;
1744 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1745 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1746 NULL, REG_OPTION_VOLATILE, &disp ))
1748 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1749 return;
1751 RtlFreeUnicodeString( &nameW );
1753 RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
1754 data = "CdRomPeripheral";
1755 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1756 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1757 RtlFreeUnicodeString( &nameW );
1758 /* FIXME - maybe read the real identifier?? */
1759 RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
1760 data = "Wine CDROM";
1761 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1762 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1763 RtlFreeUnicodeString( &nameW );
1764 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1765 RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
1766 data = "Cdrom0";
1767 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1768 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1769 RtlFreeUnicodeString( &nameW );
1771 NtClose( targetKey );
1772 NtClose( busKey );
1773 NtClose( portKey );
1774 NtClose( scsiKey );
1778 /* create the hardware registry branch */
1779 static void create_hardware_branch(void)
1781 int i;
1782 HANDLE handle;
1783 char drive[] = "\\\\.\\A:";
1785 /* create entries for cdroms */
1786 for (i = 0; i < 26; i++)
1788 drive[4] = 'A' + i;
1789 handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
1790 if (handle == INVALID_HANDLE_VALUE) continue;
1791 init_cdrom_registry( handle );
1792 CloseHandle( handle );
1797 /* convert the drive type entries from the old format to the new one */
1798 static void convert_drive_types(void)
1800 static const WCHAR TypeW[] = {'T','y','p','e',0};
1801 static const WCHAR drive_types_keyW[] = {'M','a','c','h','i','n','e','\\',
1802 'S','o','f','t','w','a','r','e','\\',
1803 'W','i','n','e','\\',
1804 'D','r','i','v','e','s',0 };
1805 WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1806 'W','i','n','e','\\','W','i','n','e','\\',
1807 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1808 char tmp[32*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1809 OBJECT_ATTRIBUTES attr;
1810 UNICODE_STRING nameW;
1811 DWORD dummy;
1812 ULONG disp;
1813 HKEY hkey_old, hkey_new;
1814 int i;
1816 attr.Length = sizeof(attr);
1817 attr.RootDirectory = 0;
1818 attr.ObjectName = &nameW;
1819 attr.Attributes = 0;
1820 attr.SecurityDescriptor = NULL;
1821 attr.SecurityQualityOfService = NULL;
1822 RtlInitUnicodeString( &nameW, drive_types_keyW );
1824 if (NtCreateKey( &hkey_new, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) return;
1825 if (disp != REG_CREATED_NEW_KEY)
1827 NtClose( hkey_new );
1828 return;
1831 for (i = 0; i < 26; i++)
1833 RtlInitUnicodeString( &nameW, driveW );
1834 nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
1835 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
1836 RtlInitUnicodeString( &nameW, TypeW );
1837 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
1839 WCHAR valueW[] = {'A',':',0};
1840 WCHAR *type = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1842 valueW[0] = 'A' + i;
1843 RtlInitUnicodeString( &nameW, valueW );
1844 NtSetValueKey( hkey_new, &nameW, 0, REG_SZ, type, (strlenW(type) + 1) * sizeof(WCHAR) );
1845 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1846 'A' + i, debugstr_w(type) );
1848 NtClose( hkey_old );
1850 NtClose( hkey_new );
1854 /* convert the environment variable entries from the old format to the new one */
1855 static void convert_environment( HKEY hkey_current_user )
1857 static const WCHAR wineW[] = {'M','a','c','h','i','n','e','\\',
1858 'S','o','f','t','w','a','r','e','\\',
1859 'W','i','n','e','\\','W','i','n','e','\\',
1860 'C','o','n','f','i','g','\\','W','i','n','e',0};
1861 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
1862 static const WCHAR systemW[] = {'s','y','s','t','e','m',0};
1863 static const WCHAR windirW[] = {'w','i','n','d','i','r',0};
1864 static const WCHAR systemrootW[] = {'S','y','s','t','e','m','r','o','o','t',0};
1865 static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
1866 static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
1867 static const WCHAR tempW[] = {'T','E','M','P',0};
1868 static const WCHAR tmpW[] = {'T','M','P',0};
1869 static const WCHAR pathW[] = {'P','A','T','H',0};
1870 static const WCHAR profileW[] = {'p','r','o','f','i','l','e',0};
1871 static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
1873 char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1874 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1875 OBJECT_ATTRIBUTES attr;
1876 UNICODE_STRING nameW;
1877 DWORD dummy;
1878 ULONG disp;
1879 HKEY hkey_old, hkey_env;
1881 attr.Length = sizeof(attr);
1882 attr.RootDirectory = 0;
1883 attr.ObjectName = &nameW;
1884 attr.Attributes = 0;
1885 attr.SecurityDescriptor = NULL;
1886 attr.SecurityQualityOfService = NULL;
1887 RtlInitUnicodeString( &nameW, wineW );
1889 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return;
1891 attr.RootDirectory = hkey_current_user;
1892 RtlInitUnicodeString( &nameW, envW );
1893 if (NtCreateKey( &hkey_env, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1895 NtClose( hkey_old );
1896 return;
1899 /* Test for existence of TEMP */
1900 RtlInitUnicodeString( &nameW, tempW );
1901 if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1903 /* convert TEMP */
1904 RtlInitUnicodeString( &nameW, tempW );
1905 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1907 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1908 RtlInitUnicodeString( &nameW, tmpW );
1909 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1910 MESSAGE( "Converted temp dir to new entry HKCU\\Environment \"TEMP\" = %s\n",
1911 debugstr_w( (WCHAR*)info->Data ) );
1915 /* Test for existence of PATH */
1916 RtlInitUnicodeString( &nameW, pathW );
1917 if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1919 /* convert PATH */
1920 RtlInitUnicodeString( &nameW, pathW );
1921 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1923 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1924 MESSAGE( "Converted path dir to new entry HKCU\\Environment \"PATH\" = %s\n",
1925 debugstr_w( (WCHAR*)info->Data ) );
1929 /* Test for existence of USERPROFILE */
1930 RtlInitUnicodeString( &nameW, userprofileW );
1931 if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1933 /* convert USERPROFILE */
1934 RtlInitUnicodeString( &nameW, profileW );
1935 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1937 RtlInitUnicodeString( &nameW, userprofileW );
1938 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1939 MESSAGE( "Converted profile dir to new entry HKCU\\Environment \"USERPROFILE\" = %s\n",
1940 debugstr_w( (WCHAR*)info->Data ) );
1944 /* Test for existence of windir */
1945 RtlInitUnicodeString( &nameW, windirW );
1946 if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1948 /* convert windir */
1949 RtlInitUnicodeString( &nameW, windowsW );
1950 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1952 RtlInitUnicodeString( &nameW, windirW );
1953 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1954 RtlInitUnicodeString( &nameW, systemrootW );
1955 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1956 MESSAGE( "Converted windows dir to new entry HKCU\\Environment \"windir\" = %s\n",
1957 debugstr_w( (WCHAR*)info->Data ) );
1961 /* Test for existence of winsysdir */
1962 RtlInitUnicodeString( &nameW, winsysdirW );
1963 if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1965 /* convert winsysdir */
1966 RtlInitUnicodeString( &nameW, systemW );
1967 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1969 RtlInitUnicodeString( &nameW, winsysdirW );
1970 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1971 MESSAGE( "Converted system dir to new entry HKCU\\Environment \"winsysdir\" = %s\n",
1972 debugstr_w( (WCHAR*)info->Data ) );
1975 NtClose( hkey_old );
1976 NtClose( hkey_env );
1980 /* load all registry (native and global and home) */
1981 void SHELL_LoadRegistry( void )
1983 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1984 OBJECT_ATTRIBUTES attr;
1985 UNICODE_STRING nameW;
1986 DWORD count;
1987 ULONG dispos;
1988 BOOL res;
1989 int all, period;
1990 char tmp[1024];
1992 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1993 static const WCHAR UserW[] = {'U','s','e','r',0};
1994 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1995 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1996 'S','o','f','t','w','a','r','e','\\',
1997 'W','i','n','e','\\',
1998 'W','i','n','e','\\',
1999 'C','o','n','f','i','g','\\',
2000 'R','e','g','i','s','t','r','y',0};
2001 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};
2002 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};
2003 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
2004 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
2005 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
2007 TRACE("(void)\n");
2009 attr.Length = sizeof(attr);
2010 attr.RootDirectory = 0;
2011 attr.ObjectName = &nameW;
2012 attr.Attributes = 0;
2013 attr.SecurityDescriptor = NULL;
2014 attr.SecurityQualityOfService = NULL;
2016 RtlInitUnicodeString( &nameW, UserW );
2017 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos );
2018 if (dispos == REG_OPENED_EXISTING_KEY)
2020 /* someone else already loaded the registry */
2021 NtClose( hkey_users );
2022 return;
2025 RtlInitUnicodeString( &nameW, MachineW );
2026 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
2028 attr.RootDirectory = hkey_users;
2029 RtlInitUnicodeString( &nameW, DefaultW );
2030 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
2032 ERR("Cannot create HKEY_USERS/.Default\n" );
2033 ExitProcess(1);
2035 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
2037 _allocate_default_keys();
2039 attr.RootDirectory = 0;
2040 RtlInitUnicodeString( &nameW, RegistryW );
2041 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
2043 /* load windows registry if required */
2045 res = TRUE;
2046 attr.RootDirectory = hkey_config;
2047 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
2048 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2050 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2051 res = !IS_OPTION_FALSE(str[0]);
2053 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
2055 /* load global registry if required */
2057 res = TRUE;
2058 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
2059 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2061 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2062 res = !IS_OPTION_FALSE(str[0]);
2064 if (res)
2066 /* load global registry files (stored in /etc/wine) */
2067 char *p, configfile[MAX_PATHNAME_LEN];
2069 /* Override ETCDIR? */
2070 configfile[0] = 0;
2071 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
2072 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2074 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2075 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
2076 str, (strlenW(str) + 1) * sizeof(WCHAR));
2078 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
2080 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
2082 /* Load the global HKU hive directly from sysconfdir */
2083 p = configfile + strlen(configfile);
2084 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
2085 load_wine_registry( hkey_users, configfile );
2087 /* Load the global machine defaults directly from sysconfdir */
2088 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
2089 load_wine_registry( hkey_local_machine, configfile );
2092 /* setup registry saving */
2094 all = FALSE;
2095 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
2096 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2098 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2099 all = IS_OPTION_FALSE(str[0]);
2102 period = 0;
2103 RtlInitUnicodeString( &nameW, PeriodicSaveW );
2104 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2106 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2107 period = (int)strtolW(str, NULL, 10);
2110 /* load home registry and set saving level (0 for saving everything,
2111 * 1 for saving only modified keys) */
2113 SERVER_START_REQ( load_user_registries )
2115 req->hkey = hkey_current_user;
2116 req->saving = !all;
2117 req->period = period * 1000;
2118 wine_server_call( req );
2120 SERVER_END_REQ;
2122 /* create hardware registry branch */
2124 create_hardware_branch();
2126 /* convert keys from config file to new registry format */
2128 convert_drive_types();
2129 convert_environment( hkey_current_user );
2131 NtClose(hkey_users_default);
2132 NtClose(hkey_current_user);
2133 NtClose(hkey_users);
2134 NtClose(hkey_local_machine);
2135 NtClose(hkey_config);