Taking into account wavemap and midimap there can be up to 8 output
[wine/multimedia.git] / misc / registry.c
blob51aed287313a29c5dfafeea0051c0e5ae2a1c92e
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 /* relative in ~user/.wine/ : */
82 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
83 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
84 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
86 #define MAX_PATHNAME_LEN 1024
88 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
89 'S','o','f','t','w','a','r','e','\\',
90 'C','l','a','s','s','e','s',0};
92 #define IS_OPTION_FALSE(ch) \
93 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
95 /* _xmalloc [Internal] */
96 static void *_xmalloc( size_t size )
98 void *res;
100 res = malloc (size ? size : 1);
101 if (res == NULL) {
102 WARN("Virtual memory exhausted.\n");
103 exit (1);
105 return res;
108 /* _xstrdup [Internal] */
109 static LPSTR _xstrdup(LPCSTR str)
111 LPSTR ret;
112 size_t len = strlen(str) + 1;
114 if (!str) return NULL;
115 ret = _xmalloc( len );
116 memcpy( ret, str, len );
117 return ret;
120 /* convert ansi string to unicode [Internal] */
121 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
123 LPWSTR ret;
124 DWORD len;
126 if (!strA) return NULL;
127 if (RtlMultiByteToUnicodeSize( &len, strA, lenA ) != STATUS_SUCCESS) return NULL;
129 ret = _xmalloc(len+sizeof(WCHAR));
130 RtlMultiByteToUnicodeN(ret, len, NULL, strA, lenA);
131 ret[len / sizeof(WCHAR)] = 0;
132 return ret;
135 /* dump a Unicode string with proper escaping [Internal] */
136 /* FIXME: this code duplicates server/unicode.c */
137 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,const char escape[2])
139 static const char escapes[32] = ".......abtnvfr.............e....";
140 char buffer[256];
141 LPSTR pos = buffer;
142 int count = 0;
144 for (; len; str++, len--)
146 if (pos > buffer + sizeof(buffer) - 8)
148 fwrite( buffer, pos - buffer, 1, f );
149 count += pos - buffer;
150 pos = buffer;
152 if (*str > 127) /* hex escape */
154 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
155 pos += sprintf( pos, "\\x%04x", *str );
156 else
157 pos += sprintf( pos, "\\x%x", *str );
158 continue;
160 if (*str < 32) /* octal or C escape */
162 if (!*str && len == 1) continue; /* do not output terminating NULL */
163 if (escapes[*str] != '.')
164 pos += sprintf( pos, "\\%c", escapes[*str] );
165 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
166 pos += sprintf( pos, "\\%03o", *str );
167 else
168 pos += sprintf( pos, "\\%o", *str );
169 continue;
171 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
172 *pos++ = *str;
174 fwrite( buffer, pos - buffer, 1, f );
175 count += pos - buffer;
176 return count;
179 /* convert ansi string to unicode and dump with proper escaping [Internal] */
180 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,const char escape[2])
182 WCHAR *strW;
183 int ret;
185 if (strA == NULL) return 0;
186 strW = _strdupnAtoW(strA,len);
187 ret = _dump_strW(strW,len,f,escape);
188 free(strW);
189 return ret;
192 /* a key value */
193 /* FIXME: this code duplicates server/registry.c */
194 struct key_value {
195 WCHAR *nameW; /* value name */
196 int type; /* value type */
197 size_t len; /* value data length in bytes */
198 void *data; /* pointer to value data */
201 /* dump a value to a text file */
202 /* FIXME: this code duplicates server/registry.c */
203 static void _dump_value(struct key_value *value,FILE *f)
205 int i, count;
207 if (value->nameW[0]) {
208 fputc( '\"', f );
209 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
210 count += fprintf( f, "\"=" );
212 else count = fprintf( f, "@=" );
214 switch(value->type) {
215 case REG_SZ:
216 case REG_EXPAND_SZ:
217 case REG_MULTI_SZ:
218 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
219 fputc( '\"', f );
220 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
221 fputc( '\"', f );
222 break;
223 case REG_DWORD:
224 if (value->len == sizeof(DWORD)) {
225 DWORD dw;
226 memcpy( &dw, value->data, sizeof(DWORD) );
227 fprintf( f, "dword:%08lx", dw );
228 break;
230 /* else fall through */
231 default:
232 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
233 else count += fprintf( f, "hex(%x):", value->type );
234 for (i = 0; i < value->len; i++) {
235 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
236 if (i < value->len-1) {
237 fputc( ',', f );
238 if (++count > 76) {
239 fprintf( f, "\\\n " );
240 count = 2;
244 break;
246 fputc( '\n', f );
249 /******************************************************************/
250 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
252 reghack - windows 3.11 registry data format demo program.
254 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
255 a combined hash table and tree description, and finally a text table.
257 The header is obvious from the struct header. The taboff1 and taboff2
258 fields are always 0x20, and their usage is unknown.
260 The 8-byte entry table has various entry types.
262 tabent[0] is a root index. The second word has the index of the root of
263 the directory.
264 tabent[1..hashsize] is a hash table. The first word in the hash entry is
265 the index of the key/value that has that hash. Data with the same
266 hash value are on a circular list. The other three words in the
267 hash entry are always zero.
268 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
269 entry: dirent and keyent/valent. They are identified by context.
270 tabent[freeidx] is the first free entry. The first word in a free entry
271 is the index of the next free entry. The last has 0 as a link.
272 The other three words in the free list are probably irrelevant.
274 Entries in text table are preceded by a word at offset-2. This word
275 has the value (2*index)+1, where index is the referring keyent/valent
276 entry in the table. I have no suggestion for the 2* and the +1.
277 Following the word, there are N bytes of data, as per the keyent/valent
278 entry length. The offset of the keyent/valent entry is from the start
279 of the text table to the first data byte.
281 This information is not available from Microsoft. The data format is
282 deduced from the reg.dat file by me. Mistakes may
283 have been made. I claim no rights and give no guarantees for this program.
285 Tor Sjøwall, tor@sn.no
288 /* reg.dat header format */
289 struct _w31_header {
290 char cookie[8]; /* 'SHCC3.10' */
291 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
292 unsigned long taboff2; /* offset of index table (??) = 0x20 */
293 unsigned long tabcnt; /* number of entries in index table */
294 unsigned long textoff; /* offset of text part */
295 unsigned long textsize; /* byte size of text part */
296 unsigned short hashsize; /* hash size */
297 unsigned short freeidx; /* free index */
300 /* generic format of table entries */
301 struct _w31_tabent {
302 unsigned short w0, w1, w2, w3;
305 /* directory tabent: */
306 struct _w31_dirent {
307 unsigned short sibling_idx; /* table index of sibling dirent */
308 unsigned short child_idx; /* table index of child dirent */
309 unsigned short key_idx; /* table index of key keyent */
310 unsigned short value_idx; /* table index of value valent */
313 /* key tabent: */
314 struct _w31_keyent {
315 unsigned short hash_idx; /* hash chain index for string */
316 unsigned short refcnt; /* reference count */
317 unsigned short length; /* length of string */
318 unsigned short string_off; /* offset of string in text table */
321 /* value tabent: */
322 struct _w31_valent {
323 unsigned short hash_idx; /* hash chain index for string */
324 unsigned short refcnt; /* reference count */
325 unsigned short length; /* length of string */
326 unsigned short string_off; /* offset of string in text table */
329 /* recursive helper function to display a directory tree [Internal] */
330 static void _w31_dumptree(unsigned short idx, unsigned char *txt,
331 struct _w31_tabent *tab, struct _w31_header *head,
332 HKEY hkey, ULONG lastmodified, int level)
334 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
335 struct _w31_dirent *dir;
336 struct _w31_keyent *key;
337 struct _w31_valent *val;
338 HKEY subkey = 0;
339 OBJECT_ATTRIBUTES attr;
340 UNICODE_STRING nameW, valueW;
341 static WCHAR tail[400];
343 attr.Length = sizeof(attr);
344 attr.RootDirectory = hkey;
345 attr.ObjectName = &nameW;
346 attr.Attributes = 0;
347 attr.SecurityDescriptor = NULL;
348 attr.SecurityQualityOfService = NULL;
349 RtlInitUnicodeString( &valueW, NULL );
351 while (idx!=0) {
352 dir=(struct _w31_dirent*)&tab[idx];
354 if (dir->key_idx) {
355 DWORD len;
356 key = (struct _w31_keyent*)&tab[dir->key_idx];
358 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
359 &txt[key->string_off], key->length);
360 tail[len/sizeof(WCHAR)] = 0;
362 /* all toplevel entries AND the entries in the
363 * toplevel subdirectory belong to \SOFTWARE\Classes
365 if (!level && !strcmpW(tail,classesW))
367 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
368 idx=dir->sibling_idx;
369 continue;
372 if (subkey) NtClose( subkey );
373 RtlInitUnicodeString( &nameW, tail );
374 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
376 /* only add if leaf node or valued node */
377 if (dir->value_idx!=0||dir->child_idx==0) {
378 if (dir->value_idx) {
379 DWORD len;
380 val=(struct _w31_valent*)&tab[dir->value_idx];
381 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
382 &txt[val->string_off], val->length);
383 tail[len/sizeof(WCHAR)] = 0;
384 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
387 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
388 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
389 idx=dir->sibling_idx;
391 if (subkey) NtClose( subkey );
395 /******************************************************************************
396 * _w31_loadreg [Internal]
398 static void _w31_loadreg(void)
400 HANDLE hf;
401 HKEY root;
402 OBJECT_ATTRIBUTES attr;
403 UNICODE_STRING nameW;
404 struct _w31_header head;
405 struct _w31_tabent* tab = NULL;
406 unsigned char* txt = NULL;
407 unsigned int len;
408 OFSTRUCT ofs;
409 ULONG lastmodified;
410 NTSTATUS status;
411 IO_STATUS_BLOCK iosb;
412 FILE_POSITION_INFORMATION fpi;
413 FILE_BASIC_INFORMATION fbi;
415 TRACE("(void)\n");
417 hf = (HANDLE)OpenFile("reg.dat",&ofs,OF_READ);
418 if (hf==(HANDLE)HFILE_ERROR) return;
420 /* read & dump header */
421 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
422 &head, sizeof(head), NULL, NULL) != STATUS_SUCCESS ||
423 iosb.Information != sizeof(head))
425 ERR("reg.dat is too short.\n");
426 goto done;
428 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie)) != 0)
430 ERR("reg.dat has bad signature.\n");
431 goto done;
434 len = head.tabcnt * sizeof(struct _w31_tabent);
435 /* read and dump index table */
436 tab = _xmalloc(len);
437 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
438 tab, len, NULL, NULL) != STATUS_SUCCESS ||
439 iosb.Information != len)
441 ERR("couldn't read index table (%d bytes).\n",len);
442 goto done;
445 /* read text */
446 txt = _xmalloc(head.textsize);
447 fpi.CurrentByteOffset.u.LowPart = head.textoff;
448 fpi.CurrentByteOffset.u.HighPart = 0;
449 if (NtSetInformationFile(hf, &iosb, &fpi, sizeof(fpi),
450 FilePositionInformation) != STATUS_SUCCESS)
452 ERR("couldn't seek to textblock.\n");
453 goto done;
455 status = NtReadFile(hf, 0, NULL, NULL, &iosb, txt, head.textsize, NULL, NULL);
456 if (!(status == STATUS_SUCCESS || status == STATUS_END_OF_FILE) ||
457 iosb.Information != head.textsize)
459 ERR("textblock too short (%d instead of %ld).\n", len, head.textsize);
460 goto done;
462 if (NtQueryInformationFile(hf, &iosb, &fbi, sizeof(fbi),
463 FileBasicInformation) != STATUS_SUCCESS)
465 ERR("Couldn't get basic information.\n");
466 goto done;
468 RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &lastmodified);
470 attr.Length = sizeof(attr);
471 attr.RootDirectory = 0;
472 attr.ObjectName = &nameW;
473 attr.Attributes = 0;
474 attr.SecurityDescriptor = NULL;
475 attr.SecurityQualityOfService = NULL;
476 RtlInitUnicodeString( &nameW, ClassesRootW );
478 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
480 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
481 NtClose( root );
483 done:
484 if (tab) free(tab);
485 if (txt) free(txt);
486 NtClose(hf);
487 return;
490 /***********************************************************************************/
491 /* windows 95 registry loader */
492 /***********************************************************************************/
494 /* SECTION 1: main header
496 * once at offset 0
498 #define W95_REG_CREG_ID 0x47455243
500 typedef struct {
501 DWORD id; /* "CREG" = W95_REG_CREG_ID */
502 DWORD version; /* ???? 0x00010000 */
503 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
504 DWORD uk2; /* 0x0c */
505 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
506 WORD uk3;
507 DWORD uk[3];
508 /* rgkn */
509 } _w95creg;
511 /* SECTION 2: Directory information (tree structure)
513 * once on offset 0x20
515 * structure: [rgkn][dke]* (repeat till last_dke is reached)
517 #define W95_REG_RGKN_ID 0x4e4b4752
519 typedef struct {
520 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
521 DWORD size; /* Size of the RGKN-block */
522 DWORD root_off; /* Rel. Offset of the root-record */
523 DWORD last_dke; /* Offset to last DKE ? */
524 DWORD uk[4];
525 } _w95rgkn;
527 /* Disk Key Entry Structure
529 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
530 * hive itself. It looks the same like other keys. Even the ID-number can
531 * be any value.
533 * The "hash"-value is a value representing the key's name. Windows will not
534 * search for the name, but for a matching hash-value. if it finds one, it
535 * will compare the actual string info, otherwise continue with the next key.
536 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
537 * of the string which are smaller than 0x80 (128) to this D-Word.
539 * If you want to modify key names, also modify the hash-values, since they
540 * cannot be found again (although they would be displayed in REGEDIT)
541 * End of list-pointers are filled with 0xFFFFFFFF
543 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
544 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
545 * structure) and reading another RGDB_section.
547 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
548 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
549 * The remaining space between last_dke and the offset calculated from
550 * rgkn->size seems to be free for use for more dke:s.
551 * So it seems if more dke:s are added, they are added to that space and
552 * last_dke is grown, and in case that "free" space is out, the space
553 * gets grown and rgkn->size gets adjusted.
555 * there is a one to one relationship between dke and dkh
557 /* key struct, once per key */
558 typedef struct {
559 DWORD x1; /* Free entry indicator(?) */
560 DWORD hash; /* sum of bytes of keyname */
561 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
562 DWORD prevlvl; /* offset of previous key */
563 DWORD nextsub; /* offset of child key */
564 DWORD next; /* offset of sibling key */
565 WORD nrLS; /* id inside the rgdb block */
566 WORD nrMS; /* number of the rgdb block */
567 } _w95dke;
569 /* SECTION 3: key information, values and data
571 * structure:
572 * section: [blocks]* (repeat creg->rgdb_num times)
573 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
574 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
576 * An interesting relationship exists in RGDB_section. The DWORD value
577 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
578 * I have no idea at the moment what this means. (Kevin Cozens)
581 /* block header, once per block */
582 #define W95_REG_RGDB_ID 0x42444752
584 typedef struct {
585 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
586 DWORD size; /* 0x04 */
587 DWORD uk1; /* 0x08 */
588 DWORD uk2; /* 0x0c */
589 DWORD uk3; /* 0x10 */
590 DWORD uk4; /* 0x14 */
591 DWORD uk5; /* 0x18 */
592 DWORD uk6; /* 0x1c */
593 /* dkh */
594 } _w95rgdb;
596 /* Disk Key Header structure (RGDB part), once per key */
597 typedef struct {
598 DWORD nextkeyoff; /* 0x00 offset to next dkh */
599 WORD nrLS; /* 0x04 id inside the rgdb block */
600 WORD nrMS; /* 0x06 number of the rgdb block */
601 DWORD bytesused; /* 0x08 */
602 WORD keynamelen; /* 0x0c len of name */
603 WORD values; /* 0x0e number of values */
604 DWORD xx1; /* 0x10 */
605 char name[1]; /* 0x14 */
606 /* dkv */ /* 0x14 + keynamelen */
607 } _w95dkh;
609 /* Disk Key Value structure, once per value */
610 typedef struct {
611 DWORD type; /* 0x00 */
612 DWORD x1; /* 0x04 */
613 WORD valnamelen; /* 0x08 length of name, 0 is default key */
614 WORD valdatalen; /* 0x0A length of data */
615 char name[1]; /* 0x0c */
616 /* raw data */ /* 0x0c + valnamelen */
617 } _w95dkv;
619 /******************************************************************************
620 * _w95_lookup_dkh [Internal]
622 * seeks the dkh belonging to a dke
624 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
626 _w95rgdb * rgdb;
627 _w95dkh * dkh;
628 int i;
630 /* get the beginning of the rgdb datastore */
631 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
633 /* check: requested block < last_block) */
634 if (creg->rgdb_num <= nrMS) {
635 ERR("registry file corrupt! requested block no. beyond end.\n");
636 goto error;
639 /* find the right block */
640 for(i=0; i<nrMS ;i++) {
641 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
642 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
643 goto error;
645 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
648 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
650 do {
651 if(nrLS==dkh->nrLS ) return dkh;
652 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
653 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
655 error:
656 return NULL;
659 /******************************************************************************
660 * _w95_dump_dkv [Internal]
662 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
664 _w95dkv * dkv;
665 int i;
667 /* first value block */
668 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
670 /* loop through the values */
671 for (i=0; i< dkh->values; i++) {
672 struct key_value value;
673 WCHAR *pdata;
675 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
676 value.type = dkv->type;
677 value.len = dkv->valdatalen;
679 value.data = &(dkv->name[dkv->valnamelen]);
680 pdata = NULL;
681 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
682 pdata = _strdupnAtoW(value.data,value.len);
683 value.len *= 2;
685 if (pdata != NULL) value.data = pdata;
687 _dump_value(&value,f);
688 free(value.nameW);
689 if (pdata != NULL) free(pdata);
691 /* next value */
692 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
694 return TRUE;
697 /******************************************************************************
698 * _w95_dump_dke [Internal]
700 static int _w95_dump_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
702 _w95dkh * dkh;
703 LPSTR new_key_name = NULL;
705 /* special root key */
706 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
708 /* parse the one subkey */
709 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
710 /* has no sibling keys */
711 return FALSE;
714 /* search subblock */
715 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
716 ERR("dke pointing to missing dkh !\n");
717 return FALSE;
720 if (level <= 0) {
721 /* create new subkey name */
722 size_t len = strlen(key_name);
723 new_key_name = _xmalloc(len+dkh->keynamelen+2);
724 memcpy( new_key_name, key_name, len );
725 if (len) new_key_name[len++] = '\\';
726 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
727 new_key_name[len + dkh->keynamelen] = 0;
729 /* walk sibling keys */
730 if (dke->next != 0xffffffff ) {
731 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
732 free(new_key_name);
733 return FALSE;
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 * _set_registry_levels [Internal]
1088 * set level to 0 for loading system files
1089 * set level to 1 for loading user files
1091 static void _set_registry_levels(int level,int saving,int period)
1093 SERVER_START_REQ( set_registry_levels )
1095 req->current = level;
1096 req->saving = saving;
1097 req->period = period;
1098 wine_server_call( req );
1100 SERVER_END_REQ;
1103 /* _save_at_exit [Internal] */
1104 static void _save_at_exit(HKEY hkey,LPCSTR path)
1106 LPCSTR confdir = wine_get_config_dir();
1108 SERVER_START_REQ( save_registry_atexit )
1110 req->hkey = hkey;
1111 wine_server_add_data( req, confdir, strlen(confdir) );
1112 wine_server_add_data( req, path, strlen(path)+1 );
1113 wine_server_call( req );
1115 SERVER_END_REQ;
1118 /******************************************************************************
1119 * _allocate_default_keys [Internal]
1120 * Registry initialisation, allocates some default keys.
1122 static void _allocate_default_keys(void)
1124 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1125 'P','e','r','f','S','t','a','t','s','\\',
1126 'S','t','a','t','D','a','t','a',0};
1127 HKEY hkey;
1128 OBJECT_ATTRIBUTES attr;
1129 UNICODE_STRING nameW;
1131 TRACE("(void)\n");
1133 attr.Length = sizeof(attr);
1134 attr.RootDirectory = 0;
1135 attr.ObjectName = &nameW;
1136 attr.Attributes = 0;
1137 attr.SecurityDescriptor = NULL;
1138 attr.SecurityQualityOfService = NULL;
1140 RtlInitUnicodeString( &nameW, StatDataW );
1141 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1144 static void get_windows_dir(WCHAR* buffer, unsigned len)
1146 OBJECT_ATTRIBUTES attr;
1147 UNICODE_STRING nameW, keyW;
1148 HKEY hkey;
1150 attr.Length = sizeof(attr);
1151 attr.RootDirectory = 0;
1152 attr.ObjectName = &nameW;
1153 attr.Attributes = 0;
1154 attr.SecurityDescriptor = NULL;
1155 attr.SecurityQualityOfService = NULL;
1157 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1159 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1161 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1162 DWORD count;
1164 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1165 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1166 tmp, sizeof(tmp), &count ))
1168 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1169 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1171 RtlFreeUnicodeString( &keyW );
1173 RtlFreeUnicodeString( &nameW );
1178 #define REG_DONTLOAD -1
1179 #define REG_WIN31 0
1180 #define REG_WIN95 1
1181 #define REG_WINNT 2
1183 /* return the type of native registry [Internal] */
1184 static int _get_reg_type(const WCHAR* windir)
1186 WCHAR tmp[MAX_PATHNAME_LEN];
1187 int ret = REG_WIN31;
1188 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};
1189 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1191 /* test %windir%/system32/config/system --> winnt */
1192 strcpyW(tmp, windir);
1193 strcatW(tmp, nt_reg_pathW);
1194 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1195 ret = REG_WINNT;
1196 else
1198 /* test %windir%/system.dat --> win95 */
1199 strcpyW(tmp, windir);
1200 strcatW(tmp, win9x_reg_pathW);
1201 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1202 ret = REG_WIN95;
1205 return ret;
1208 /* load the registry file in wine format [Internal] */
1209 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1211 WCHAR *buffer;
1212 HANDLE file;
1213 DWORD len;
1214 UNICODE_STRING name;
1215 OBJECT_ATTRIBUTES attr;
1216 IO_STATUS_BLOCK io;
1218 len = MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, NULL, 0 );
1219 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
1220 MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, buffer, len );
1221 RtlInitUnicodeString( &name, buffer );
1223 attr.Length = sizeof(attr);
1224 attr.RootDirectory = 0;
1225 attr.Attributes = 0;
1226 attr.ObjectName = &name;
1227 attr.SecurityDescriptor = NULL;
1228 attr.SecurityQualityOfService = NULL;
1230 if (!NtOpenFile( &file, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
1231 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
1233 SERVER_START_REQ( load_registry )
1235 req->hkey = hkey;
1236 req->file = file;
1237 wine_server_call( req );
1239 SERVER_END_REQ;
1240 CloseHandle( file );
1242 HeapFree( GetProcessHeap(), 0, buffer );
1245 /* generate and return the name of the tmp file and associated stream [Internal] */
1246 static LPSTR _get_tmp_fn(FILE **f)
1248 LPSTR ret;
1249 int tmp_fd,count;
1251 ret = _xmalloc(50);
1252 for (count = 0;;) {
1253 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1254 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1255 if (errno != EEXIST) {
1256 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1257 free(ret);
1258 *f = NULL;
1259 return NULL;
1263 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1264 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1265 close(tmp_fd);
1266 free(ret);
1267 return NULL;
1270 return ret;
1273 /* convert win95 native registry file to wine format [Internal] */
1274 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1276 HANDLE hFile, hMapping;
1277 FILE *f;
1278 void *base;
1279 LPSTR ret = NULL;
1280 OBJECT_ATTRIBUTES attr;
1281 LARGE_INTEGER lg_int;
1282 NTSTATUS nts;
1283 SIZE_T len;
1285 _w95creg *creg;
1286 _w95rgkn *rgkn;
1287 _w95dke *dke, *root_dke;
1289 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1290 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1292 attr.Length = sizeof(attr);
1293 attr.RootDirectory = 0;
1294 attr.ObjectName = NULL;
1295 attr.Attributes = 0;
1296 attr.SecurityDescriptor = NULL;
1297 attr.SecurityQualityOfService = NULL;
1299 lg_int.QuadPart = 0;
1300 nts = NtCreateSection( &hMapping,
1301 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1302 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1303 if (nts != STATUS_SUCCESS) goto error1;
1305 base = NULL; len = 0;
1306 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1307 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1308 PAGE_READONLY);
1309 NtClose( hMapping );
1310 if (nts != STATUS_SUCCESS) goto error1;
1312 /* control signature */
1313 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1314 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1315 debugstr_w(fn));
1316 goto error;
1319 creg = base;
1320 /* load the header (rgkn) */
1321 rgkn = (_w95rgkn*)(creg + 1);
1322 if (rgkn->id != W95_REG_RGKN_ID) {
1323 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1324 goto error;
1326 if (rgkn->root_off != 0x20) {
1327 ERR("rgkn->root_off not 0x20, please report !\n");
1328 goto error;
1330 if (rgkn->last_dke > rgkn->size)
1332 ERR("registry file corrupt! last_dke > size!\n");
1333 goto error;
1335 /* verify last dke */
1336 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1337 if (dke->x1 != 0x80000000)
1338 { /* wrong magic */
1339 ERR("last dke invalid !\n");
1340 goto error;
1342 if (rgkn->size > creg->rgdb_off)
1344 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1345 goto error;
1347 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1348 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1350 ERR("registry file corrupt! invalid root dke !\n");
1351 goto error;
1354 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1355 fprintf(f,"WINE REGISTRY Version 2");
1356 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1357 fclose(f);
1359 error:
1360 if(ret == NULL) {
1361 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1362 ERR("Please report this.\n");
1363 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1366 NtUnmapViewOfSection( GetCurrentProcess(), base );
1367 error1:
1368 NtClose(hFile);
1369 return ret;
1372 /* convert winnt native registry file to wine format [Internal] */
1373 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1375 FILE *f;
1376 void *base;
1377 LPSTR ret = NULL;
1378 HANDLE hFile;
1379 HANDLE hMapping;
1380 OBJECT_ATTRIBUTES attr;
1381 LARGE_INTEGER lg_int;
1382 NTSTATUS nts;
1383 SIZE_T len;
1385 nt_regf *regf;
1386 nt_hbin *hbin;
1387 nt_hbin_sub *hbin_sub;
1388 nt_nk *nk;
1390 TRACE("%s\n", debugstr_w(fn));
1392 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1393 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1394 attr.Length = sizeof(attr);
1395 attr.RootDirectory = 0;
1396 attr.ObjectName = NULL;
1397 attr.Attributes = 0;
1398 attr.SecurityDescriptor = NULL;
1399 attr.SecurityQualityOfService = NULL;
1401 lg_int.QuadPart = 0;
1402 nts = NtCreateSection( &hMapping,
1403 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1404 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1405 if (nts != STATUS_SUCCESS) goto error1;
1407 base = NULL; len = 0;
1408 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1409 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1410 PAGE_READONLY);
1411 NtClose( hMapping );
1412 if (nts != STATUS_SUCCESS) goto error1;
1414 /* control signature */
1415 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1416 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1417 debugstr_w(fn));
1418 goto error;
1421 /* start block */
1422 regf = base;
1424 /* hbin block */
1425 hbin = (nt_hbin*)((char*) base + 0x1000);
1426 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1427 ERR( "hbin block invalid\n");
1428 goto error;
1431 /* hbin_sub block */
1432 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1433 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1434 ERR( "hbin_sub block invalid\n");
1435 goto error;
1438 /* nk block */
1439 nk = (nt_nk*)&(hbin_sub->data[0]);
1440 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1441 ERR( "special nk block not found\n");
1442 goto error;
1445 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1446 fprintf(f,"WINE REGISTRY Version 2");
1447 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1448 fclose(f);
1450 error:
1451 NtUnmapViewOfSection( GetCurrentProcess(), base );
1452 error1:
1453 NtClose(hFile);
1454 return ret;
1457 /* convert native registry to wine format and load it via server call [Internal] */
1458 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1460 LPSTR tmp = NULL;
1462 switch (reg_type) {
1463 case REG_WINNT:
1464 /* FIXME: following function doesn't really convert yet */
1465 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1466 break;
1467 case REG_WIN95:
1468 tmp = _convert_win95_registry_to_wine_format(fn,level);
1469 break;
1470 case REG_WIN31:
1471 ERR("Don't know how to convert native 3.1 registry yet.\n");
1472 break;
1473 default:
1474 ERR("Unknown registry format parameter (%d)\n",reg_type);
1475 break;
1478 if (tmp != NULL) {
1479 load_wine_registry(hkey,tmp);
1480 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1481 debugstr_w(fn), tmp);
1482 unlink(tmp);
1484 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1485 free(tmp);
1488 /* load all native windows registry files [Internal] */
1489 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1490 HKEY hkey_users_default )
1492 int reg_type;
1493 WCHAR windir[MAX_PATHNAME_LEN];
1494 WCHAR path[MAX_PATHNAME_LEN];
1495 OBJECT_ATTRIBUTES attr;
1496 UNICODE_STRING nameW;
1497 HKEY hkey, profile_key;
1498 char tmp[1024];
1499 DWORD dummy;
1501 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1502 'S','o','f','t','w','a','r','e','\\',
1503 'W','i','n','e','\\','W','i','n','e','\\',
1504 'C','o','n','f','i','g','\\','W','i','n','e',0};
1505 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1506 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1507 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1508 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1509 'S','y','s','t','e','m','\\',
1510 'C','l','o','n','e',0};
1512 attr.Length = sizeof(attr);
1513 attr.RootDirectory = 0;
1514 attr.ObjectName = &nameW;
1515 attr.Attributes = 0;
1516 attr.SecurityDescriptor = NULL;
1517 attr.SecurityQualityOfService = NULL;
1519 RtlInitUnicodeString( &nameW, WineW );
1520 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1522 get_windows_dir(windir, sizeof(windir));
1524 reg_type = _get_reg_type(windir);
1525 switch (reg_type) {
1526 case REG_WINNT: {
1527 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1528 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};
1529 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};
1530 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};
1531 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1532 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};
1534 /* user specific ntuser.dat */
1535 RtlInitUnicodeString( &nameW, ProfileW );
1536 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1537 tmp, sizeof(tmp), &dummy ))
1539 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1540 strcatW(path, ntuser_datW);
1541 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1543 else
1545 MESSAGE("When you are running with a native NT directory specify\n");
1546 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1547 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1548 break;
1551 /* default user.dat */
1552 if (hkey_users_default) {
1553 strcpyW(path, windir);
1554 strcatW(path, defaultW);
1555 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1559 * FIXME
1560 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1562 RtlInitUnicodeString( &nameW, System );
1563 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1565 strcpyW(path, windir);
1566 strcatW(path, systemW);
1567 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1568 NtClose( hkey );
1570 RtlInitUnicodeString( &nameW, Software );
1571 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1573 strcpyW(path, windir);
1574 strcatW(path, softwareW);
1575 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1576 NtClose( hkey );
1579 strcpyW(path, windir);
1580 strcatW(path, samW);
1581 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1583 strcpyW(path,windir);
1584 strcatW(path, securityW);
1585 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1587 /* this key is generated when the nt-core booted successfully */
1588 RtlInitUnicodeString( &nameW, Clone );
1589 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1590 break;
1593 case REG_WIN95:
1595 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1596 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1597 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1598 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1600 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1602 strcpyW(path, windir);
1603 strcatW(path, system_datW);
1604 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1606 RtlInitUnicodeString( &nameW, ClassesRootW );
1607 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1609 strcpyW(path, windir);
1610 strcatW(path, classes_datW);
1611 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1612 NtClose( hkey );
1615 RtlInitUnicodeString( &nameW, ProfileW );
1616 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1617 tmp, sizeof(tmp), &dummy ))
1619 /* user specific user.dat */
1620 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1621 strcatW(path, user_datW);
1622 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1624 /* default user.dat */
1625 if (hkey_users_default) {
1626 strcpyW(path, windir);
1627 strcatW(path, user_datW);
1628 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1630 } else {
1631 strcpyW(path, windir);
1632 strcatW(path, user_datW);
1633 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1635 break;
1638 case REG_WIN31:
1639 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1640 _w31_loadreg();
1641 break;
1643 case REG_DONTLOAD:
1644 TRACE("REG_DONTLOAD\n");
1645 break;
1647 default:
1648 ERR("switch: no match (%d)\n",reg_type);
1649 break;
1652 if (profile_key) NtClose( profile_key );
1655 /* load home registry files (stored in ~/.wine) [Internal] */
1656 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1657 HKEY hkey_users_default )
1659 LPCSTR confdir = wine_get_config_dir();
1660 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1662 strcpy(tmp,confdir);
1663 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1664 load_wine_registry(hkey_users_default,tmp);
1666 strcpy(tmp,confdir);
1667 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1668 load_wine_registry(hkey_current_user,tmp);
1670 strcpy(tmp,confdir);
1671 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1672 load_wine_registry(hkey_local_machine,tmp);
1674 free(tmp);
1678 /******************************************************************
1679 * init_cdrom_registry
1681 * Initializes registry to contain scsi info about the cdrom in NT.
1682 * All devices (even not real scsi ones) have this info in NT.
1683 * TODO: for now it only works for non scsi devices
1684 * NOTE: programs usually read these registry entries after sending the
1685 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1687 static void init_cdrom_registry( HANDLE handle )
1689 OBJECT_ATTRIBUTES attr;
1690 UNICODE_STRING nameW;
1691 WCHAR dataW[50];
1692 DWORD lenW;
1693 char buffer[40];
1694 DWORD value;
1695 const char *data;
1696 HKEY scsiKey;
1697 HKEY portKey;
1698 HKEY busKey;
1699 HKEY targetKey;
1700 DWORD disp;
1701 IO_STATUS_BLOCK io;
1702 SCSI_ADDRESS scsi_addr;
1704 if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS,
1705 NULL, 0, &scsi_addr, sizeof(scsi_addr) ))
1706 return;
1708 attr.Length = sizeof(attr);
1709 attr.RootDirectory = 0;
1710 attr.ObjectName = &nameW;
1711 attr.Attributes = 0;
1712 attr.SecurityDescriptor = NULL;
1713 attr.SecurityQualityOfService = NULL;
1715 /* Ensure there is Scsi key */
1716 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1717 NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
1718 NULL, REG_OPTION_VOLATILE, &disp ))
1720 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1721 return;
1723 RtlFreeUnicodeString( &nameW );
1725 snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber);
1726 attr.RootDirectory = scsiKey;
1727 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1728 NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
1729 NULL, REG_OPTION_VOLATILE, &disp ))
1731 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1732 return;
1734 RtlFreeUnicodeString( &nameW );
1736 RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
1737 data = "atapi";
1738 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1739 NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1740 RtlFreeUnicodeString( &nameW );
1741 value = 10;
1742 RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
1743 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1744 RtlFreeUnicodeString( &nameW );
1745 value = 0;
1746 #ifdef HDIO_GET_DMA
1748 int fd, dma;
1749 if (!wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL ))
1751 if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma;
1752 wine_server_release_fd( handle, fd );
1755 #endif
1756 RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
1757 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1758 RtlFreeUnicodeString( &nameW );
1760 snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId);
1761 attr.RootDirectory = portKey;
1762 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1763 NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
1764 NULL, REG_OPTION_VOLATILE, &disp ))
1766 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1767 return;
1769 RtlFreeUnicodeString( &nameW );
1771 attr.RootDirectory = busKey;
1772 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
1773 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1774 NULL, REG_OPTION_VOLATILE, &disp ))
1776 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1777 return;
1779 RtlFreeUnicodeString( &nameW );
1780 NtClose( targetKey );
1782 snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId);
1783 attr.RootDirectory = busKey;
1784 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1785 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1786 NULL, REG_OPTION_VOLATILE, &disp ))
1788 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1789 return;
1791 RtlFreeUnicodeString( &nameW );
1793 RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
1794 data = "CdRomPeripheral";
1795 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1796 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1797 RtlFreeUnicodeString( &nameW );
1798 /* FIXME - maybe read the real identifier?? */
1799 RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
1800 data = "Wine CDROM";
1801 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1802 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1803 RtlFreeUnicodeString( &nameW );
1804 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1805 RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
1806 data = "Cdrom0";
1807 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1808 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1809 RtlFreeUnicodeString( &nameW );
1811 NtClose( targetKey );
1812 NtClose( busKey );
1813 NtClose( portKey );
1814 NtClose( scsiKey );
1818 /* create the hardware registry branch */
1819 static void create_hardware_branch(void)
1821 int i;
1822 HANDLE handle;
1823 char drive[] = "\\\\.\\A:";
1825 /* create entries for cdroms */
1826 for (i = 0; i < 26; i++)
1828 drive[4] = 'A' + i;
1829 handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
1830 if (handle == INVALID_HANDLE_VALUE) continue;
1831 init_cdrom_registry( handle );
1832 CloseHandle( handle );
1837 /* convert the drive type entries from the old format to the new one */
1838 static void convert_drive_types(void)
1840 static const WCHAR TypeW[] = {'T','y','p','e',0};
1841 static const WCHAR drive_types_keyW[] = {'M','a','c','h','i','n','e','\\',
1842 'S','o','f','t','w','a','r','e','\\',
1843 'W','i','n','e','\\',
1844 'D','r','i','v','e','s',0 };
1845 WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1846 'W','i','n','e','\\','W','i','n','e','\\',
1847 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1848 char tmp[32*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1849 OBJECT_ATTRIBUTES attr;
1850 UNICODE_STRING nameW;
1851 DWORD dummy;
1852 ULONG disp;
1853 HKEY hkey_old, hkey_new;
1854 int i;
1856 attr.Length = sizeof(attr);
1857 attr.RootDirectory = 0;
1858 attr.ObjectName = &nameW;
1859 attr.Attributes = 0;
1860 attr.SecurityDescriptor = NULL;
1861 attr.SecurityQualityOfService = NULL;
1862 RtlInitUnicodeString( &nameW, drive_types_keyW );
1864 if (NtCreateKey( &hkey_new, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) return;
1865 if (disp != REG_CREATED_NEW_KEY) return;
1867 for (i = 0; i < 26; i++)
1869 RtlInitUnicodeString( &nameW, driveW );
1870 nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
1871 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
1872 RtlInitUnicodeString( &nameW, TypeW );
1873 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
1875 WCHAR valueW[] = {'A',':',0};
1876 WCHAR *type = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1878 valueW[0] = 'A' + i;
1879 RtlInitUnicodeString( &nameW, valueW );
1880 NtSetValueKey( hkey_new, &nameW, 0, REG_SZ, type, (strlenW(type) + 1) * sizeof(WCHAR) );
1881 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1882 'A' + i, debugstr_w(type) );
1884 NtClose( hkey_old );
1886 NtClose( hkey_new );
1890 /* load all registry (native and global and home) */
1891 void SHELL_LoadRegistry( void )
1893 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1894 OBJECT_ATTRIBUTES attr;
1895 UNICODE_STRING nameW;
1896 DWORD count;
1897 ULONG dispos;
1898 BOOL res;
1899 int all, period;
1900 char tmp[1024];
1902 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1903 static const WCHAR UserW[] = {'U','s','e','r',0};
1904 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1905 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1906 'S','o','f','t','w','a','r','e','\\',
1907 'W','i','n','e','\\',
1908 'W','i','n','e','\\',
1909 'C','o','n','f','i','g','\\',
1910 'R','e','g','i','s','t','r','y',0};
1911 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};
1912 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};
1913 static const WCHAR load_home_reg_filesW[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1914 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1915 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1916 static const WCHAR WritetoHomeRegistryFilesW[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1917 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1919 TRACE("(void)\n");
1921 attr.Length = sizeof(attr);
1922 attr.RootDirectory = 0;
1923 attr.ObjectName = &nameW;
1924 attr.Attributes = 0;
1925 attr.SecurityDescriptor = NULL;
1926 attr.SecurityQualityOfService = NULL;
1928 RtlInitUnicodeString( &nameW, UserW );
1929 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos );
1930 if (dispos == REG_OPENED_EXISTING_KEY)
1932 /* someone else already loaded the registry */
1933 NtClose( hkey_users );
1934 return;
1937 RtlInitUnicodeString( &nameW, MachineW );
1938 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1940 attr.RootDirectory = hkey_users;
1941 RtlInitUnicodeString( &nameW, DefaultW );
1942 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1944 ERR("Cannot create HKEY_USERS/.Default\n" );
1945 ExitProcess(1);
1947 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1949 _set_registry_levels(0,0,0);
1950 _allocate_default_keys();
1952 attr.RootDirectory = 0;
1953 RtlInitUnicodeString( &nameW, RegistryW );
1954 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1956 /* load windows registry if required */
1958 res = TRUE;
1959 attr.RootDirectory = hkey_config;
1960 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1961 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1963 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1964 res = !IS_OPTION_FALSE(str[0]);
1966 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1968 /* load global registry if required */
1970 res = TRUE;
1971 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1972 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1974 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1975 res = !IS_OPTION_FALSE(str[0]);
1977 if (res)
1979 /* load global registry files (stored in /etc/wine) */
1980 char *p, configfile[MAX_PATHNAME_LEN];
1982 /* Override ETCDIR? */
1983 configfile[0] = 0;
1984 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1985 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1987 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1988 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
1989 str, (strlenW(str) + 1) * sizeof(WCHAR));
1991 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1993 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1995 /* Load the global HKU hive directly from sysconfdir */
1996 p = configfile + strlen(configfile);
1997 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1998 load_wine_registry( hkey_users, configfile );
2000 /* Load the global machine defaults directly from sysconfdir */
2001 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
2002 load_wine_registry( hkey_local_machine, configfile );
2005 _set_registry_levels(1,0,0);
2007 /* load home registry if required */
2009 res = TRUE;
2010 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
2011 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2013 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2014 res = !IS_OPTION_FALSE(str[0]);
2016 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
2018 /* create hardware registry branch */
2020 create_hardware_branch();
2022 /* setup registry saving */
2024 all = FALSE;
2025 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
2026 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2028 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2029 all = IS_OPTION_FALSE(str[0]);
2032 period = 0;
2033 RtlInitUnicodeString( &nameW, PeriodicSaveW );
2034 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2036 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2037 period = (int)strtolW(str, NULL, 10);
2040 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
2041 _set_registry_levels(1,!all,period*1000);
2043 /* setup keys to save */
2045 res = TRUE;
2046 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
2047 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2049 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2050 res = !IS_OPTION_FALSE(str[0]);
2052 if (res)
2054 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
2055 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
2056 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
2059 /* convert keys from config file to new registry format */
2061 convert_drive_types();
2063 NtClose(hkey_users_default);
2064 NtClose(hkey_current_user);
2065 NtClose(hkey_users);
2066 NtClose(hkey_local_machine);
2067 NtClose(hkey_config);