Change the ARTS_Init() error message from an ERR() to a WARN() since
[wine/multimedia.git] / misc / registry.c
blobffc6a3fbf41c5615020ba5d75fa9fc632a456273
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 /******************************************************************************
692 * _w95_dump_dke [Internal]
694 static int _w95_dump_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
696 _w95dkh * dkh;
697 LPSTR new_key_name = NULL;
699 /* special root key */
700 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
702 /* parse the one subkey */
703 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
704 /* has no sibling keys */
705 return FALSE;
708 /* search subblock */
709 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
710 ERR("dke pointing to missing dkh !\n");
711 return FALSE;
714 if (level <= 0) {
715 /* create new subkey name */
716 size_t len = strlen(key_name);
717 new_key_name = _xmalloc(len+dkh->keynamelen+2);
718 memcpy( new_key_name, key_name, len );
719 if (len) new_key_name[len++] = '\\';
720 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
721 new_key_name[len + dkh->keynamelen] = 0;
723 /* walk sibling keys */
724 if (dke->next != 0xffffffff ) {
725 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
726 free(new_key_name);
727 return FALSE;
731 /* write the key path (something like [Software\\Microsoft\\..]) only if:
732 1) key has some values
733 2) key has no values and no subkeys
735 if (dkh->values > 0) {
736 /* there are some values */
737 fprintf(f,"\n[");
738 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
739 fprintf(f,"]\n");
740 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
741 free(new_key_name);
742 return FALSE;
745 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
746 /* no subkeys and no values */
747 fprintf(f,"\n[");
748 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
749 fprintf(f,"]\n");
751 } else new_key_name = _xstrdup(key_name);
753 /* next sub key */
754 if (dke->nextsub != 0xffffffff) {
755 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
756 free(new_key_name);
757 return FALSE;
761 free(new_key_name);
762 return TRUE;
764 /* end windows 95 loader */
766 /***********************************************************************************/
767 /* windows NT registry loader */
768 /***********************************************************************************/
770 /* NT REGISTRY LOADER */
772 #ifdef HAVE_SYS_MMAN_H
773 # include <sys/mman.h>
774 #endif
776 #ifndef MAP_FAILED
777 #define MAP_FAILED ((LPVOID)-1)
778 #endif
780 #define NT_REG_BLOCK_SIZE 0x1000
782 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
783 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
784 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
785 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
787 /* subblocks of nk */
788 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
789 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
790 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
792 #define NT_REG_KEY_BLOCK_TYPE 0x20
793 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
795 typedef struct {
796 DWORD id; /* 0x66676572 'regf'*/
797 DWORD uk1; /* 0x04 */
798 DWORD uk2; /* 0x08 */
799 FILETIME DateModified; /* 0x0c */
800 DWORD uk3; /* 0x14 */
801 DWORD uk4; /* 0x18 */
802 DWORD uk5; /* 0x1c */
803 DWORD uk6; /* 0x20 */
804 DWORD RootKeyBlock; /* 0x24 */
805 DWORD BlockSize; /* 0x28 */
806 DWORD uk7[116];
807 DWORD Checksum; /* at offset 0x1FC */
808 } nt_regf;
810 typedef struct {
811 DWORD blocksize;
812 BYTE data[1];
813 } nt_hbin_sub;
815 typedef struct {
816 DWORD id; /* 0x6E696268 'hbin' */
817 DWORD off_prev;
818 DWORD off_next;
819 DWORD uk1;
820 DWORD uk2; /* 0x10 */
821 DWORD uk3; /* 0x14 */
822 DWORD uk4; /* 0x18 */
823 DWORD size; /* 0x1C */
824 nt_hbin_sub hbin_sub; /* 0x20 */
825 } nt_hbin;
828 * the value_list consists of offsets to the values (vk)
830 typedef struct {
831 WORD SubBlockId; /* 0x00 0x6B6E */
832 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
833 FILETIME writetime; /* 0x04 */
834 DWORD uk1; /* 0x0C */
835 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
836 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
837 DWORD uk8; /* 0x18 */
838 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
839 DWORD uk2; /* 0x20 */
840 DWORD nr_values; /* 0x24 number of values */
841 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
842 DWORD off_sk; /* 0x2c Offset of the sk-Record */
843 DWORD off_class; /* 0x30 Offset of the Class-Name */
844 DWORD uk3; /* 0x34 */
845 DWORD uk4; /* 0x38 */
846 DWORD uk5; /* 0x3c */
847 DWORD uk6; /* 0x40 */
848 DWORD uk7; /* 0x44 */
849 WORD name_len; /* 0x48 name-length */
850 WORD class_len; /* 0x4a class-name length */
851 char name[1]; /* 0x4c key-name */
852 } nt_nk;
854 typedef struct {
855 DWORD off_nk; /* 0x00 */
856 DWORD name; /* 0x04 */
857 } hash_rec;
859 typedef struct {
860 WORD id; /* 0x00 0x666c */
861 WORD nr_keys; /* 0x06 */
862 hash_rec hash_rec[1];
863 } nt_lf;
866 list of subkeys without hash
868 li --+-->nk
870 +-->nk
872 typedef struct {
873 WORD id; /* 0x00 0x696c */
874 WORD nr_keys;
875 DWORD off_nk[1];
876 } nt_li;
879 this is a intermediate node
881 ri --+-->li--+-->nk
883 | +-->nk
885 +-->li--+-->nk
887 +-->nk
889 typedef struct {
890 WORD id; /* 0x00 0x6972 */
891 WORD nr_li; /* 0x02 number off offsets */
892 DWORD off_li[1]; /* 0x04 points to li */
893 } nt_ri;
895 typedef struct {
896 WORD id; /* 0x00 'vk' */
897 WORD nam_len;
898 DWORD data_len;
899 DWORD data_off;
900 DWORD type;
901 WORD flag;
902 WORD uk1;
903 char name[1];
904 } nt_vk;
907 * gets a value
909 * vk->flag:
910 * 0 value is a default value
911 * 1 the value has a name
913 * vk->data_len
914 * len of the whole data block
915 * - reg_sz (unicode)
916 * bytes including the terminating \0 = 2*(number_of_chars+1)
917 * - reg_dword, reg_binary:
918 * if highest bit of data_len is set data_off contains the value
920 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
922 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
923 struct key_value value;
925 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
926 ERR("unknown block found (0x%04x), please report!\n", vk->id);
927 return FALSE;
930 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
931 value.type = vk->type;
932 value.len = (vk->data_len & 0x7fffffff);
933 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
935 _dump_value(&value,f);
936 free(value.nameW);
938 return TRUE;
941 /* it's called from _nt_dump_lf() */
942 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
945 * get the subkeys
947 * this structure contains the hash of a keyname and points to all
948 * subkeys
950 * exception: if the id is 'il' there are no hash values and every
951 * dword is a offset
953 static int _nt_dump_lf(LPCSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
955 int i;
957 if (lf->id == NT_REG_HASH_BLOCK_ID) {
958 if (subkeys != lf->nr_keys) goto error1;
960 for (i=0; i<lf->nr_keys; i++)
961 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
962 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
963 nt_li * li = (nt_li*)lf;
964 if (subkeys != li->nr_keys) goto error1;
966 for (i=0; i<li->nr_keys; i++)
967 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
968 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
969 nt_ri * ri = (nt_ri*)lf;
970 int li_subkeys = 0;
972 /* count all subkeys */
973 for (i=0; i<ri->nr_li; i++) {
974 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
975 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
976 li_subkeys += li->nr_keys;
979 /* check number */
980 if (subkeys != li_subkeys) goto error1;
982 /* loop through the keys */
983 for (i=0; i<ri->nr_li; i++) {
984 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
985 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
987 } else goto error2;
989 return TRUE;
991 error2:
992 if (lf->id == 0x686c)
993 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
994 else
995 ERR("unknown node id 0x%04x, please report!\n", lf->id);
996 return TRUE;
998 error1:
999 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
1000 return FALSE;
1002 error:
1003 ERR("error reading lf block\n");
1004 return FALSE;
1007 /* _nt_dump_nk [Internal] */
1008 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
1010 unsigned int n;
1011 DWORD *vl;
1012 LPSTR new_key_name = NULL;
1014 TRACE("%s\n", key_name);
1016 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
1017 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1018 return FALSE;
1021 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1022 ERR("registry file corrupt!\n");
1023 return FALSE;
1026 /* create the new key */
1027 if (level <= 0) {
1028 /* create new subkey name */
1029 size_t len = strlen(key_name);
1030 new_key_name = _xmalloc( len+nk->name_len+2 );
1031 memcpy( new_key_name, key_name, len );
1032 if (len) new_key_name[len++] = '\\';
1033 memcpy( new_key_name + len, nk->name, nk->name_len );
1034 new_key_name[len + nk->name_len] = 0;
1036 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1037 1) key has some values
1038 2) key has no values and no subkeys
1040 if (nk->nr_values > 0) {
1041 /* there are some values */
1042 fprintf(f,"\n[");
1043 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1044 fprintf(f,"]\n");
1046 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1047 /* no subkeys and no values */
1048 fprintf(f,"\n[");
1049 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1050 fprintf(f,"]\n");
1053 /* loop trough the value list */
1054 vl = (DWORD *)(base+nk->valuelist_off+4);
1055 for (n=0; n<nk->nr_values; n++) {
1056 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1057 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1058 free(new_key_name);
1059 return FALSE;
1062 } else new_key_name = _xstrdup(key_name);
1064 /* loop through the subkeys */
1065 if (nk->nr_subkeys) {
1066 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1067 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1068 free(new_key_name);
1069 return FALSE;
1073 free(new_key_name);
1074 return TRUE;
1077 /* end nt loader */
1079 /******************************************************************************
1080 * _allocate_default_keys [Internal]
1081 * Registry initialisation, allocates some default keys.
1083 static void _allocate_default_keys(void)
1085 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1086 'P','e','r','f','S','t','a','t','s','\\',
1087 'S','t','a','t','D','a','t','a',0};
1088 HKEY hkey;
1089 OBJECT_ATTRIBUTES attr;
1090 UNICODE_STRING nameW;
1092 TRACE("(void)\n");
1094 attr.Length = sizeof(attr);
1095 attr.RootDirectory = 0;
1096 attr.ObjectName = &nameW;
1097 attr.Attributes = 0;
1098 attr.SecurityDescriptor = NULL;
1099 attr.SecurityQualityOfService = NULL;
1101 RtlInitUnicodeString( &nameW, StatDataW );
1102 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1105 static void get_windows_dir(WCHAR* buffer, unsigned len)
1107 OBJECT_ATTRIBUTES attr;
1108 UNICODE_STRING nameW, keyW;
1109 HKEY hkey;
1111 attr.Length = sizeof(attr);
1112 attr.RootDirectory = 0;
1113 attr.ObjectName = &nameW;
1114 attr.Attributes = 0;
1115 attr.SecurityDescriptor = NULL;
1116 attr.SecurityQualityOfService = NULL;
1118 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1120 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1122 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1123 DWORD count;
1125 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1126 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1127 tmp, sizeof(tmp), &count ))
1129 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1130 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1132 RtlFreeUnicodeString( &keyW );
1134 RtlFreeUnicodeString( &nameW );
1139 #define REG_DONTLOAD -1
1140 #define REG_WIN31 0
1141 #define REG_WIN95 1
1142 #define REG_WINNT 2
1144 /* return the type of native registry [Internal] */
1145 static int _get_reg_type(const WCHAR* windir)
1147 WCHAR tmp[MAX_PATHNAME_LEN];
1148 int ret = REG_WIN31;
1149 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};
1150 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1152 /* test %windir%/system32/config/system --> winnt */
1153 strcpyW(tmp, windir);
1154 strcatW(tmp, nt_reg_pathW);
1155 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1156 ret = REG_WINNT;
1157 else
1159 /* test %windir%/system.dat --> win95 */
1160 strcpyW(tmp, windir);
1161 strcatW(tmp, win9x_reg_pathW);
1162 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1163 ret = REG_WIN95;
1166 return ret;
1169 /* load the registry file in wine format [Internal] */
1170 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1172 WCHAR *buffer;
1173 HANDLE file;
1174 DWORD len;
1175 UNICODE_STRING name;
1176 OBJECT_ATTRIBUTES attr;
1177 IO_STATUS_BLOCK io;
1179 len = MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, NULL, 0 );
1180 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
1181 MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, buffer, len );
1182 RtlInitUnicodeString( &name, buffer );
1184 attr.Length = sizeof(attr);
1185 attr.RootDirectory = 0;
1186 attr.Attributes = 0;
1187 attr.ObjectName = &name;
1188 attr.SecurityDescriptor = NULL;
1189 attr.SecurityQualityOfService = NULL;
1191 if (!NtOpenFile( &file, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
1192 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
1194 SERVER_START_REQ( load_registry )
1196 req->hkey = hkey;
1197 req->file = file;
1198 wine_server_call( req );
1200 SERVER_END_REQ;
1201 CloseHandle( file );
1203 HeapFree( GetProcessHeap(), 0, buffer );
1206 /* generate and return the name of the tmp file and associated stream [Internal] */
1207 static LPSTR _get_tmp_fn(FILE **f)
1209 LPSTR ret;
1210 int tmp_fd,count;
1212 ret = _xmalloc(50);
1213 for (count = 0;;) {
1214 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1215 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1216 if (errno != EEXIST) {
1217 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1218 free(ret);
1219 *f = NULL;
1220 return NULL;
1224 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1225 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1226 close(tmp_fd);
1227 free(ret);
1228 return NULL;
1231 return ret;
1234 /* convert win95 native registry file to wine format [Internal] */
1235 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1237 HANDLE hFile, hMapping;
1238 FILE *f;
1239 void *base;
1240 LPSTR ret = NULL;
1241 OBJECT_ATTRIBUTES attr;
1242 LARGE_INTEGER lg_int;
1243 NTSTATUS nts;
1244 SIZE_T len;
1246 _w95creg *creg;
1247 _w95rgkn *rgkn;
1248 _w95dke *dke, *root_dke;
1250 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1251 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1253 attr.Length = sizeof(attr);
1254 attr.RootDirectory = 0;
1255 attr.ObjectName = NULL;
1256 attr.Attributes = 0;
1257 attr.SecurityDescriptor = NULL;
1258 attr.SecurityQualityOfService = NULL;
1260 lg_int.QuadPart = 0;
1261 nts = NtCreateSection( &hMapping,
1262 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1263 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1264 if (nts != STATUS_SUCCESS) goto error1;
1266 base = NULL; len = 0;
1267 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1268 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1269 PAGE_READONLY);
1270 NtClose( hMapping );
1271 if (nts != STATUS_SUCCESS) goto error1;
1273 /* control signature */
1274 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1275 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1276 debugstr_w(fn));
1277 goto error;
1280 creg = base;
1281 /* load the header (rgkn) */
1282 rgkn = (_w95rgkn*)(creg + 1);
1283 if (rgkn->id != W95_REG_RGKN_ID) {
1284 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1285 goto error;
1287 if (rgkn->root_off != 0x20) {
1288 ERR("rgkn->root_off not 0x20, please report !\n");
1289 goto error;
1291 if (rgkn->last_dke > rgkn->size)
1293 ERR("registry file corrupt! last_dke > size!\n");
1294 goto error;
1296 /* verify last dke */
1297 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1298 if (dke->x1 != 0x80000000)
1299 { /* wrong magic */
1300 ERR("last dke invalid !\n");
1301 goto error;
1303 if (rgkn->size > creg->rgdb_off)
1305 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1306 goto error;
1308 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1309 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1311 ERR("registry file corrupt! invalid root dke !\n");
1312 goto error;
1315 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1316 fprintf(f,"WINE REGISTRY Version 2");
1317 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1318 fclose(f);
1320 error:
1321 if(ret == NULL) {
1322 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1323 ERR("Please report this.\n");
1324 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1327 NtUnmapViewOfSection( GetCurrentProcess(), base );
1328 error1:
1329 NtClose(hFile);
1330 return ret;
1333 /* convert winnt native registry file to wine format [Internal] */
1334 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1336 FILE *f;
1337 void *base;
1338 LPSTR ret = NULL;
1339 HANDLE hFile;
1340 HANDLE hMapping;
1341 OBJECT_ATTRIBUTES attr;
1342 LARGE_INTEGER lg_int;
1343 NTSTATUS nts;
1344 SIZE_T len;
1346 nt_regf *regf;
1347 nt_hbin *hbin;
1348 nt_hbin_sub *hbin_sub;
1349 nt_nk *nk;
1351 TRACE("%s\n", debugstr_w(fn));
1353 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1354 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1355 attr.Length = sizeof(attr);
1356 attr.RootDirectory = 0;
1357 attr.ObjectName = NULL;
1358 attr.Attributes = 0;
1359 attr.SecurityDescriptor = NULL;
1360 attr.SecurityQualityOfService = NULL;
1362 lg_int.QuadPart = 0;
1363 nts = NtCreateSection( &hMapping,
1364 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1365 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1366 if (nts != STATUS_SUCCESS) goto error1;
1368 base = NULL; len = 0;
1369 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1370 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1371 PAGE_READONLY);
1372 NtClose( hMapping );
1373 if (nts != STATUS_SUCCESS) goto error1;
1375 /* control signature */
1376 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1377 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1378 debugstr_w(fn));
1379 goto error;
1382 /* start block */
1383 regf = base;
1385 /* hbin block */
1386 hbin = (nt_hbin*)((char*) base + 0x1000);
1387 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1388 ERR( "hbin block invalid\n");
1389 goto error;
1392 /* hbin_sub block */
1393 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1394 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1395 ERR( "hbin_sub block invalid\n");
1396 goto error;
1399 /* nk block */
1400 nk = (nt_nk*)&(hbin_sub->data[0]);
1401 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1402 ERR( "special nk block not found\n");
1403 goto error;
1406 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1407 fprintf(f,"WINE REGISTRY Version 2");
1408 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1409 fclose(f);
1411 error:
1412 NtUnmapViewOfSection( GetCurrentProcess(), base );
1413 error1:
1414 NtClose(hFile);
1415 return ret;
1418 /* convert native registry to wine format and load it via server call [Internal] */
1419 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1421 LPSTR tmp = NULL;
1423 switch (reg_type) {
1424 case REG_WINNT:
1425 /* FIXME: following function doesn't really convert yet */
1426 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1427 break;
1428 case REG_WIN95:
1429 tmp = _convert_win95_registry_to_wine_format(fn,level);
1430 break;
1431 case REG_WIN31:
1432 ERR("Don't know how to convert native 3.1 registry yet.\n");
1433 break;
1434 default:
1435 ERR("Unknown registry format parameter (%d)\n",reg_type);
1436 break;
1439 if (tmp != NULL) {
1440 load_wine_registry(hkey,tmp);
1441 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1442 debugstr_w(fn), tmp);
1443 unlink(tmp);
1445 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1446 free(tmp);
1449 /* load all native windows registry files [Internal] */
1450 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1451 HKEY hkey_users_default )
1453 int reg_type;
1454 WCHAR windir[MAX_PATHNAME_LEN];
1455 WCHAR path[MAX_PATHNAME_LEN];
1456 OBJECT_ATTRIBUTES attr;
1457 UNICODE_STRING nameW;
1458 HKEY hkey, profile_key;
1459 char tmp[1024];
1460 DWORD dummy;
1462 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1463 'S','o','f','t','w','a','r','e','\\',
1464 'W','i','n','e','\\','W','i','n','e','\\',
1465 'C','o','n','f','i','g','\\','W','i','n','e',0};
1466 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1467 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1468 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1469 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1470 'S','y','s','t','e','m','\\',
1471 'C','l','o','n','e',0};
1473 attr.Length = sizeof(attr);
1474 attr.RootDirectory = 0;
1475 attr.ObjectName = &nameW;
1476 attr.Attributes = 0;
1477 attr.SecurityDescriptor = NULL;
1478 attr.SecurityQualityOfService = NULL;
1480 RtlInitUnicodeString( &nameW, WineW );
1481 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1483 get_windows_dir(windir, sizeof(windir));
1485 reg_type = _get_reg_type(windir);
1486 switch (reg_type) {
1487 case REG_WINNT: {
1488 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1489 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};
1490 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};
1491 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};
1492 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1493 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};
1495 /* user specific ntuser.dat */
1496 RtlInitUnicodeString( &nameW, ProfileW );
1497 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1498 tmp, sizeof(tmp), &dummy ))
1500 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1501 strcatW(path, ntuser_datW);
1502 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1504 else
1506 MESSAGE("When you are running with a native NT directory specify\n");
1507 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1508 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1509 break;
1512 /* default user.dat */
1513 if (hkey_users_default) {
1514 strcpyW(path, windir);
1515 strcatW(path, defaultW);
1516 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1520 * FIXME
1521 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1523 RtlInitUnicodeString( &nameW, System );
1524 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1526 strcpyW(path, windir);
1527 strcatW(path, systemW);
1528 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1529 NtClose( hkey );
1531 RtlInitUnicodeString( &nameW, Software );
1532 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1534 strcpyW(path, windir);
1535 strcatW(path, softwareW);
1536 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1537 NtClose( hkey );
1540 strcpyW(path, windir);
1541 strcatW(path, samW);
1542 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1544 strcpyW(path,windir);
1545 strcatW(path, securityW);
1546 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1548 /* this key is generated when the nt-core booted successfully */
1549 RtlInitUnicodeString( &nameW, Clone );
1550 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1551 break;
1554 case REG_WIN95:
1556 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1557 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1558 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1559 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1561 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1563 strcpyW(path, windir);
1564 strcatW(path, system_datW);
1565 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1567 RtlInitUnicodeString( &nameW, ClassesRootW );
1568 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1570 strcpyW(path, windir);
1571 strcatW(path, classes_datW);
1572 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1573 NtClose( hkey );
1576 RtlInitUnicodeString( &nameW, ProfileW );
1577 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1578 tmp, sizeof(tmp), &dummy ))
1580 /* user specific user.dat */
1581 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1582 strcatW(path, user_datW);
1583 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1585 /* default user.dat */
1586 if (hkey_users_default) {
1587 strcpyW(path, windir);
1588 strcatW(path, user_datW);
1589 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1591 } else {
1592 strcpyW(path, windir);
1593 strcatW(path, user_datW);
1594 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1596 break;
1599 case REG_WIN31:
1601 static const WCHAR reg_datW[] = {'\\','r','e','g','.','d','a','t',0};
1602 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1603 strcpyW(path, windir);
1604 strcatW(path, reg_datW);
1605 _w31_loadreg( path );
1606 break;
1609 case REG_DONTLOAD:
1610 TRACE("REG_DONTLOAD\n");
1611 break;
1613 default:
1614 ERR("switch: no match (%d)\n",reg_type);
1615 break;
1618 if (profile_key) NtClose( profile_key );
1623 /******************************************************************
1624 * init_cdrom_registry
1626 * Initializes registry to contain scsi info about the cdrom in NT.
1627 * All devices (even not real scsi ones) have this info in NT.
1628 * TODO: for now it only works for non scsi devices
1629 * NOTE: programs usually read these registry entries after sending the
1630 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1632 static void init_cdrom_registry( HANDLE handle )
1634 OBJECT_ATTRIBUTES attr;
1635 UNICODE_STRING nameW;
1636 WCHAR dataW[50];
1637 DWORD lenW;
1638 char buffer[40];
1639 DWORD value;
1640 const char *data;
1641 HKEY scsiKey;
1642 HKEY portKey;
1643 HKEY busKey;
1644 HKEY targetKey;
1645 DWORD disp;
1646 IO_STATUS_BLOCK io;
1647 SCSI_ADDRESS scsi_addr;
1649 if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS,
1650 NULL, 0, &scsi_addr, sizeof(scsi_addr) ))
1651 return;
1653 attr.Length = sizeof(attr);
1654 attr.RootDirectory = 0;
1655 attr.ObjectName = &nameW;
1656 attr.Attributes = 0;
1657 attr.SecurityDescriptor = NULL;
1658 attr.SecurityQualityOfService = NULL;
1660 /* Ensure there is Scsi key */
1661 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1662 NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
1663 NULL, REG_OPTION_VOLATILE, &disp ))
1665 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1666 return;
1668 RtlFreeUnicodeString( &nameW );
1670 snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber);
1671 attr.RootDirectory = scsiKey;
1672 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1673 NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
1674 NULL, REG_OPTION_VOLATILE, &disp ))
1676 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1677 return;
1679 RtlFreeUnicodeString( &nameW );
1681 RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
1682 data = "atapi";
1683 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1684 NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1685 RtlFreeUnicodeString( &nameW );
1686 value = 10;
1687 RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
1688 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1689 RtlFreeUnicodeString( &nameW );
1690 value = 0;
1691 #ifdef HDIO_GET_DMA
1693 int fd, dma;
1694 if (!wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL ))
1696 if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma;
1697 wine_server_release_fd( handle, fd );
1700 #endif
1701 RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
1702 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1703 RtlFreeUnicodeString( &nameW );
1705 snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId);
1706 attr.RootDirectory = portKey;
1707 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1708 NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
1709 NULL, REG_OPTION_VOLATILE, &disp ))
1711 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1712 return;
1714 RtlFreeUnicodeString( &nameW );
1716 attr.RootDirectory = busKey;
1717 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
1718 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1719 NULL, REG_OPTION_VOLATILE, &disp ))
1721 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1722 return;
1724 RtlFreeUnicodeString( &nameW );
1725 NtClose( targetKey );
1727 snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId);
1728 attr.RootDirectory = busKey;
1729 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1730 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1731 NULL, REG_OPTION_VOLATILE, &disp ))
1733 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1734 return;
1736 RtlFreeUnicodeString( &nameW );
1738 RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
1739 data = "CdRomPeripheral";
1740 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1741 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1742 RtlFreeUnicodeString( &nameW );
1743 /* FIXME - maybe read the real identifier?? */
1744 RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
1745 data = "Wine CDROM";
1746 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1747 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1748 RtlFreeUnicodeString( &nameW );
1749 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1750 RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
1751 data = "Cdrom0";
1752 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1753 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1754 RtlFreeUnicodeString( &nameW );
1756 NtClose( targetKey );
1757 NtClose( busKey );
1758 NtClose( portKey );
1759 NtClose( scsiKey );
1763 /* create the hardware registry branch */
1764 static void create_hardware_branch(void)
1766 int i;
1767 HANDLE handle;
1768 char drive[] = "\\\\.\\A:";
1770 /* create entries for cdroms */
1771 for (i = 0; i < 26; i++)
1773 drive[4] = 'A' + i;
1774 handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
1775 if (handle == INVALID_HANDLE_VALUE) continue;
1776 init_cdrom_registry( handle );
1777 CloseHandle( handle );
1782 /* convert the drive type entries from the old format to the new one */
1783 static void convert_drive_types(void)
1785 static const WCHAR TypeW[] = {'T','y','p','e',0};
1786 static const WCHAR drive_types_keyW[] = {'M','a','c','h','i','n','e','\\',
1787 'S','o','f','t','w','a','r','e','\\',
1788 'W','i','n','e','\\',
1789 'D','r','i','v','e','s',0 };
1790 WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1791 'W','i','n','e','\\','W','i','n','e','\\',
1792 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1793 char tmp[32*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1794 OBJECT_ATTRIBUTES attr;
1795 UNICODE_STRING nameW;
1796 DWORD dummy;
1797 ULONG disp;
1798 HKEY hkey_old, hkey_new;
1799 int i;
1801 attr.Length = sizeof(attr);
1802 attr.RootDirectory = 0;
1803 attr.ObjectName = &nameW;
1804 attr.Attributes = 0;
1805 attr.SecurityDescriptor = NULL;
1806 attr.SecurityQualityOfService = NULL;
1807 RtlInitUnicodeString( &nameW, drive_types_keyW );
1809 if (NtCreateKey( &hkey_new, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) return;
1810 if (disp != REG_CREATED_NEW_KEY)
1812 NtClose( hkey_new );
1813 return;
1816 for (i = 0; i < 26; i++)
1818 RtlInitUnicodeString( &nameW, driveW );
1819 nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
1820 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
1821 RtlInitUnicodeString( &nameW, TypeW );
1822 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
1824 WCHAR valueW[] = {'A',':',0};
1825 WCHAR *type = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1827 valueW[0] = 'A' + i;
1828 RtlInitUnicodeString( &nameW, valueW );
1829 NtSetValueKey( hkey_new, &nameW, 0, REG_SZ, type, (strlenW(type) + 1) * sizeof(WCHAR) );
1830 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1831 'A' + i, debugstr_w(type) );
1833 NtClose( hkey_old );
1835 NtClose( hkey_new );
1839 /* convert the environment variable entries from the old format to the new one */
1840 static void convert_environment( HKEY hkey_current_user )
1842 static const WCHAR wineW[] = {'M','a','c','h','i','n','e','\\',
1843 'S','o','f','t','w','a','r','e','\\',
1844 'W','i','n','e','\\','W','i','n','e','\\',
1845 'C','o','n','f','i','g','\\','W','i','n','e',0};
1846 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
1847 static const WCHAR systemW[] = {'s','y','s','t','e','m',0};
1848 static const WCHAR windirW[] = {'w','i','n','d','i','r',0};
1849 static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
1850 static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
1851 static const WCHAR tempW[] = {'T','E','M','P',0};
1852 static const WCHAR tmpW[] = {'T','M','P',0};
1853 static const WCHAR pathW[] = {'P','A','T','H',0};
1854 static const WCHAR profileW[] = {'p','r','o','f','i','l','e',0};
1855 static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
1857 char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1858 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1859 OBJECT_ATTRIBUTES attr;
1860 UNICODE_STRING nameW;
1861 DWORD dummy;
1862 ULONG disp;
1863 HKEY hkey_old, hkey_env;
1865 attr.Length = sizeof(attr);
1866 attr.RootDirectory = 0;
1867 attr.ObjectName = &nameW;
1868 attr.Attributes = 0;
1869 attr.SecurityDescriptor = NULL;
1870 attr.SecurityQualityOfService = NULL;
1871 RtlInitUnicodeString( &nameW, wineW );
1873 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return;
1875 attr.RootDirectory = hkey_current_user;
1876 RtlInitUnicodeString( &nameW, envW );
1877 if (NtCreateKey( &hkey_env, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1879 NtClose( hkey_old );
1880 return;
1882 if (disp != REG_CREATED_NEW_KEY) goto done;
1884 /* convert TEMP */
1885 RtlInitUnicodeString( &nameW, tempW );
1886 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1888 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1889 RtlInitUnicodeString( &nameW, tmpW );
1890 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1891 MESSAGE( "Converted temp dir to new entry HKCU\\Environment \"TEMP\" = %s\n",
1892 debugstr_w( (WCHAR*)info->Data ) );
1895 /* convert PATH */
1896 RtlInitUnicodeString( &nameW, pathW );
1897 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1899 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1900 MESSAGE( "Converted path dir to new entry HKCU\\Environment \"PATH\" = %s\n",
1901 debugstr_w( (WCHAR*)info->Data ) );
1904 /* convert USERPROFILE */
1905 RtlInitUnicodeString( &nameW, profileW );
1906 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1908 RtlInitUnicodeString( &nameW, userprofileW );
1909 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1910 MESSAGE( "Converted profile dir to new entry HKCU\\Environment \"USERPROFILE\" = %s\n",
1911 debugstr_w( (WCHAR*)info->Data ) );
1914 /* convert windir */
1915 RtlInitUnicodeString( &nameW, windowsW );
1916 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1918 RtlInitUnicodeString( &nameW, windirW );
1919 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1920 MESSAGE( "Converted windows dir to new entry HKCU\\Environment \"windir\" = %s\n",
1921 debugstr_w( (WCHAR*)info->Data ) );
1924 /* convert winsysdir */
1925 RtlInitUnicodeString( &nameW, systemW );
1926 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1928 RtlInitUnicodeString( &nameW, winsysdirW );
1929 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1930 MESSAGE( "Converted system dir to new entry HKCU\\Environment \"winsysdir\" = %s\n",
1931 debugstr_w( (WCHAR*)info->Data ) );
1934 done:
1935 NtClose( hkey_old );
1936 NtClose( hkey_env );
1940 /* load all registry (native and global and home) */
1941 void SHELL_LoadRegistry( void )
1943 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1944 OBJECT_ATTRIBUTES attr;
1945 UNICODE_STRING nameW;
1946 DWORD count;
1947 ULONG dispos;
1948 BOOL res;
1949 int all, period;
1950 char tmp[1024];
1952 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1953 static const WCHAR UserW[] = {'U','s','e','r',0};
1954 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1955 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1956 'S','o','f','t','w','a','r','e','\\',
1957 'W','i','n','e','\\',
1958 'W','i','n','e','\\',
1959 'C','o','n','f','i','g','\\',
1960 'R','e','g','i','s','t','r','y',0};
1961 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};
1962 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};
1963 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1964 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1965 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1967 TRACE("(void)\n");
1969 attr.Length = sizeof(attr);
1970 attr.RootDirectory = 0;
1971 attr.ObjectName = &nameW;
1972 attr.Attributes = 0;
1973 attr.SecurityDescriptor = NULL;
1974 attr.SecurityQualityOfService = NULL;
1976 RtlInitUnicodeString( &nameW, UserW );
1977 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos );
1978 if (dispos == REG_OPENED_EXISTING_KEY)
1980 /* someone else already loaded the registry */
1981 NtClose( hkey_users );
1982 return;
1985 RtlInitUnicodeString( &nameW, MachineW );
1986 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1988 attr.RootDirectory = hkey_users;
1989 RtlInitUnicodeString( &nameW, DefaultW );
1990 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1992 ERR("Cannot create HKEY_USERS/.Default\n" );
1993 ExitProcess(1);
1995 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1997 _allocate_default_keys();
1999 attr.RootDirectory = 0;
2000 RtlInitUnicodeString( &nameW, RegistryW );
2001 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
2003 /* load windows registry if required */
2005 res = TRUE;
2006 attr.RootDirectory = hkey_config;
2007 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
2008 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2010 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2011 res = !IS_OPTION_FALSE(str[0]);
2013 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
2015 /* load global registry if required */
2017 res = TRUE;
2018 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
2019 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2021 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2022 res = !IS_OPTION_FALSE(str[0]);
2024 if (res)
2026 /* load global registry files (stored in /etc/wine) */
2027 char *p, configfile[MAX_PATHNAME_LEN];
2029 /* Override ETCDIR? */
2030 configfile[0] = 0;
2031 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
2032 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2034 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2035 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
2036 str, (strlenW(str) + 1) * sizeof(WCHAR));
2038 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
2040 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
2042 /* Load the global HKU hive directly from sysconfdir */
2043 p = configfile + strlen(configfile);
2044 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
2045 load_wine_registry( hkey_users, configfile );
2047 /* Load the global machine defaults directly from sysconfdir */
2048 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
2049 load_wine_registry( hkey_local_machine, configfile );
2052 /* setup registry saving */
2054 all = FALSE;
2055 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
2056 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2058 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2059 all = IS_OPTION_FALSE(str[0]);
2062 period = 0;
2063 RtlInitUnicodeString( &nameW, PeriodicSaveW );
2064 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2066 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2067 period = (int)strtolW(str, NULL, 10);
2070 /* load home registry and set saving level (0 for saving everything,
2071 * 1 for saving only modified keys) */
2073 SERVER_START_REQ( load_user_registries )
2075 req->hkey = hkey_current_user;
2076 req->saving = !all;
2077 req->period = period * 1000;
2078 wine_server_call( req );
2080 SERVER_END_REQ;
2082 /* create hardware registry branch */
2084 create_hardware_branch();
2086 /* convert keys from config file to new registry format */
2088 convert_drive_types();
2089 convert_environment( hkey_current_user );
2091 NtClose(hkey_users_default);
2092 NtClose(hkey_current_user);
2093 NtClose(hkey_users);
2094 NtClose(hkey_local_machine);
2095 NtClose(hkey_config);