Distinguish between Open and Explore commands.
[wine/multimedia.git] / misc / registry.c
blob991616406863138f1e82e6882b79692855c4d8d4
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 static const WCHAR ConfigManagerW[] = {'D','y','n','D','a','t','a','\\',
1089 'C','o','n','f','i','g',' ','M','a','n','a','g','e','r','\\',
1090 'E','n','u','m',0};
1091 HKEY hkey;
1092 OBJECT_ATTRIBUTES attr;
1093 UNICODE_STRING nameW;
1095 TRACE("(void)\n");
1097 attr.Length = sizeof(attr);
1098 attr.RootDirectory = 0;
1099 attr.ObjectName = &nameW;
1100 attr.Attributes = 0;
1101 attr.SecurityDescriptor = NULL;
1102 attr.SecurityQualityOfService = NULL;
1104 RtlInitUnicodeString( &nameW, StatDataW );
1105 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1107 RtlInitUnicodeString( &nameW, ConfigManagerW );
1108 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1111 static void get_windows_dir(WCHAR* buffer, unsigned len)
1113 OBJECT_ATTRIBUTES attr;
1114 UNICODE_STRING nameW, keyW;
1115 HKEY hkey;
1117 attr.Length = sizeof(attr);
1118 attr.RootDirectory = 0;
1119 attr.ObjectName = &nameW;
1120 attr.Attributes = 0;
1121 attr.SecurityDescriptor = NULL;
1122 attr.SecurityQualityOfService = NULL;
1124 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1126 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1128 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1129 DWORD count;
1131 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1132 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1133 tmp, sizeof(tmp), &count ))
1135 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1136 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1138 RtlFreeUnicodeString( &keyW );
1140 RtlFreeUnicodeString( &nameW );
1145 #define REG_DONTLOAD -1
1146 #define REG_WIN31 0
1147 #define REG_WIN95 1
1148 #define REG_WINNT 2
1150 /* return the type of native registry [Internal] */
1151 static int _get_reg_type(const WCHAR* windir)
1153 WCHAR tmp[MAX_PATHNAME_LEN];
1154 int ret = REG_WIN31;
1155 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};
1156 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1158 /* test %windir%/system32/config/system --> winnt */
1159 strcpyW(tmp, windir);
1160 strcatW(tmp, nt_reg_pathW);
1161 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1162 ret = REG_WINNT;
1163 else
1165 /* test %windir%/system.dat --> win95 */
1166 strcpyW(tmp, windir);
1167 strcatW(tmp, win9x_reg_pathW);
1168 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1169 ret = REG_WIN95;
1172 return ret;
1175 /* load the registry file in wine format [Internal] */
1176 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1178 WCHAR *buffer;
1179 HANDLE file;
1180 DWORD len;
1181 UNICODE_STRING name;
1182 OBJECT_ATTRIBUTES attr;
1183 IO_STATUS_BLOCK io;
1185 len = MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, NULL, 0 );
1186 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
1187 MultiByteToWideChar( CP_UNIXCP, 0, fn, -1, buffer, len );
1188 RtlInitUnicodeString( &name, buffer );
1190 attr.Length = sizeof(attr);
1191 attr.RootDirectory = 0;
1192 attr.Attributes = 0;
1193 attr.ObjectName = &name;
1194 attr.SecurityDescriptor = NULL;
1195 attr.SecurityQualityOfService = NULL;
1197 if (!NtOpenFile( &file, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
1198 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
1200 SERVER_START_REQ( load_registry )
1202 req->hkey = hkey;
1203 req->file = file;
1204 wine_server_call( req );
1206 SERVER_END_REQ;
1207 CloseHandle( file );
1209 HeapFree( GetProcessHeap(), 0, buffer );
1212 /* generate and return the name of the tmp file and associated stream [Internal] */
1213 static LPSTR _get_tmp_fn(FILE **f)
1215 LPSTR ret;
1216 int tmp_fd,count;
1218 ret = _xmalloc(50);
1219 for (count = 0;;) {
1220 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1221 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1222 if (errno != EEXIST) {
1223 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1224 free(ret);
1225 *f = NULL;
1226 return NULL;
1230 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1231 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1232 close(tmp_fd);
1233 free(ret);
1234 return NULL;
1237 return ret;
1240 /* convert win95 native registry file to wine format [Internal] */
1241 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1243 HANDLE hFile, hMapping;
1244 FILE *f;
1245 void *base;
1246 LPSTR ret = NULL;
1247 OBJECT_ATTRIBUTES attr;
1248 LARGE_INTEGER lg_int;
1249 NTSTATUS nts;
1250 SIZE_T len;
1252 _w95creg *creg;
1253 _w95rgkn *rgkn;
1254 _w95dke *dke, *root_dke;
1256 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1257 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1259 attr.Length = sizeof(attr);
1260 attr.RootDirectory = 0;
1261 attr.ObjectName = NULL;
1262 attr.Attributes = 0;
1263 attr.SecurityDescriptor = NULL;
1264 attr.SecurityQualityOfService = NULL;
1266 lg_int.QuadPart = 0;
1267 nts = NtCreateSection( &hMapping,
1268 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1269 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1270 if (nts != STATUS_SUCCESS) goto error1;
1272 base = NULL; len = 0;
1273 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1274 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1275 PAGE_READONLY);
1276 NtClose( hMapping );
1277 if (nts != STATUS_SUCCESS) goto error1;
1279 /* control signature */
1280 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1281 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1282 debugstr_w(fn));
1283 goto error;
1286 creg = base;
1287 /* load the header (rgkn) */
1288 rgkn = (_w95rgkn*)(creg + 1);
1289 if (rgkn->id != W95_REG_RGKN_ID) {
1290 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1291 goto error;
1293 if (rgkn->root_off != 0x20) {
1294 ERR("rgkn->root_off not 0x20, please report !\n");
1295 goto error;
1297 if (rgkn->last_dke > rgkn->size)
1299 ERR("registry file corrupt! last_dke > size!\n");
1300 goto error;
1302 /* verify last dke */
1303 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1304 if (dke->x1 != 0x80000000)
1305 { /* wrong magic */
1306 ERR("last dke invalid !\n");
1307 goto error;
1309 if (rgkn->size > creg->rgdb_off)
1311 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1312 goto error;
1314 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1315 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1317 ERR("registry file corrupt! invalid root dke !\n");
1318 goto error;
1321 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1322 fprintf(f,"WINE REGISTRY Version 2");
1323 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1324 fclose(f);
1326 error:
1327 if(ret == NULL) {
1328 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1329 ERR("Please report this.\n");
1330 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1333 NtUnmapViewOfSection( GetCurrentProcess(), base );
1334 error1:
1335 NtClose(hFile);
1336 return ret;
1339 /* convert winnt native registry file to wine format [Internal] */
1340 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1342 FILE *f;
1343 void *base;
1344 LPSTR ret = NULL;
1345 HANDLE hFile;
1346 HANDLE hMapping;
1347 OBJECT_ATTRIBUTES attr;
1348 LARGE_INTEGER lg_int;
1349 NTSTATUS nts;
1350 SIZE_T len;
1352 nt_regf *regf;
1353 nt_hbin *hbin;
1354 nt_hbin_sub *hbin_sub;
1355 nt_nk *nk;
1357 TRACE("%s\n", debugstr_w(fn));
1359 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1360 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1361 attr.Length = sizeof(attr);
1362 attr.RootDirectory = 0;
1363 attr.ObjectName = NULL;
1364 attr.Attributes = 0;
1365 attr.SecurityDescriptor = NULL;
1366 attr.SecurityQualityOfService = NULL;
1368 lg_int.QuadPart = 0;
1369 nts = NtCreateSection( &hMapping,
1370 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1371 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1372 if (nts != STATUS_SUCCESS) goto error1;
1374 base = NULL; len = 0;
1375 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1376 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1377 PAGE_READONLY);
1378 NtClose( hMapping );
1379 if (nts != STATUS_SUCCESS) goto error1;
1381 /* control signature */
1382 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1383 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1384 debugstr_w(fn));
1385 goto error;
1388 /* start block */
1389 regf = base;
1391 /* hbin block */
1392 hbin = (nt_hbin*)((char*) base + 0x1000);
1393 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1394 ERR( "hbin block invalid\n");
1395 goto error;
1398 /* hbin_sub block */
1399 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1400 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1401 ERR( "hbin_sub block invalid\n");
1402 goto error;
1405 /* nk block */
1406 nk = (nt_nk*)&(hbin_sub->data[0]);
1407 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1408 ERR( "special nk block not found\n");
1409 goto error;
1412 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1413 fprintf(f,"WINE REGISTRY Version 2");
1414 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1415 fclose(f);
1417 error:
1418 NtUnmapViewOfSection( GetCurrentProcess(), base );
1419 error1:
1420 NtClose(hFile);
1421 return ret;
1424 /* convert native registry to wine format and load it via server call [Internal] */
1425 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1427 LPSTR tmp = NULL;
1429 switch (reg_type) {
1430 case REG_WINNT:
1431 /* FIXME: following function doesn't really convert yet */
1432 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1433 break;
1434 case REG_WIN95:
1435 tmp = _convert_win95_registry_to_wine_format(fn,level);
1436 break;
1437 case REG_WIN31:
1438 ERR("Don't know how to convert native 3.1 registry yet.\n");
1439 break;
1440 default:
1441 ERR("Unknown registry format parameter (%d)\n",reg_type);
1442 break;
1445 if (tmp != NULL) {
1446 load_wine_registry(hkey,tmp);
1447 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1448 debugstr_w(fn), tmp);
1449 unlink(tmp);
1451 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1452 free(tmp);
1455 /* load all native windows registry files [Internal] */
1456 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1457 HKEY hkey_users_default )
1459 int reg_type;
1460 WCHAR windir[MAX_PATHNAME_LEN];
1461 WCHAR path[MAX_PATHNAME_LEN];
1462 OBJECT_ATTRIBUTES attr;
1463 UNICODE_STRING nameW;
1464 HKEY hkey, profile_key;
1465 char tmp[1024];
1466 DWORD dummy;
1468 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1469 'S','o','f','t','w','a','r','e','\\',
1470 'W','i','n','e','\\','W','i','n','e','\\',
1471 'C','o','n','f','i','g','\\','W','i','n','e',0};
1472 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1473 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1474 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1475 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1476 'S','y','s','t','e','m','\\',
1477 'C','l','o','n','e',0};
1479 attr.Length = sizeof(attr);
1480 attr.RootDirectory = 0;
1481 attr.ObjectName = &nameW;
1482 attr.Attributes = 0;
1483 attr.SecurityDescriptor = NULL;
1484 attr.SecurityQualityOfService = NULL;
1486 RtlInitUnicodeString( &nameW, WineW );
1487 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1489 get_windows_dir(windir, sizeof(windir));
1491 reg_type = _get_reg_type(windir);
1492 switch (reg_type) {
1493 case REG_WINNT: {
1494 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1495 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};
1496 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};
1497 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};
1498 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1499 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};
1501 /* user specific ntuser.dat */
1502 RtlInitUnicodeString( &nameW, ProfileW );
1503 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1504 tmp, sizeof(tmp), &dummy ))
1506 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1507 strcatW(path, ntuser_datW);
1508 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1510 else
1512 MESSAGE("When you are running with a native NT directory specify\n");
1513 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1514 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1515 break;
1518 /* default user.dat */
1519 if (hkey_users_default) {
1520 strcpyW(path, windir);
1521 strcatW(path, defaultW);
1522 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1526 * FIXME
1527 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1529 RtlInitUnicodeString( &nameW, System );
1530 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1532 strcpyW(path, windir);
1533 strcatW(path, systemW);
1534 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1535 NtClose( hkey );
1537 RtlInitUnicodeString( &nameW, Software );
1538 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1540 strcpyW(path, windir);
1541 strcatW(path, softwareW);
1542 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1543 NtClose( hkey );
1546 strcpyW(path, windir);
1547 strcatW(path, samW);
1548 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1550 strcpyW(path,windir);
1551 strcatW(path, securityW);
1552 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1554 /* this key is generated when the nt-core booted successfully */
1555 RtlInitUnicodeString( &nameW, Clone );
1556 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1557 break;
1560 case REG_WIN95:
1562 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1563 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1564 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1565 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1567 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1569 strcpyW(path, windir);
1570 strcatW(path, system_datW);
1571 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1573 RtlInitUnicodeString( &nameW, ClassesRootW );
1574 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1576 strcpyW(path, windir);
1577 strcatW(path, classes_datW);
1578 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1579 NtClose( hkey );
1582 RtlInitUnicodeString( &nameW, ProfileW );
1583 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1584 tmp, sizeof(tmp), &dummy ))
1586 /* user specific user.dat */
1587 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1588 strcatW(path, user_datW);
1589 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1591 /* default user.dat */
1592 if (hkey_users_default) {
1593 strcpyW(path, windir);
1594 strcatW(path, user_datW);
1595 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1597 } else {
1598 strcpyW(path, windir);
1599 strcatW(path, user_datW);
1600 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1602 break;
1605 case REG_WIN31:
1607 static const WCHAR reg_datW[] = {'\\','r','e','g','.','d','a','t',0};
1608 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1609 strcpyW(path, windir);
1610 strcatW(path, reg_datW);
1611 _w31_loadreg( path );
1612 break;
1615 case REG_DONTLOAD:
1616 TRACE("REG_DONTLOAD\n");
1617 break;
1619 default:
1620 ERR("switch: no match (%d)\n",reg_type);
1621 break;
1624 if (profile_key) NtClose( profile_key );
1629 /******************************************************************
1630 * init_cdrom_registry
1632 * Initializes registry to contain scsi info about the cdrom in NT.
1633 * All devices (even not real scsi ones) have this info in NT.
1634 * TODO: for now it only works for non scsi devices
1635 * NOTE: programs usually read these registry entries after sending the
1636 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1638 static void init_cdrom_registry( HANDLE handle )
1640 OBJECT_ATTRIBUTES attr;
1641 UNICODE_STRING nameW;
1642 WCHAR dataW[50];
1643 DWORD lenW;
1644 char buffer[40];
1645 DWORD value;
1646 const char *data;
1647 HKEY scsiKey;
1648 HKEY portKey;
1649 HKEY busKey;
1650 HKEY targetKey;
1651 DWORD disp;
1652 IO_STATUS_BLOCK io;
1653 SCSI_ADDRESS scsi_addr;
1655 if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS,
1656 NULL, 0, &scsi_addr, sizeof(scsi_addr) ))
1657 return;
1659 attr.Length = sizeof(attr);
1660 attr.RootDirectory = 0;
1661 attr.ObjectName = &nameW;
1662 attr.Attributes = 0;
1663 attr.SecurityDescriptor = NULL;
1664 attr.SecurityQualityOfService = NULL;
1666 /* Ensure there is Scsi key */
1667 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1668 NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
1669 NULL, REG_OPTION_VOLATILE, &disp ))
1671 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1672 return;
1674 RtlFreeUnicodeString( &nameW );
1676 snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber);
1677 attr.RootDirectory = scsiKey;
1678 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1679 NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
1680 NULL, REG_OPTION_VOLATILE, &disp ))
1682 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1683 return;
1685 RtlFreeUnicodeString( &nameW );
1687 RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
1688 data = "atapi";
1689 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1690 NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1691 RtlFreeUnicodeString( &nameW );
1692 value = 10;
1693 RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
1694 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1695 RtlFreeUnicodeString( &nameW );
1696 value = 0;
1697 #ifdef HDIO_GET_DMA
1699 int fd, dma;
1700 if (!wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL ))
1702 if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma;
1703 wine_server_release_fd( handle, fd );
1706 #endif
1707 RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
1708 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
1709 RtlFreeUnicodeString( &nameW );
1711 snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId);
1712 attr.RootDirectory = portKey;
1713 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1714 NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
1715 NULL, REG_OPTION_VOLATILE, &disp ))
1717 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1718 return;
1720 RtlFreeUnicodeString( &nameW );
1722 attr.RootDirectory = busKey;
1723 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
1724 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1725 NULL, REG_OPTION_VOLATILE, &disp ))
1727 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1728 return;
1730 RtlFreeUnicodeString( &nameW );
1731 NtClose( targetKey );
1733 snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId);
1734 attr.RootDirectory = busKey;
1735 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
1736 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
1737 NULL, REG_OPTION_VOLATILE, &disp ))
1739 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1740 return;
1742 RtlFreeUnicodeString( &nameW );
1744 RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
1745 data = "CdRomPeripheral";
1746 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1747 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1748 RtlFreeUnicodeString( &nameW );
1749 /* FIXME - maybe read the real identifier?? */
1750 RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
1751 data = "Wine CDROM";
1752 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1753 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1754 RtlFreeUnicodeString( &nameW );
1755 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1756 RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
1757 data = "Cdrom0";
1758 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
1759 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
1760 RtlFreeUnicodeString( &nameW );
1762 NtClose( targetKey );
1763 NtClose( busKey );
1764 NtClose( portKey );
1765 NtClose( scsiKey );
1769 /* create the hardware registry branch */
1770 static void create_hardware_branch(void)
1772 int i;
1773 HANDLE handle;
1774 char drive[] = "\\\\.\\A:";
1776 /* create entries for cdroms */
1777 for (i = 0; i < 26; i++)
1779 drive[4] = 'A' + i;
1780 handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
1781 if (handle == INVALID_HANDLE_VALUE) continue;
1782 init_cdrom_registry( handle );
1783 CloseHandle( handle );
1788 /* convert the drive type entries from the old format to the new one */
1789 static void convert_drive_types(void)
1791 static const WCHAR TypeW[] = {'T','y','p','e',0};
1792 static const WCHAR drive_types_keyW[] = {'M','a','c','h','i','n','e','\\',
1793 'S','o','f','t','w','a','r','e','\\',
1794 'W','i','n','e','\\',
1795 'D','r','i','v','e','s',0 };
1796 WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1797 'W','i','n','e','\\','W','i','n','e','\\',
1798 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1799 char tmp[32*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1800 OBJECT_ATTRIBUTES attr;
1801 UNICODE_STRING nameW;
1802 DWORD dummy;
1803 ULONG disp;
1804 HKEY hkey_old, hkey_new;
1805 int i;
1807 attr.Length = sizeof(attr);
1808 attr.RootDirectory = 0;
1809 attr.ObjectName = &nameW;
1810 attr.Attributes = 0;
1811 attr.SecurityDescriptor = NULL;
1812 attr.SecurityQualityOfService = NULL;
1813 RtlInitUnicodeString( &nameW, drive_types_keyW );
1815 if (NtCreateKey( &hkey_new, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) return;
1816 if (disp != REG_CREATED_NEW_KEY)
1818 NtClose( hkey_new );
1819 return;
1822 for (i = 0; i < 26; i++)
1824 RtlInitUnicodeString( &nameW, driveW );
1825 nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
1826 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
1827 RtlInitUnicodeString( &nameW, TypeW );
1828 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
1830 WCHAR valueW[] = {'A',':',0};
1831 WCHAR *type = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1833 valueW[0] = 'A' + i;
1834 RtlInitUnicodeString( &nameW, valueW );
1835 NtSetValueKey( hkey_new, &nameW, 0, REG_SZ, type, (strlenW(type) + 1) * sizeof(WCHAR) );
1836 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1837 'A' + i, debugstr_w(type) );
1839 NtClose( hkey_old );
1841 NtClose( hkey_new );
1845 /* convert the environment variable entries from the old format to the new one */
1846 static void convert_environment( HKEY hkey_current_user )
1848 static const WCHAR wineW[] = {'M','a','c','h','i','n','e','\\',
1849 'S','o','f','t','w','a','r','e','\\',
1850 'W','i','n','e','\\','W','i','n','e','\\',
1851 'C','o','n','f','i','g','\\','W','i','n','e',0};
1852 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
1853 static const WCHAR systemW[] = {'s','y','s','t','e','m',0};
1854 static const WCHAR windirW[] = {'w','i','n','d','i','r',0};
1855 static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
1856 static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
1857 static const WCHAR tempW[] = {'T','E','M','P',0};
1858 static const WCHAR tmpW[] = {'T','M','P',0};
1859 static const WCHAR pathW[] = {'P','A','T','H',0};
1860 static const WCHAR profileW[] = {'p','r','o','f','i','l','e',0};
1861 static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
1863 char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1864 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1865 OBJECT_ATTRIBUTES attr;
1866 UNICODE_STRING nameW;
1867 DWORD dummy;
1868 ULONG disp;
1869 HKEY hkey_old, hkey_env;
1871 attr.Length = sizeof(attr);
1872 attr.RootDirectory = 0;
1873 attr.ObjectName = &nameW;
1874 attr.Attributes = 0;
1875 attr.SecurityDescriptor = NULL;
1876 attr.SecurityQualityOfService = NULL;
1877 RtlInitUnicodeString( &nameW, wineW );
1879 if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return;
1881 attr.RootDirectory = hkey_current_user;
1882 RtlInitUnicodeString( &nameW, envW );
1883 if (NtCreateKey( &hkey_env, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1885 NtClose( hkey_old );
1886 return;
1888 if (disp != REG_CREATED_NEW_KEY) goto done;
1890 /* convert TEMP */
1891 RtlInitUnicodeString( &nameW, tempW );
1892 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1894 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1895 RtlInitUnicodeString( &nameW, tmpW );
1896 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1897 MESSAGE( "Converted temp dir to new entry HKCU\\Environment \"TEMP\" = %s\n",
1898 debugstr_w( (WCHAR*)info->Data ) );
1901 /* convert PATH */
1902 RtlInitUnicodeString( &nameW, pathW );
1903 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1905 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1906 MESSAGE( "Converted path dir to new entry HKCU\\Environment \"PATH\" = %s\n",
1907 debugstr_w( (WCHAR*)info->Data ) );
1910 /* convert USERPROFILE */
1911 RtlInitUnicodeString( &nameW, profileW );
1912 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1914 RtlInitUnicodeString( &nameW, userprofileW );
1915 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1916 MESSAGE( "Converted profile dir to new entry HKCU\\Environment \"USERPROFILE\" = %s\n",
1917 debugstr_w( (WCHAR*)info->Data ) );
1920 /* convert windir */
1921 RtlInitUnicodeString( &nameW, windowsW );
1922 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1924 RtlInitUnicodeString( &nameW, windirW );
1925 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1926 MESSAGE( "Converted windows dir to new entry HKCU\\Environment \"windir\" = %s\n",
1927 debugstr_w( (WCHAR*)info->Data ) );
1930 /* convert winsysdir */
1931 RtlInitUnicodeString( &nameW, systemW );
1932 if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy ))
1934 RtlInitUnicodeString( &nameW, winsysdirW );
1935 NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength );
1936 MESSAGE( "Converted system dir to new entry HKCU\\Environment \"winsysdir\" = %s\n",
1937 debugstr_w( (WCHAR*)info->Data ) );
1940 done:
1941 NtClose( hkey_old );
1942 NtClose( hkey_env );
1946 /* load all registry (native and global and home) */
1947 void SHELL_LoadRegistry( void )
1949 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1950 OBJECT_ATTRIBUTES attr;
1951 UNICODE_STRING nameW;
1952 DWORD count;
1953 ULONG dispos;
1954 BOOL res;
1955 int all, period;
1956 char tmp[1024];
1958 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1959 static const WCHAR UserW[] = {'U','s','e','r',0};
1960 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1961 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1962 'S','o','f','t','w','a','r','e','\\',
1963 'W','i','n','e','\\',
1964 'W','i','n','e','\\',
1965 'C','o','n','f','i','g','\\',
1966 'R','e','g','i','s','t','r','y',0};
1967 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};
1968 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};
1969 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1970 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1971 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1973 TRACE("(void)\n");
1975 attr.Length = sizeof(attr);
1976 attr.RootDirectory = 0;
1977 attr.ObjectName = &nameW;
1978 attr.Attributes = 0;
1979 attr.SecurityDescriptor = NULL;
1980 attr.SecurityQualityOfService = NULL;
1982 RtlInitUnicodeString( &nameW, UserW );
1983 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos );
1984 if (dispos == REG_OPENED_EXISTING_KEY)
1986 /* someone else already loaded the registry */
1987 NtClose( hkey_users );
1988 return;
1991 RtlInitUnicodeString( &nameW, MachineW );
1992 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1994 attr.RootDirectory = hkey_users;
1995 RtlInitUnicodeString( &nameW, DefaultW );
1996 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1998 ERR("Cannot create HKEY_USERS/.Default\n" );
1999 ExitProcess(1);
2001 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
2003 _allocate_default_keys();
2005 attr.RootDirectory = 0;
2006 RtlInitUnicodeString( &nameW, RegistryW );
2007 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
2009 /* load windows registry if required */
2011 res = TRUE;
2012 attr.RootDirectory = hkey_config;
2013 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
2014 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2016 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2017 res = !IS_OPTION_FALSE(str[0]);
2019 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
2021 /* load global registry if required */
2023 res = TRUE;
2024 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
2025 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2027 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2028 res = !IS_OPTION_FALSE(str[0]);
2030 if (res)
2032 /* load global registry files (stored in /etc/wine) */
2033 char *p, configfile[MAX_PATHNAME_LEN];
2035 /* Override ETCDIR? */
2036 configfile[0] = 0;
2037 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
2038 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2040 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2041 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
2042 str, (strlenW(str) + 1) * sizeof(WCHAR));
2044 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
2046 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
2048 /* Load the global HKU hive directly from sysconfdir */
2049 p = configfile + strlen(configfile);
2050 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
2051 load_wine_registry( hkey_users, configfile );
2053 /* Load the global machine defaults directly from sysconfdir */
2054 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
2055 load_wine_registry( hkey_local_machine, configfile );
2058 /* setup registry saving */
2060 all = FALSE;
2061 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
2062 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2064 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2065 all = IS_OPTION_FALSE(str[0]);
2068 period = 0;
2069 RtlInitUnicodeString( &nameW, PeriodicSaveW );
2070 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
2072 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
2073 period = (int)strtolW(str, NULL, 10);
2076 /* load home registry and set saving level (0 for saving everything,
2077 * 1 for saving only modified keys) */
2079 SERVER_START_REQ( load_user_registries )
2081 req->hkey = hkey_current_user;
2082 req->saving = !all;
2083 req->period = period * 1000;
2084 wine_server_call( req );
2086 SERVER_END_REQ;
2088 /* create hardware registry branch */
2090 create_hardware_branch();
2092 /* convert keys from config file to new registry format */
2094 convert_drive_types();
2095 convert_environment( hkey_current_user );
2097 NtClose(hkey_users_default);
2098 NtClose(hkey_current_user);
2099 NtClose(hkey_users);
2100 NtClose(hkey_local_machine);
2101 NtClose(hkey_config);