Added workaround for broken dlls that modify ebx in their entry point
[wine.git] / misc / registry.c
blobc275409cfeb4f74236bb1ffc26c06ba0fc494e26
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
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
56 #include "ntstatus.h"
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winerror.h"
61 #include "wine/winbase16.h"
62 #include "wine/library.h"
63 #include "wine/server.h"
64 #include "wine/unicode.h"
65 #include "file.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(reg);
71 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
72 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
74 /* relative in ~user/.wine/ : */
75 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
76 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
77 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
79 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
80 'S','o','f','t','w','a','r','e','\\',
81 'C','l','a','s','s','e','s',0};
83 #define IS_OPTION_FALSE(ch) \
84 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
86 /* _xmalloc [Internal] */
87 static void *_xmalloc( size_t size )
89 void *res;
91 res = malloc (size ? size : 1);
92 if (res == NULL) {
93 WARN("Virtual memory exhausted.\n");
94 exit (1);
96 return res;
99 /* _xstrdup [Internal] */
100 static LPSTR _xstrdup(LPCSTR str)
102 LPSTR ret;
103 size_t len = strlen(str) + 1;
105 if (!str) return NULL;
106 ret = _xmalloc( len );
107 memcpy( ret, str, len );
108 return ret;
111 /* convert ansi string to unicode [Internal] */
112 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
114 LPWSTR ret;
115 DWORD len;
117 if (!strA) return NULL;
118 if (RtlMultiByteToUnicodeSize( &len, strA, lenA ) != STATUS_SUCCESS) return NULL;
120 ret = _xmalloc(len+sizeof(WCHAR));
121 RtlMultiByteToUnicodeN(ret, len, NULL, strA, lenA);
122 ret[len / sizeof(WCHAR)] = 0;
123 return ret;
126 /* dump a Unicode string with proper escaping [Internal] */
127 /* FIXME: this code duplicates server/unicode.c */
128 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,const char escape[2])
130 static const char escapes[32] = ".......abtnvfr.............e....";
131 char buffer[256];
132 LPSTR pos = buffer;
133 int count = 0;
135 for (; len; str++, len--)
137 if (pos > buffer + sizeof(buffer) - 8)
139 fwrite( buffer, pos - buffer, 1, f );
140 count += pos - buffer;
141 pos = buffer;
143 if (*str > 127) /* hex escape */
145 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
146 pos += sprintf( pos, "\\x%04x", *str );
147 else
148 pos += sprintf( pos, "\\x%x", *str );
149 continue;
151 if (*str < 32) /* octal or C escape */
153 if (!*str && len == 1) continue; /* do not output terminating NULL */
154 if (escapes[*str] != '.')
155 pos += sprintf( pos, "\\%c", escapes[*str] );
156 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
157 pos += sprintf( pos, "\\%03o", *str );
158 else
159 pos += sprintf( pos, "\\%o", *str );
160 continue;
162 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
163 *pos++ = *str;
165 fwrite( buffer, pos - buffer, 1, f );
166 count += pos - buffer;
167 return count;
170 /* convert ansi string to unicode and dump with proper escaping [Internal] */
171 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,const char escape[2])
173 WCHAR *strW;
174 int ret;
176 if (strA == NULL) return 0;
177 strW = _strdupnAtoW(strA,len);
178 ret = _dump_strW(strW,len,f,escape);
179 free(strW);
180 return ret;
183 /* a key value */
184 /* FIXME: this code duplicates server/registry.c */
185 struct key_value {
186 WCHAR *nameW; /* value name */
187 int type; /* value type */
188 size_t len; /* value data length in bytes */
189 void *data; /* pointer to value data */
192 /* dump a value to a text file */
193 /* FIXME: this code duplicates server/registry.c */
194 static void _dump_value(struct key_value *value,FILE *f)
196 int i, count;
198 if (value->nameW[0]) {
199 fputc( '\"', f );
200 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
201 count += fprintf( f, "\"=" );
203 else count = fprintf( f, "@=" );
205 switch(value->type) {
206 case REG_SZ:
207 case REG_EXPAND_SZ:
208 case REG_MULTI_SZ:
209 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
210 fputc( '\"', f );
211 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
212 fputc( '\"', f );
213 break;
214 case REG_DWORD:
215 if (value->len == sizeof(DWORD)) {
216 DWORD dw;
217 memcpy( &dw, value->data, sizeof(DWORD) );
218 fprintf( f, "dword:%08lx", dw );
219 break;
221 /* else fall through */
222 default:
223 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
224 else count += fprintf( f, "hex(%x):", value->type );
225 for (i = 0; i < value->len; i++) {
226 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
227 if (i < value->len-1) {
228 fputc( ',', f );
229 if (++count > 76) {
230 fprintf( f, "\\\n " );
231 count = 2;
235 break;
237 fputc( '\n', f );
240 /******************************************************************/
241 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
243 reghack - windows 3.11 registry data format demo program.
245 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
246 a combined hash table and tree description, and finally a text table.
248 The header is obvious from the struct header. The taboff1 and taboff2
249 fields are always 0x20, and their usage is unknown.
251 The 8-byte entry table has various entry types.
253 tabent[0] is a root index. The second word has the index of the root of
254 the directory.
255 tabent[1..hashsize] is a hash table. The first word in the hash entry is
256 the index of the key/value that has that hash. Data with the same
257 hash value are on a circular list. The other three words in the
258 hash entry are always zero.
259 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
260 entry: dirent and keyent/valent. They are identified by context.
261 tabent[freeidx] is the first free entry. The first word in a free entry
262 is the index of the next free entry. The last has 0 as a link.
263 The other three words in the free list are probably irrelevant.
265 Entries in text table are preceded by a word at offset-2. This word
266 has the value (2*index)+1, where index is the referring keyent/valent
267 entry in the table. I have no suggestion for the 2* and the +1.
268 Following the word, there are N bytes of data, as per the keyent/valent
269 entry length. The offset of the keyent/valent entry is from the start
270 of the text table to the first data byte.
272 This information is not available from Microsoft. The data format is
273 deduced from the reg.dat file by me. Mistakes may
274 have been made. I claim no rights and give no guarantees for this program.
276 Tor Sjøwall, tor@sn.no
279 /* reg.dat header format */
280 struct _w31_header {
281 char cookie[8]; /* 'SHCC3.10' */
282 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
283 unsigned long taboff2; /* offset of index table (??) = 0x20 */
284 unsigned long tabcnt; /* number of entries in index table */
285 unsigned long textoff; /* offset of text part */
286 unsigned long textsize; /* byte size of text part */
287 unsigned short hashsize; /* hash size */
288 unsigned short freeidx; /* free index */
291 /* generic format of table entries */
292 struct _w31_tabent {
293 unsigned short w0, w1, w2, w3;
296 /* directory tabent: */
297 struct _w31_dirent {
298 unsigned short sibling_idx; /* table index of sibling dirent */
299 unsigned short child_idx; /* table index of child dirent */
300 unsigned short key_idx; /* table index of key keyent */
301 unsigned short value_idx; /* table index of value valent */
304 /* key tabent: */
305 struct _w31_keyent {
306 unsigned short hash_idx; /* hash chain index for string */
307 unsigned short refcnt; /* reference count */
308 unsigned short length; /* length of string */
309 unsigned short string_off; /* offset of string in text table */
312 /* value tabent: */
313 struct _w31_valent {
314 unsigned short hash_idx; /* hash chain index for string */
315 unsigned short refcnt; /* reference count */
316 unsigned short length; /* length of string */
317 unsigned short string_off; /* offset of string in text table */
320 /* recursive helper function to display a directory tree [Internal] */
321 static void _w31_dumptree(unsigned short idx, unsigned char *txt,
322 struct _w31_tabent *tab, struct _w31_header *head,
323 HKEY hkey, ULONG lastmodified, int level)
325 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
326 struct _w31_dirent *dir;
327 struct _w31_keyent *key;
328 struct _w31_valent *val;
329 HKEY subkey = 0;
330 OBJECT_ATTRIBUTES attr;
331 UNICODE_STRING nameW, valueW;
332 static WCHAR tail[400];
334 attr.Length = sizeof(attr);
335 attr.RootDirectory = hkey;
336 attr.ObjectName = &nameW;
337 attr.Attributes = 0;
338 attr.SecurityDescriptor = NULL;
339 attr.SecurityQualityOfService = NULL;
340 RtlInitUnicodeString( &valueW, NULL );
342 while (idx!=0) {
343 dir=(struct _w31_dirent*)&tab[idx];
345 if (dir->key_idx) {
346 DWORD len;
347 key = (struct _w31_keyent*)&tab[dir->key_idx];
349 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
350 &txt[key->string_off], key->length);
351 tail[len/sizeof(WCHAR)] = 0;
353 /* all toplevel entries AND the entries in the
354 * toplevel subdirectory belong to \SOFTWARE\Classes
356 if (!level && !strcmpW(tail,classesW))
358 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
359 idx=dir->sibling_idx;
360 continue;
363 if (subkey) NtClose( subkey );
364 RtlInitUnicodeString( &nameW, tail );
365 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
367 /* only add if leaf node or valued node */
368 if (dir->value_idx!=0||dir->child_idx==0) {
369 if (dir->value_idx) {
370 DWORD len;
371 val=(struct _w31_valent*)&tab[dir->value_idx];
372 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
373 &txt[val->string_off], val->length);
374 tail[len/sizeof(WCHAR)] = 0;
375 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
378 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
379 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
380 idx=dir->sibling_idx;
382 if (subkey) NtClose( subkey );
386 /******************************************************************************
387 * _w31_loadreg [Internal]
389 static void _w31_loadreg(void)
391 HANDLE hf;
392 HKEY root;
393 OBJECT_ATTRIBUTES attr;
394 UNICODE_STRING nameW;
395 struct _w31_header head;
396 struct _w31_tabent* tab = NULL;
397 unsigned char* txt = NULL;
398 unsigned int len;
399 OFSTRUCT ofs;
400 ULONG lastmodified;
401 NTSTATUS status;
402 IO_STATUS_BLOCK iosb;
403 FILE_POSITION_INFORMATION fpi;
404 FILE_BASIC_INFORMATION fbi;
406 TRACE("(void)\n");
408 hf = (HANDLE)OpenFile("reg.dat",&ofs,OF_READ);
409 if (hf==(HANDLE)HFILE_ERROR) return;
411 /* read & dump header */
412 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
413 &head, sizeof(head), NULL, NULL) != STATUS_SUCCESS ||
414 iosb.Information != sizeof(head))
416 ERR("reg.dat is too short.\n");
417 goto done;
419 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie)) != 0)
421 ERR("reg.dat has bad signature.\n");
422 goto done;
425 len = head.tabcnt * sizeof(struct _w31_tabent);
426 /* read and dump index table */
427 tab = _xmalloc(len);
428 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
429 tab, len, NULL, NULL) != STATUS_SUCCESS ||
430 iosb.Information != len)
432 ERR("couldn't read index table (%d bytes).\n",len);
433 goto done;
436 /* read text */
437 txt = _xmalloc(head.textsize);
438 fpi.CurrentByteOffset.u.LowPart = head.textoff;
439 fpi.CurrentByteOffset.u.HighPart = 0;
440 if (NtSetInformationFile(hf, &iosb, &fpi, sizeof(fpi),
441 FilePositionInformation) != STATUS_SUCCESS)
443 ERR("couldn't seek to textblock.\n");
444 goto done;
446 status = NtReadFile(hf, 0, NULL, NULL, &iosb, txt, head.textsize, NULL, NULL);
447 if (!(status == STATUS_SUCCESS || status == STATUS_END_OF_FILE) ||
448 iosb.Information != head.textsize)
450 ERR("textblock too short (%d instead of %ld).\n", len, head.textsize);
451 goto done;
453 if (NtQueryInformationFile(hf, &iosb, &fbi, sizeof(fbi),
454 FileBasicInformation) != STATUS_SUCCESS)
456 ERR("Couldn't get basic information.\n");
457 goto done;
459 RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &lastmodified);
461 attr.Length = sizeof(attr);
462 attr.RootDirectory = 0;
463 attr.ObjectName = &nameW;
464 attr.Attributes = 0;
465 attr.SecurityDescriptor = NULL;
466 attr.SecurityQualityOfService = NULL;
467 RtlInitUnicodeString( &nameW, ClassesRootW );
469 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
471 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
472 NtClose( root );
474 done:
475 if (tab) free(tab);
476 if (txt) free(txt);
477 NtClose(hf);
478 return;
481 /***********************************************************************************/
482 /* windows 95 registry loader */
483 /***********************************************************************************/
485 /* SECTION 1: main header
487 * once at offset 0
489 #define W95_REG_CREG_ID 0x47455243
491 typedef struct {
492 DWORD id; /* "CREG" = W95_REG_CREG_ID */
493 DWORD version; /* ???? 0x00010000 */
494 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
495 DWORD uk2; /* 0x0c */
496 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
497 WORD uk3;
498 DWORD uk[3];
499 /* rgkn */
500 } _w95creg;
502 /* SECTION 2: Directory information (tree structure)
504 * once on offset 0x20
506 * structure: [rgkn][dke]* (repeat till last_dke is reached)
508 #define W95_REG_RGKN_ID 0x4e4b4752
510 typedef struct {
511 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
512 DWORD size; /* Size of the RGKN-block */
513 DWORD root_off; /* Rel. Offset of the root-record */
514 DWORD last_dke; /* Offset to last DKE ? */
515 DWORD uk[4];
516 } _w95rgkn;
518 /* Disk Key Entry Structure
520 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
521 * hive itself. It looks the same like other keys. Even the ID-number can
522 * be any value.
524 * The "hash"-value is a value representing the key's name. Windows will not
525 * search for the name, but for a matching hash-value. if it finds one, it
526 * will compare the actual string info, otherwise continue with the next key.
527 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
528 * of the string which are smaller than 0x80 (128) to this D-Word.
530 * If you want to modify key names, also modify the hash-values, since they
531 * cannot be found again (although they would be displayed in REGEDIT)
532 * End of list-pointers are filled with 0xFFFFFFFF
534 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
535 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
536 * structure) and reading another RGDB_section.
538 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
539 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
540 * The remaining space between last_dke and the offset calculated from
541 * rgkn->size seems to be free for use for more dke:s.
542 * So it seems if more dke:s are added, they are added to that space and
543 * last_dke is grown, and in case that "free" space is out, the space
544 * gets grown and rgkn->size gets adjusted.
546 * there is a one to one relationship between dke and dkh
548 /* key struct, once per key */
549 typedef struct {
550 DWORD x1; /* Free entry indicator(?) */
551 DWORD hash; /* sum of bytes of keyname */
552 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
553 DWORD prevlvl; /* offset of previous key */
554 DWORD nextsub; /* offset of child key */
555 DWORD next; /* offset of sibling key */
556 WORD nrLS; /* id inside the rgdb block */
557 WORD nrMS; /* number of the rgdb block */
558 } _w95dke;
560 /* SECTION 3: key information, values and data
562 * structure:
563 * section: [blocks]* (repeat creg->rgdb_num times)
564 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
565 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
567 * An interesting relationship exists in RGDB_section. The DWORD value
568 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
569 * I have no idea at the moment what this means. (Kevin Cozens)
572 /* block header, once per block */
573 #define W95_REG_RGDB_ID 0x42444752
575 typedef struct {
576 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
577 DWORD size; /* 0x04 */
578 DWORD uk1; /* 0x08 */
579 DWORD uk2; /* 0x0c */
580 DWORD uk3; /* 0x10 */
581 DWORD uk4; /* 0x14 */
582 DWORD uk5; /* 0x18 */
583 DWORD uk6; /* 0x1c */
584 /* dkh */
585 } _w95rgdb;
587 /* Disk Key Header structure (RGDB part), once per key */
588 typedef struct {
589 DWORD nextkeyoff; /* 0x00 offset to next dkh */
590 WORD nrLS; /* 0x04 id inside the rgdb block */
591 WORD nrMS; /* 0x06 number of the rgdb block */
592 DWORD bytesused; /* 0x08 */
593 WORD keynamelen; /* 0x0c len of name */
594 WORD values; /* 0x0e number of values */
595 DWORD xx1; /* 0x10 */
596 char name[1]; /* 0x14 */
597 /* dkv */ /* 0x14 + keynamelen */
598 } _w95dkh;
600 /* Disk Key Value structure, once per value */
601 typedef struct {
602 DWORD type; /* 0x00 */
603 DWORD x1; /* 0x04 */
604 WORD valnamelen; /* 0x08 length of name, 0 is default key */
605 WORD valdatalen; /* 0x0A length of data */
606 char name[1]; /* 0x0c */
607 /* raw data */ /* 0x0c + valnamelen */
608 } _w95dkv;
610 /******************************************************************************
611 * _w95_lookup_dkh [Internal]
613 * seeks the dkh belonging to a dke
615 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
617 _w95rgdb * rgdb;
618 _w95dkh * dkh;
619 int i;
621 /* get the beginning of the rgdb datastore */
622 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
624 /* check: requested block < last_block) */
625 if (creg->rgdb_num <= nrMS) {
626 ERR("registry file corrupt! requested block no. beyond end.\n");
627 goto error;
630 /* find the right block */
631 for(i=0; i<nrMS ;i++) {
632 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
633 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
634 goto error;
636 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
639 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
641 do {
642 if(nrLS==dkh->nrLS ) return dkh;
643 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
644 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
646 error:
647 return NULL;
650 /******************************************************************************
651 * _w95_dump_dkv [Internal]
653 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
655 _w95dkv * dkv;
656 int i;
658 /* first value block */
659 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
661 /* loop through the values */
662 for (i=0; i< dkh->values; i++) {
663 struct key_value value;
664 WCHAR *pdata;
666 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
667 value.type = dkv->type;
668 value.len = dkv->valdatalen;
670 value.data = &(dkv->name[dkv->valnamelen]);
671 pdata = NULL;
672 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
673 pdata = _strdupnAtoW(value.data,value.len);
674 value.len *= 2;
676 if (pdata != NULL) value.data = pdata;
678 _dump_value(&value,f);
679 free(value.nameW);
680 if (pdata != NULL) free(pdata);
682 /* next value */
683 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
685 return TRUE;
688 /******************************************************************************
689 * _w95_dump_dke [Internal]
691 static int _w95_dump_dke(LPCSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
693 _w95dkh * dkh;
694 LPSTR new_key_name = NULL;
696 /* special root key */
697 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
699 /* parse the one subkey */
700 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
701 /* has no sibling keys */
702 return FALSE;
705 /* search subblock */
706 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
707 ERR("dke pointing to missing dkh !\n");
708 return FALSE;
711 if (level <= 0) {
712 /* create new subkey name */
713 size_t len = strlen(key_name);
714 new_key_name = _xmalloc(len+dkh->keynamelen+2);
715 memcpy( new_key_name, key_name, len );
716 if (len) new_key_name[len++] = '\\';
717 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
718 new_key_name[len + dkh->keynamelen] = 0;
720 /* walk sibling keys */
721 if (dke->next != 0xffffffff ) {
722 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
723 free(new_key_name);
724 return FALSE;
728 /* write the key path (something like [Software\\Microsoft\\..]) only if:
729 1) key has some values
730 2) key has no values and no subkeys
732 if (dkh->values > 0) {
733 /* there are some values */
734 fprintf(f,"\n[");
735 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
736 fprintf(f,"]\n");
737 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
738 free(new_key_name);
739 return FALSE;
742 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
743 /* no subkeys and no values */
744 fprintf(f,"\n[");
745 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
746 fprintf(f,"]\n");
748 } else new_key_name = _xstrdup(key_name);
750 /* next sub key */
751 if (dke->nextsub != 0xffffffff) {
752 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
753 free(new_key_name);
754 return FALSE;
758 free(new_key_name);
759 return TRUE;
761 /* end windows 95 loader */
763 /***********************************************************************************/
764 /* windows NT registry loader */
765 /***********************************************************************************/
767 /* NT REGISTRY LOADER */
769 #ifdef HAVE_SYS_MMAN_H
770 # include <sys/mman.h>
771 #endif
773 #ifndef MAP_FAILED
774 #define MAP_FAILED ((LPVOID)-1)
775 #endif
777 #define NT_REG_BLOCK_SIZE 0x1000
779 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
780 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
781 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
782 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
784 /* subblocks of nk */
785 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
786 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
787 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
789 #define NT_REG_KEY_BLOCK_TYPE 0x20
790 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
792 typedef struct {
793 DWORD id; /* 0x66676572 'regf'*/
794 DWORD uk1; /* 0x04 */
795 DWORD uk2; /* 0x08 */
796 FILETIME DateModified; /* 0x0c */
797 DWORD uk3; /* 0x14 */
798 DWORD uk4; /* 0x18 */
799 DWORD uk5; /* 0x1c */
800 DWORD uk6; /* 0x20 */
801 DWORD RootKeyBlock; /* 0x24 */
802 DWORD BlockSize; /* 0x28 */
803 DWORD uk7[116];
804 DWORD Checksum; /* at offset 0x1FC */
805 } nt_regf;
807 typedef struct {
808 DWORD blocksize;
809 BYTE data[1];
810 } nt_hbin_sub;
812 typedef struct {
813 DWORD id; /* 0x6E696268 'hbin' */
814 DWORD off_prev;
815 DWORD off_next;
816 DWORD uk1;
817 DWORD uk2; /* 0x10 */
818 DWORD uk3; /* 0x14 */
819 DWORD uk4; /* 0x18 */
820 DWORD size; /* 0x1C */
821 nt_hbin_sub hbin_sub; /* 0x20 */
822 } nt_hbin;
825 * the value_list consists of offsets to the values (vk)
827 typedef struct {
828 WORD SubBlockId; /* 0x00 0x6B6E */
829 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
830 FILETIME writetime; /* 0x04 */
831 DWORD uk1; /* 0x0C */
832 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
833 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
834 DWORD uk8; /* 0x18 */
835 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
836 DWORD uk2; /* 0x20 */
837 DWORD nr_values; /* 0x24 number of values */
838 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
839 DWORD off_sk; /* 0x2c Offset of the sk-Record */
840 DWORD off_class; /* 0x30 Offset of the Class-Name */
841 DWORD uk3; /* 0x34 */
842 DWORD uk4; /* 0x38 */
843 DWORD uk5; /* 0x3c */
844 DWORD uk6; /* 0x40 */
845 DWORD uk7; /* 0x44 */
846 WORD name_len; /* 0x48 name-length */
847 WORD class_len; /* 0x4a class-name length */
848 char name[1]; /* 0x4c key-name */
849 } nt_nk;
851 typedef struct {
852 DWORD off_nk; /* 0x00 */
853 DWORD name; /* 0x04 */
854 } hash_rec;
856 typedef struct {
857 WORD id; /* 0x00 0x666c */
858 WORD nr_keys; /* 0x06 */
859 hash_rec hash_rec[1];
860 } nt_lf;
863 list of subkeys without hash
865 li --+-->nk
867 +-->nk
869 typedef struct {
870 WORD id; /* 0x00 0x696c */
871 WORD nr_keys;
872 DWORD off_nk[1];
873 } nt_li;
876 this is a intermediate node
878 ri --+-->li--+-->nk
880 | +-->nk
882 +-->li--+-->nk
884 +-->nk
886 typedef struct {
887 WORD id; /* 0x00 0x6972 */
888 WORD nr_li; /* 0x02 number off offsets */
889 DWORD off_li[1]; /* 0x04 points to li */
890 } nt_ri;
892 typedef struct {
893 WORD id; /* 0x00 'vk' */
894 WORD nam_len;
895 DWORD data_len;
896 DWORD data_off;
897 DWORD type;
898 WORD flag;
899 WORD uk1;
900 char name[1];
901 } nt_vk;
904 * gets a value
906 * vk->flag:
907 * 0 value is a default value
908 * 1 the value has a name
910 * vk->data_len
911 * len of the whole data block
912 * - reg_sz (unicode)
913 * bytes including the terminating \0 = 2*(number_of_chars+1)
914 * - reg_dword, reg_binary:
915 * if highest bit of data_len is set data_off contains the value
917 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
919 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
920 struct key_value value;
922 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
923 ERR("unknown block found (0x%04x), please report!\n", vk->id);
924 return FALSE;
927 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
928 value.type = vk->type;
929 value.len = (vk->data_len & 0x7fffffff);
930 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
932 _dump_value(&value,f);
933 free(value.nameW);
935 return TRUE;
938 /* it's called from _nt_dump_lf() */
939 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
942 * get the subkeys
944 * this structure contains the hash of a keyname and points to all
945 * subkeys
947 * exception: if the id is 'il' there are no hash values and every
948 * dword is a offset
950 static int _nt_dump_lf(LPCSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
952 int i;
954 if (lf->id == NT_REG_HASH_BLOCK_ID) {
955 if (subkeys != lf->nr_keys) goto error1;
957 for (i=0; i<lf->nr_keys; i++)
958 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
959 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
960 nt_li * li = (nt_li*)lf;
961 if (subkeys != li->nr_keys) goto error1;
963 for (i=0; i<li->nr_keys; i++)
964 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
965 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
966 nt_ri * ri = (nt_ri*)lf;
967 int li_subkeys = 0;
969 /* count all subkeys */
970 for (i=0; i<ri->nr_li; i++) {
971 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
972 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
973 li_subkeys += li->nr_keys;
976 /* check number */
977 if (subkeys != li_subkeys) goto error1;
979 /* loop through the keys */
980 for (i=0; i<ri->nr_li; i++) {
981 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
982 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
984 } else goto error2;
986 return TRUE;
988 error2:
989 if (lf->id == 0x686c)
990 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
991 else
992 ERR("unknown node id 0x%04x, please report!\n", lf->id);
993 return TRUE;
995 error1:
996 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
997 return FALSE;
999 error:
1000 ERR("error reading lf block\n");
1001 return FALSE;
1004 /* _nt_dump_nk [Internal] */
1005 static int _nt_dump_nk(LPCSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
1007 unsigned int n;
1008 DWORD *vl;
1009 LPSTR new_key_name = NULL;
1011 TRACE("%s\n", key_name);
1013 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
1014 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1015 return FALSE;
1018 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1019 ERR("registry file corrupt!\n");
1020 return FALSE;
1023 /* create the new key */
1024 if (level <= 0) {
1025 /* create new subkey name */
1026 size_t len = strlen(key_name);
1027 new_key_name = _xmalloc( len+nk->name_len+2 );
1028 memcpy( new_key_name, key_name, len );
1029 if (len) new_key_name[len++] = '\\';
1030 memcpy( new_key_name + len, nk->name, nk->name_len );
1031 new_key_name[len + nk->name_len] = 0;
1033 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1034 1) key has some values
1035 2) key has no values and no subkeys
1037 if (nk->nr_values > 0) {
1038 /* there are some values */
1039 fprintf(f,"\n[");
1040 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1041 fprintf(f,"]\n");
1043 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1044 /* no subkeys and no values */
1045 fprintf(f,"\n[");
1046 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1047 fprintf(f,"]\n");
1050 /* loop trough the value list */
1051 vl = (DWORD *)(base+nk->valuelist_off+4);
1052 for (n=0; n<nk->nr_values; n++) {
1053 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1054 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1055 free(new_key_name);
1056 return FALSE;
1059 } else new_key_name = _xstrdup(key_name);
1061 /* loop through the subkeys */
1062 if (nk->nr_subkeys) {
1063 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1064 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1065 free(new_key_name);
1066 return FALSE;
1070 free(new_key_name);
1071 return TRUE;
1074 /* end nt loader */
1076 /**********************************************************************************
1077 * _set_registry_levels [Internal]
1079 * set level to 0 for loading system files
1080 * set level to 1 for loading user files
1082 static void _set_registry_levels(int level,int saving,int period)
1084 SERVER_START_REQ( set_registry_levels )
1086 req->current = level;
1087 req->saving = saving;
1088 req->period = period;
1089 wine_server_call( req );
1091 SERVER_END_REQ;
1094 /* _save_at_exit [Internal] */
1095 static void _save_at_exit(HKEY hkey,LPCSTR path)
1097 LPCSTR confdir = wine_get_config_dir();
1099 SERVER_START_REQ( save_registry_atexit )
1101 req->hkey = hkey;
1102 wine_server_add_data( req, confdir, strlen(confdir) );
1103 wine_server_add_data( req, path, strlen(path)+1 );
1104 wine_server_call( req );
1106 SERVER_END_REQ;
1109 /******************************************************************************
1110 * _allocate_default_keys [Internal]
1111 * Registry initialisation, allocates some default keys.
1113 static void _allocate_default_keys(void)
1115 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1116 'P','e','r','f','S','t','a','t','s','\\',
1117 'S','t','a','t','D','a','t','a',0};
1118 HKEY hkey;
1119 OBJECT_ATTRIBUTES attr;
1120 UNICODE_STRING nameW;
1122 TRACE("(void)\n");
1124 attr.Length = sizeof(attr);
1125 attr.RootDirectory = 0;
1126 attr.ObjectName = &nameW;
1127 attr.Attributes = 0;
1128 attr.SecurityDescriptor = NULL;
1129 attr.SecurityQualityOfService = NULL;
1131 RtlInitUnicodeString( &nameW, StatDataW );
1132 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1135 static void get_windows_dir(WCHAR* buffer, unsigned len)
1137 OBJECT_ATTRIBUTES attr;
1138 UNICODE_STRING nameW, keyW;
1139 HKEY hkey;
1141 attr.Length = sizeof(attr);
1142 attr.RootDirectory = 0;
1143 attr.ObjectName = &nameW;
1144 attr.Attributes = 0;
1145 attr.SecurityDescriptor = NULL;
1146 attr.SecurityQualityOfService = NULL;
1148 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1150 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1152 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1153 DWORD count;
1155 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1156 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1157 tmp, sizeof(tmp), &count ))
1159 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1160 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1162 RtlFreeUnicodeString( &keyW );
1164 RtlFreeUnicodeString( &nameW );
1169 #define REG_DONTLOAD -1
1170 #define REG_WIN31 0
1171 #define REG_WIN95 1
1172 #define REG_WINNT 2
1174 /* return the type of native registry [Internal] */
1175 static int _get_reg_type(const WCHAR* windir)
1177 WCHAR tmp[MAX_PATHNAME_LEN];
1178 int ret = REG_WIN31;
1179 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};
1180 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1182 /* test %windir%/system32/config/system --> winnt */
1183 strcpyW(tmp, windir);
1184 strcatW(tmp, nt_reg_pathW);
1185 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1186 ret = REG_WINNT;
1187 else
1189 /* test %windir%/system.dat --> win95 */
1190 strcpyW(tmp, windir);
1191 strcatW(tmp, win9x_reg_pathW);
1192 if(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES)
1193 ret = REG_WIN95;
1196 return ret;
1199 /* load the registry file in wine format [Internal] */
1200 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1202 HANDLE file;
1203 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1204 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1206 SERVER_START_REQ( load_registry )
1208 req->hkey = hkey;
1209 req->file = file;
1210 wine_server_call( req );
1212 SERVER_END_REQ;
1213 CloseHandle( file );
1217 /* generate and return the name of the tmp file and associated stream [Internal] */
1218 static LPSTR _get_tmp_fn(FILE **f)
1220 LPSTR ret;
1221 int tmp_fd,count;
1223 ret = _xmalloc(50);
1224 for (count = 0;;) {
1225 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1226 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1227 if (errno != EEXIST) {
1228 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1229 free(ret);
1230 *f = NULL;
1231 return NULL;
1235 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1236 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1237 close(tmp_fd);
1238 free(ret);
1239 return NULL;
1242 return ret;
1245 /* convert win95 native registry file to wine format [Internal] */
1246 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1248 HANDLE hFile, hMapping;
1249 FILE *f;
1250 void *base;
1251 LPSTR ret = NULL;
1252 OBJECT_ATTRIBUTES attr;
1253 LARGE_INTEGER lg_int;
1254 NTSTATUS nts;
1255 SIZE_T len;
1257 _w95creg *creg;
1258 _w95rgkn *rgkn;
1259 _w95dke *dke, *root_dke;
1261 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1262 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1264 attr.Length = sizeof(attr);
1265 attr.RootDirectory = 0;
1266 attr.ObjectName = NULL;
1267 attr.Attributes = 0;
1268 attr.SecurityDescriptor = NULL;
1269 attr.SecurityQualityOfService = NULL;
1271 lg_int.QuadPart = 0;
1272 nts = NtCreateSection( &hMapping,
1273 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1274 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1275 if (nts != STATUS_SUCCESS) goto error1;
1277 base = NULL; len = 0;
1278 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1279 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1280 PAGE_READONLY);
1281 NtClose( hMapping );
1282 if (nts != STATUS_SUCCESS) goto error1;
1284 /* control signature */
1285 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1286 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1287 debugstr_w(fn));
1288 goto error;
1291 creg = base;
1292 /* load the header (rgkn) */
1293 rgkn = (_w95rgkn*)(creg + 1);
1294 if (rgkn->id != W95_REG_RGKN_ID) {
1295 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1296 goto error;
1298 if (rgkn->root_off != 0x20) {
1299 ERR("rgkn->root_off not 0x20, please report !\n");
1300 goto error;
1302 if (rgkn->last_dke > rgkn->size)
1304 ERR("registry file corrupt! last_dke > size!\n");
1305 goto error;
1307 /* verify last dke */
1308 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1309 if (dke->x1 != 0x80000000)
1310 { /* wrong magic */
1311 ERR("last dke invalid !\n");
1312 goto error;
1314 if (rgkn->size > creg->rgdb_off)
1316 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1317 goto error;
1319 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1320 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1322 ERR("registry file corrupt! invalid root dke !\n");
1323 goto error;
1326 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1327 fprintf(f,"WINE REGISTRY Version 2");
1328 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1329 fclose(f);
1331 error:
1332 if(ret == NULL) {
1333 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1334 ERR("Please report this.\n");
1335 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1338 NtUnmapViewOfSection( GetCurrentProcess(), base );
1339 error1:
1340 NtClose(hFile);
1341 return ret;
1344 /* convert winnt native registry file to wine format [Internal] */
1345 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1347 FILE *f;
1348 void *base;
1349 LPSTR ret = NULL;
1350 HANDLE hFile;
1351 HANDLE hMapping;
1352 OBJECT_ATTRIBUTES attr;
1353 LARGE_INTEGER lg_int;
1354 NTSTATUS nts;
1355 SIZE_T len;
1357 nt_regf *regf;
1358 nt_hbin *hbin;
1359 nt_hbin_sub *hbin_sub;
1360 nt_nk *nk;
1362 TRACE("%s\n", debugstr_w(fn));
1364 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1365 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1366 attr.Length = sizeof(attr);
1367 attr.RootDirectory = 0;
1368 attr.ObjectName = NULL;
1369 attr.Attributes = 0;
1370 attr.SecurityDescriptor = NULL;
1371 attr.SecurityQualityOfService = NULL;
1373 lg_int.QuadPart = 0;
1374 nts = NtCreateSection( &hMapping,
1375 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1376 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1377 if (nts != STATUS_SUCCESS) goto error1;
1379 base = NULL; len = 0;
1380 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1381 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1382 PAGE_READONLY);
1383 NtClose( hMapping );
1384 if (nts != STATUS_SUCCESS) goto error1;
1386 /* control signature */
1387 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1388 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1389 debugstr_w(fn));
1390 goto error;
1393 /* start block */
1394 regf = base;
1396 /* hbin block */
1397 hbin = (nt_hbin*)((char*) base + 0x1000);
1398 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1399 ERR( "hbin block invalid\n");
1400 goto error;
1403 /* hbin_sub block */
1404 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1405 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1406 ERR( "hbin_sub block invalid\n");
1407 goto error;
1410 /* nk block */
1411 nk = (nt_nk*)&(hbin_sub->data[0]);
1412 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1413 ERR( "special nk block not found\n");
1414 goto error;
1417 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1418 fprintf(f,"WINE REGISTRY Version 2");
1419 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1420 fclose(f);
1422 error:
1423 NtUnmapViewOfSection( GetCurrentProcess(), base );
1424 error1:
1425 NtClose(hFile);
1426 return ret;
1429 /* convert native registry to wine format and load it via server call [Internal] */
1430 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1432 LPSTR tmp = NULL;
1434 switch (reg_type) {
1435 case REG_WINNT:
1436 /* FIXME: following function doesn't really convert yet */
1437 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1438 break;
1439 case REG_WIN95:
1440 tmp = _convert_win95_registry_to_wine_format(fn,level);
1441 break;
1442 case REG_WIN31:
1443 ERR("Don't know how to convert native 3.1 registry yet.\n");
1444 break;
1445 default:
1446 ERR("Unknown registry format parameter (%d)\n",reg_type);
1447 break;
1450 if (tmp != NULL) {
1451 load_wine_registry(hkey,tmp);
1452 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1453 debugstr_w(fn), tmp);
1454 unlink(tmp);
1456 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1457 free(tmp);
1460 /* load all native windows registry files [Internal] */
1461 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1462 HKEY hkey_users_default )
1464 int reg_type;
1465 WCHAR windir[MAX_PATHNAME_LEN];
1466 WCHAR path[MAX_PATHNAME_LEN];
1467 OBJECT_ATTRIBUTES attr;
1468 UNICODE_STRING nameW;
1469 HKEY hkey, profile_key;
1470 char tmp[1024];
1471 DWORD dummy;
1473 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1474 'S','o','f','t','w','a','r','e','\\',
1475 'W','i','n','e','\\','W','i','n','e','\\',
1476 'C','o','n','f','i','g','\\','W','i','n','e',0};
1477 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1478 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1479 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1480 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1481 'S','y','s','t','e','m','\\',
1482 'C','l','o','n','e',0};
1484 attr.Length = sizeof(attr);
1485 attr.RootDirectory = 0;
1486 attr.ObjectName = &nameW;
1487 attr.Attributes = 0;
1488 attr.SecurityDescriptor = NULL;
1489 attr.SecurityQualityOfService = NULL;
1491 RtlInitUnicodeString( &nameW, WineW );
1492 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1494 get_windows_dir(windir, sizeof(windir));
1496 reg_type = _get_reg_type(windir);
1497 switch (reg_type) {
1498 case REG_WINNT: {
1499 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1500 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};
1501 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};
1502 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};
1503 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1504 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};
1506 /* user specific ntuser.dat */
1507 RtlInitUnicodeString( &nameW, ProfileW );
1508 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1509 tmp, sizeof(tmp), &dummy ))
1511 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1512 strcatW(path, ntuser_datW);
1513 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1515 else
1517 MESSAGE("When you are running with a native NT directory specify\n");
1518 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1519 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1520 break;
1523 /* default user.dat */
1524 if (hkey_users_default) {
1525 strcpyW(path, windir);
1526 strcatW(path, defaultW);
1527 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1531 * FIXME
1532 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1534 RtlInitUnicodeString( &nameW, System );
1535 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1537 strcpyW(path, windir);
1538 strcatW(path, systemW);
1539 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1540 NtClose( hkey );
1542 RtlInitUnicodeString( &nameW, Software );
1543 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1545 strcpyW(path, windir);
1546 strcatW(path, softwareW);
1547 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1548 NtClose( hkey );
1551 strcpyW(path, windir);
1552 strcatW(path, samW);
1553 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1555 strcpyW(path,windir);
1556 strcatW(path, securityW);
1557 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1559 /* this key is generated when the nt-core booted successfully */
1560 RtlInitUnicodeString( &nameW, Clone );
1561 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1562 break;
1565 case REG_WIN95:
1567 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1568 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1569 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1570 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1572 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1574 strcpyW(path, windir);
1575 strcatW(path, system_datW);
1576 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1578 RtlInitUnicodeString( &nameW, ClassesRootW );
1579 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1581 strcpyW(path, windir);
1582 strcatW(path, classes_datW);
1583 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1584 NtClose( hkey );
1587 RtlInitUnicodeString( &nameW, ProfileW );
1588 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1589 tmp, sizeof(tmp), &dummy ))
1591 /* user specific user.dat */
1592 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1593 strcatW(path, user_datW);
1594 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1596 /* default user.dat */
1597 if (hkey_users_default) {
1598 strcpyW(path, windir);
1599 strcatW(path, user_datW);
1600 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1602 } else {
1603 strcpyW(path, windir);
1604 strcatW(path, user_datW);
1605 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1607 break;
1610 case REG_WIN31:
1611 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1612 _w31_loadreg();
1613 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 );
1627 /* load home registry files (stored in ~/.wine) [Internal] */
1628 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1629 HKEY hkey_users_default )
1631 LPCSTR confdir = wine_get_config_dir();
1632 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1634 strcpy(tmp,confdir);
1635 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1636 load_wine_registry(hkey_users_default,tmp);
1638 strcpy(tmp,confdir);
1639 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1640 load_wine_registry(hkey_current_user,tmp);
1642 strcpy(tmp,confdir);
1643 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1644 load_wine_registry(hkey_local_machine,tmp);
1646 free(tmp);
1650 /* load all registry (native and global and home) */
1651 void SHELL_LoadRegistry( void )
1653 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1654 OBJECT_ATTRIBUTES attr;
1655 UNICODE_STRING nameW;
1656 DWORD count;
1657 ULONG dispos;
1658 BOOL res;
1659 int all, period;
1660 char tmp[1024];
1662 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1663 static const WCHAR UserW[] = {'U','s','e','r',0};
1664 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1665 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1666 'S','o','f','t','w','a','r','e','\\',
1667 'W','i','n','e','\\',
1668 'W','i','n','e','\\',
1669 'C','o','n','f','i','g','\\',
1670 'R','e','g','i','s','t','r','y',0};
1671 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};
1672 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};
1673 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};
1674 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1675 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1676 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};
1677 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1679 TRACE("(void)\n");
1681 attr.Length = sizeof(attr);
1682 attr.RootDirectory = 0;
1683 attr.ObjectName = &nameW;
1684 attr.Attributes = 0;
1685 attr.SecurityDescriptor = NULL;
1686 attr.SecurityQualityOfService = NULL;
1688 RtlInitUnicodeString( &nameW, UserW );
1689 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos );
1690 if (dispos == REG_OPENED_EXISTING_KEY)
1692 /* someone else already loaded the registry */
1693 NtClose( hkey_users );
1694 return;
1697 RtlInitUnicodeString( &nameW, MachineW );
1698 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1700 attr.RootDirectory = hkey_users;
1701 RtlInitUnicodeString( &nameW, DefaultW );
1702 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1704 ERR("Cannot create HKEY_USERS/.Default\n" );
1705 ExitProcess(1);
1707 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1709 _set_registry_levels(0,0,0);
1710 _allocate_default_keys();
1712 attr.RootDirectory = 0;
1713 RtlInitUnicodeString( &nameW, RegistryW );
1714 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1716 /* load windows registry if required */
1718 res = TRUE;
1719 attr.RootDirectory = hkey_config;
1720 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1721 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1723 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1724 res = !IS_OPTION_FALSE(str[0]);
1726 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1728 /* load global registry if required */
1730 res = TRUE;
1731 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1732 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1734 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1735 res = !IS_OPTION_FALSE(str[0]);
1737 if (res)
1739 /* load global registry files (stored in /etc/wine) */
1740 char *p, configfile[MAX_PATHNAME_LEN];
1742 /* Override ETCDIR? */
1743 configfile[0] = 0;
1744 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1745 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1747 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1748 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
1749 str, (strlenW(str) + 1) * sizeof(WCHAR));
1751 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1753 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1755 /* Load the global HKU hive directly from sysconfdir */
1756 p = configfile + strlen(configfile);
1757 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1758 load_wine_registry( hkey_users, configfile );
1760 /* Load the global machine defaults directly from sysconfdir */
1761 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1762 load_wine_registry( hkey_local_machine, configfile );
1765 _set_registry_levels(1,0,0);
1767 /* load home registry if required */
1769 res = TRUE;
1770 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
1771 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1773 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1774 res = !IS_OPTION_FALSE(str[0]);
1776 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1778 /* setup registry saving */
1780 all = FALSE;
1781 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
1782 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1784 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1785 all = IS_OPTION_FALSE(str[0]);
1788 period = 0;
1789 RtlInitUnicodeString( &nameW, PeriodicSaveW );
1790 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1792 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1793 period = (int)strtolW(str, NULL, 10);
1796 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1797 _set_registry_levels(1,!all,period*1000);
1799 /* setup keys to save */
1801 res = TRUE;
1802 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
1803 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1805 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1806 res = !IS_OPTION_FALSE(str[0]);
1808 if (res)
1810 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1811 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1812 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1815 NtClose(hkey_users_default);
1816 NtClose(hkey_current_user);
1817 NtClose(hkey_users);
1818 NtClose(hkey_local_machine);
1819 NtClose(hkey_config);