Translate a few more kernel32 calls into the ntdll equivalents.
[wine.git] / misc / registry.c
blob7ab7aa19b2c7eb9f63326780aa5d1a01c9099531
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 <stdio.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
51 #endif
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
55 #include "windef.h"
56 #include "winerror.h"
58 #include "wine/winbase16.h"
59 #include "wine/library.h"
60 #include "wine/server.h"
61 #include "wine/unicode.h"
62 #include "file.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(reg);
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
71 /* relative in ~user/.wine/ : */
72 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
73 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
74 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
76 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
77 'S','o','f','t','w','a','r','e','\\',
78 'C','l','a','s','s','e','s',0};
80 #define IS_OPTION_FALSE(ch) \
81 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
83 /* _xmalloc [Internal] */
84 static void *_xmalloc( size_t size )
86 void *res;
88 res = malloc (size ? size : 1);
89 if (res == NULL) {
90 WARN("Virtual memory exhausted.\n");
91 exit (1);
93 return res;
96 /* _xstrdup [Internal] */
97 static LPSTR _xstrdup(LPCSTR str)
99 LPSTR ret;
100 size_t len = strlen(str) + 1;
102 if (!str) return NULL;
103 ret = _xmalloc( len );
104 memcpy( ret, str, len );
105 return ret;
108 /* convert ansi string to unicode [Internal] */
109 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
111 LPWSTR ret;
112 DWORD len;
114 if (!strA) return NULL;
115 if (RtlMultiByteToUnicodeSize( &len, strA, lenA ) != STATUS_SUCCESS) return NULL;
117 ret = _xmalloc(len+sizeof(WCHAR));
118 RtlMultiByteToUnicodeN(ret, len, NULL, strA, lenA);
119 ret[len / sizeof(WCHAR)] = 0;
120 return ret;
123 /* dump a Unicode string with proper escaping [Internal] */
124 /* FIXME: this code duplicates server/unicode.c */
125 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
127 static const char escapes[32] = ".......abtnvfr.............e....";
128 char buffer[256];
129 LPSTR pos = buffer;
130 int count = 0;
132 for (; len; str++, len--)
134 if (pos > buffer + sizeof(buffer) - 8)
136 fwrite( buffer, pos - buffer, 1, f );
137 count += pos - buffer;
138 pos = buffer;
140 if (*str > 127) /* hex escape */
142 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
143 pos += sprintf( pos, "\\x%04x", *str );
144 else
145 pos += sprintf( pos, "\\x%x", *str );
146 continue;
148 if (*str < 32) /* octal or C escape */
150 if (!*str && len == 1) continue; /* do not output terminating NULL */
151 if (escapes[*str] != '.')
152 pos += sprintf( pos, "\\%c", escapes[*str] );
153 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
154 pos += sprintf( pos, "\\%03o", *str );
155 else
156 pos += sprintf( pos, "\\%o", *str );
157 continue;
159 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
160 *pos++ = *str;
162 fwrite( buffer, pos - buffer, 1, f );
163 count += pos - buffer;
164 return count;
167 /* convert ansi string to unicode and dump with proper escaping [Internal] */
168 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
170 WCHAR *strW;
171 int ret;
173 if (strA == NULL) return 0;
174 strW = _strdupnAtoW(strA,len);
175 ret = _dump_strW(strW,len,f,escape);
176 free(strW);
177 return ret;
180 /* a key value */
181 /* FIXME: this code duplicates server/registry.c */
182 struct key_value {
183 WCHAR *nameW; /* value name */
184 int type; /* value type */
185 size_t len; /* value data length in bytes */
186 void *data; /* pointer to value data */
189 /* dump a value to a text file */
190 /* FIXME: this code duplicates server/registry.c */
191 static void _dump_value(struct key_value *value,FILE *f)
193 int i, count;
195 if (value->nameW[0]) {
196 fputc( '\"', f );
197 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
198 count += fprintf( f, "\"=" );
200 else count = fprintf( f, "@=" );
202 switch(value->type) {
203 case REG_SZ:
204 case REG_EXPAND_SZ:
205 case REG_MULTI_SZ:
206 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
207 fputc( '\"', f );
208 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
209 fputc( '\"', f );
210 break;
211 case REG_DWORD:
212 if (value->len == sizeof(DWORD)) {
213 DWORD dw;
214 memcpy( &dw, value->data, sizeof(DWORD) );
215 fprintf( f, "dword:%08lx", dw );
216 break;
218 /* else fall through */
219 default:
220 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
221 else count += fprintf( f, "hex(%x):", value->type );
222 for (i = 0; i < value->len; i++) {
223 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
224 if (i < value->len-1) {
225 fputc( ',', f );
226 if (++count > 76) {
227 fprintf( f, "\\\n " );
228 count = 2;
232 break;
234 fputc( '\n', f );
237 /******************************************************************/
238 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
240 reghack - windows 3.11 registry data format demo program.
242 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
243 a combined hash table and tree description, and finally a text table.
245 The header is obvious from the struct header. The taboff1 and taboff2
246 fields are always 0x20, and their usage is unknown.
248 The 8-byte entry table has various entry types.
250 tabent[0] is a root index. The second word has the index of the root of
251 the directory.
252 tabent[1..hashsize] is a hash table. The first word in the hash entry is
253 the index of the key/value that has that hash. Data with the same
254 hash value are on a circular list. The other three words in the
255 hash entry are always zero.
256 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
257 entry: dirent and keyent/valent. They are identified by context.
258 tabent[freeidx] is the first free entry. The first word in a free entry
259 is the index of the next free entry. The last has 0 as a link.
260 The other three words in the free list are probably irrelevant.
262 Entries in text table are preceded by a word at offset-2. This word
263 has the value (2*index)+1, where index is the referring keyent/valent
264 entry in the table. I have no suggestion for the 2* and the +1.
265 Following the word, there are N bytes of data, as per the keyent/valent
266 entry length. The offset of the keyent/valent entry is from the start
267 of the text table to the first data byte.
269 This information is not available from Microsoft. The data format is
270 deduced from the reg.dat file by me. Mistakes may
271 have been made. I claim no rights and give no guarantees for this program.
273 Tor Sjøwall, tor@sn.no
276 /* reg.dat header format */
277 struct _w31_header {
278 char cookie[8]; /* 'SHCC3.10' */
279 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
280 unsigned long taboff2; /* offset of index table (??) = 0x20 */
281 unsigned long tabcnt; /* number of entries in index table */
282 unsigned long textoff; /* offset of text part */
283 unsigned long textsize; /* byte size of text part */
284 unsigned short hashsize; /* hash size */
285 unsigned short freeidx; /* free index */
288 /* generic format of table entries */
289 struct _w31_tabent {
290 unsigned short w0, w1, w2, w3;
293 /* directory tabent: */
294 struct _w31_dirent {
295 unsigned short sibling_idx; /* table index of sibling dirent */
296 unsigned short child_idx; /* table index of child dirent */
297 unsigned short key_idx; /* table index of key keyent */
298 unsigned short value_idx; /* table index of value valent */
301 /* key tabent: */
302 struct _w31_keyent {
303 unsigned short hash_idx; /* hash chain index for string */
304 unsigned short refcnt; /* reference count */
305 unsigned short length; /* length of string */
306 unsigned short string_off; /* offset of string in text table */
309 /* value tabent: */
310 struct _w31_valent {
311 unsigned short hash_idx; /* hash chain index for string */
312 unsigned short refcnt; /* reference count */
313 unsigned short length; /* length of string */
314 unsigned short string_off; /* offset of string in text table */
317 /* recursive helper function to display a directory tree [Internal] */
318 static void _w31_dumptree(unsigned short idx, unsigned char *txt,
319 struct _w31_tabent *tab, struct _w31_header *head,
320 HKEY hkey, ULONG lastmodified, int level)
322 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
323 struct _w31_dirent *dir;
324 struct _w31_keyent *key;
325 struct _w31_valent *val;
326 HKEY subkey = 0;
327 OBJECT_ATTRIBUTES attr;
328 UNICODE_STRING nameW, valueW;
329 static WCHAR tail[400];
331 attr.Length = sizeof(attr);
332 attr.RootDirectory = hkey;
333 attr.ObjectName = &nameW;
334 attr.Attributes = 0;
335 attr.SecurityDescriptor = NULL;
336 attr.SecurityQualityOfService = NULL;
337 RtlInitUnicodeString( &valueW, NULL );
339 while (idx!=0) {
340 dir=(struct _w31_dirent*)&tab[idx];
342 if (dir->key_idx) {
343 DWORD len;
344 key = (struct _w31_keyent*)&tab[dir->key_idx];
346 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
347 &txt[key->string_off], key->length);
348 tail[len/sizeof(WCHAR)] = 0;
350 /* all toplevel entries AND the entries in the
351 * toplevel subdirectory belong to \SOFTWARE\Classes
353 if (!level && !strcmpW(tail,classesW))
355 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
356 idx=dir->sibling_idx;
357 continue;
360 if (subkey) NtClose( subkey );
361 RtlInitUnicodeString( &nameW, tail );
362 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
364 /* only add if leaf node or valued node */
365 if (dir->value_idx!=0||dir->child_idx==0) {
366 if (dir->value_idx) {
367 DWORD len;
368 val=(struct _w31_valent*)&tab[dir->value_idx];
369 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
370 &txt[val->string_off], val->length);
371 tail[len/sizeof(WCHAR)] = 0;
372 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
375 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
376 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
377 idx=dir->sibling_idx;
379 if (subkey) NtClose( subkey );
383 /******************************************************************************
384 * _w31_loadreg [Internal]
386 static void _w31_loadreg(void)
388 HANDLE hf;
389 HKEY root;
390 OBJECT_ATTRIBUTES attr;
391 UNICODE_STRING nameW;
392 struct _w31_header head;
393 struct _w31_tabent* tab = NULL;
394 unsigned char* txt = NULL;
395 unsigned int len;
396 OFSTRUCT ofs;
397 ULONG lastmodified;
398 NTSTATUS status;
399 IO_STATUS_BLOCK iosb;
400 FILE_POSITION_INFORMATION fpi;
401 FILE_BASIC_INFORMATION fbi;
403 TRACE("(void)\n");
405 hf = (HANDLE)OpenFile("reg.dat",&ofs,OF_READ);
406 if (hf==(HANDLE)HFILE_ERROR) return;
408 /* read & dump header */
409 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
410 &head, sizeof(head), NULL, NULL) != STATUS_SUCCESS ||
411 iosb.Information != sizeof(head))
413 ERR("reg.dat is too short.\n");
414 goto done;
416 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie)) != 0)
418 ERR("reg.dat has bad signature.\n");
419 goto done;
422 len = head.tabcnt * sizeof(struct _w31_tabent);
423 /* read and dump index table */
424 tab = _xmalloc(len);
425 if (NtReadFile(hf, 0, NULL, NULL, &iosb,
426 tab, len, NULL, NULL) != STATUS_SUCCESS ||
427 iosb.Information != len)
429 ERR("couldn't read index table (%d bytes).\n",len);
430 goto done;
433 /* read text */
434 txt = _xmalloc(head.textsize);
435 fpi.CurrentByteOffset.s.LowPart = head.textoff;
436 fpi.CurrentByteOffset.s.HighPart = 0;
437 if (NtSetInformationFile(hf, &iosb, &fpi, sizeof(fpi),
438 FilePositionInformation) != STATUS_SUCCESS)
440 ERR("couldn't seek to textblock.\n");
441 goto done;
443 status = NtReadFile(hf, 0, NULL, NULL, &iosb, txt, head.textsize, NULL, NULL);
444 if (!(status == STATUS_SUCCESS || status == STATUS_END_OF_FILE) ||
445 iosb.Information != head.textsize)
447 ERR("textblock too short (%d instead of %ld).\n", len, head.textsize);
448 goto done;
450 if (NtQueryInformationFile(hf, &iosb, &fbi, sizeof(fbi),
451 FileBasicInformation) != STATUS_SUCCESS)
453 ERR("Couldn't get basic information.\n");
454 goto done;
456 RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &lastmodified);
458 attr.Length = sizeof(attr);
459 attr.RootDirectory = 0;
460 attr.ObjectName = &nameW;
461 attr.Attributes = 0;
462 attr.SecurityDescriptor = NULL;
463 attr.SecurityQualityOfService = NULL;
464 RtlInitUnicodeString( &nameW, ClassesRootW );
466 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
468 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
469 NtClose( root );
471 done:
472 if (tab) free(tab);
473 if (txt) free(txt);
474 NtClose(hf);
475 return;
478 /***********************************************************************************/
479 /* windows 95 registry loader */
480 /***********************************************************************************/
482 /* SECTION 1: main header
484 * once at offset 0
486 #define W95_REG_CREG_ID 0x47455243
488 typedef struct {
489 DWORD id; /* "CREG" = W95_REG_CREG_ID */
490 DWORD version; /* ???? 0x00010000 */
491 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
492 DWORD uk2; /* 0x0c */
493 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
494 WORD uk3;
495 DWORD uk[3];
496 /* rgkn */
497 } _w95creg;
499 /* SECTION 2: Directory information (tree structure)
501 * once on offset 0x20
503 * structure: [rgkn][dke]* (repeat till last_dke is reached)
505 #define W95_REG_RGKN_ID 0x4e4b4752
507 typedef struct {
508 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
509 DWORD size; /* Size of the RGKN-block */
510 DWORD root_off; /* Rel. Offset of the root-record */
511 DWORD last_dke; /* Offset to last DKE ? */
512 DWORD uk[4];
513 } _w95rgkn;
515 /* Disk Key Entry Structure
517 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
518 * hive itself. It looks the same like other keys. Even the ID-number can
519 * be any value.
521 * The "hash"-value is a value representing the key's name. Windows will not
522 * search for the name, but for a matching hash-value. if it finds one, it
523 * will compare the actual string info, otherwise continue with the next key.
524 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
525 * of the string which are smaller than 0x80 (128) to this D-Word.
527 * If you want to modify key names, also modify the hash-values, since they
528 * cannot be found again (although they would be displayed in REGEDIT)
529 * End of list-pointers are filled with 0xFFFFFFFF
531 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
532 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
533 * structure) and reading another RGDB_section.
535 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
536 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
537 * The remaining space between last_dke and the offset calculated from
538 * rgkn->size seems to be free for use for more dke:s.
539 * So it seems if more dke:s are added, they are added to that space and
540 * last_dke is grown, and in case that "free" space is out, the space
541 * gets grown and rgkn->size gets adjusted.
543 * there is a one to one relationship between dke and dkh
545 /* key struct, once per key */
546 typedef struct {
547 DWORD x1; /* Free entry indicator(?) */
548 DWORD hash; /* sum of bytes of keyname */
549 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
550 DWORD prevlvl; /* offset of previous key */
551 DWORD nextsub; /* offset of child key */
552 DWORD next; /* offset of sibling key */
553 WORD nrLS; /* id inside the rgdb block */
554 WORD nrMS; /* number of the rgdb block */
555 } _w95dke;
557 /* SECTION 3: key information, values and data
559 * structure:
560 * section: [blocks]* (repeat creg->rgdb_num times)
561 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
562 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
564 * An interesting relationship exists in RGDB_section. The DWORD value
565 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
566 * I have no idea at the moment what this means. (Kevin Cozens)
569 /* block header, once per block */
570 #define W95_REG_RGDB_ID 0x42444752
572 typedef struct {
573 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
574 DWORD size; /* 0x04 */
575 DWORD uk1; /* 0x08 */
576 DWORD uk2; /* 0x0c */
577 DWORD uk3; /* 0x10 */
578 DWORD uk4; /* 0x14 */
579 DWORD uk5; /* 0x18 */
580 DWORD uk6; /* 0x1c */
581 /* dkh */
582 } _w95rgdb;
584 /* Disk Key Header structure (RGDB part), once per key */
585 typedef struct {
586 DWORD nextkeyoff; /* 0x00 offset to next dkh */
587 WORD nrLS; /* 0x04 id inside the rgdb block */
588 WORD nrMS; /* 0x06 number of the rgdb block */
589 DWORD bytesused; /* 0x08 */
590 WORD keynamelen; /* 0x0c len of name */
591 WORD values; /* 0x0e number of values */
592 DWORD xx1; /* 0x10 */
593 char name[1]; /* 0x14 */
594 /* dkv */ /* 0x14 + keynamelen */
595 } _w95dkh;
597 /* Disk Key Value structure, once per value */
598 typedef struct {
599 DWORD type; /* 0x00 */
600 DWORD x1; /* 0x04 */
601 WORD valnamelen; /* 0x08 length of name, 0 is default key */
602 WORD valdatalen; /* 0x0A length of data */
603 char name[1]; /* 0x0c */
604 /* raw data */ /* 0x0c + valnamelen */
605 } _w95dkv;
607 /******************************************************************************
608 * _w95_lookup_dkh [Internal]
610 * seeks the dkh belonging to a dke
612 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
614 _w95rgdb * rgdb;
615 _w95dkh * dkh;
616 int i;
618 /* get the beginning of the rgdb datastore */
619 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
621 /* check: requested block < last_block) */
622 if (creg->rgdb_num <= nrMS) {
623 ERR("registry file corrupt! requested block no. beyond end.\n");
624 goto error;
627 /* find the right block */
628 for(i=0; i<nrMS ;i++) {
629 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
630 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
631 goto error;
633 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
636 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
638 do {
639 if(nrLS==dkh->nrLS ) return dkh;
640 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
641 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
643 error:
644 return NULL;
647 /******************************************************************************
648 * _w95_dump_dkv [Internal]
650 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
652 _w95dkv * dkv;
653 int i;
655 /* first value block */
656 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
658 /* loop through the values */
659 for (i=0; i< dkh->values; i++) {
660 struct key_value value;
661 WCHAR *pdata;
663 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
664 value.type = dkv->type;
665 value.len = dkv->valdatalen;
667 value.data = &(dkv->name[dkv->valnamelen]);
668 pdata = NULL;
669 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
670 pdata = _strdupnAtoW(value.data,value.len);
671 value.len *= 2;
673 if (pdata != NULL) value.data = pdata;
675 _dump_value(&value,f);
676 free(value.nameW);
677 if (pdata != NULL) free(pdata);
679 /* next value */
680 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
682 return TRUE;
685 /******************************************************************************
686 * _w95_dump_dke [Internal]
688 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
690 _w95dkh * dkh;
691 LPSTR new_key_name = NULL;
693 /* special root key */
694 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
696 /* parse the one subkey */
697 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
698 /* has no sibling keys */
699 return FALSE;
702 /* search subblock */
703 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
704 ERR("dke pointing to missing dkh !\n");
705 return FALSE;
708 if (level <= 0) {
709 /* create new subkey name */
710 size_t len = strlen(key_name);
711 new_key_name = _xmalloc(len+dkh->keynamelen+2);
712 memcpy( new_key_name, key_name, len );
713 if (len) new_key_name[len++] = '\\';
714 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
715 new_key_name[len + dkh->keynamelen] = 0;
717 /* walk sibling keys */
718 if (dke->next != 0xffffffff ) {
719 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
720 free(new_key_name);
721 return FALSE;
725 /* write the key path (something like [Software\\Microsoft\\..]) only if:
726 1) key has some values
727 2) key has no values and no subkeys
729 if (dkh->values > 0) {
730 /* there are some values */
731 fprintf(f,"\n[");
732 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
733 fprintf(f,"]\n");
734 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
735 free(new_key_name);
736 return FALSE;
739 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
740 /* no subkeys and no values */
741 fprintf(f,"\n[");
742 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
743 fprintf(f,"]\n");
745 } else new_key_name = _xstrdup(key_name);
747 /* next sub key */
748 if (dke->nextsub != 0xffffffff) {
749 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
750 free(new_key_name);
751 return FALSE;
755 free(new_key_name);
756 return TRUE;
758 /* end windows 95 loader */
760 /***********************************************************************************/
761 /* windows NT registry loader */
762 /***********************************************************************************/
764 /* NT REGISTRY LOADER */
766 #ifdef HAVE_SYS_MMAN_H
767 # include <sys/mman.h>
768 #endif
770 #ifndef MAP_FAILED
771 #define MAP_FAILED ((LPVOID)-1)
772 #endif
774 #define NT_REG_BLOCK_SIZE 0x1000
776 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
777 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
778 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
779 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
781 /* subblocks of nk */
782 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
783 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
784 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
786 #define NT_REG_KEY_BLOCK_TYPE 0x20
787 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
789 typedef struct {
790 DWORD id; /* 0x66676572 'regf'*/
791 DWORD uk1; /* 0x04 */
792 DWORD uk2; /* 0x08 */
793 FILETIME DateModified; /* 0x0c */
794 DWORD uk3; /* 0x14 */
795 DWORD uk4; /* 0x18 */
796 DWORD uk5; /* 0x1c */
797 DWORD uk6; /* 0x20 */
798 DWORD RootKeyBlock; /* 0x24 */
799 DWORD BlockSize; /* 0x28 */
800 DWORD uk7[116];
801 DWORD Checksum; /* at offset 0x1FC */
802 } nt_regf;
804 typedef struct {
805 DWORD blocksize;
806 BYTE data[1];
807 } nt_hbin_sub;
809 typedef struct {
810 DWORD id; /* 0x6E696268 'hbin' */
811 DWORD off_prev;
812 DWORD off_next;
813 DWORD uk1;
814 DWORD uk2; /* 0x10 */
815 DWORD uk3; /* 0x14 */
816 DWORD uk4; /* 0x18 */
817 DWORD size; /* 0x1C */
818 nt_hbin_sub hbin_sub; /* 0x20 */
819 } nt_hbin;
822 * the value_list consists of offsets to the values (vk)
824 typedef struct {
825 WORD SubBlockId; /* 0x00 0x6B6E */
826 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
827 FILETIME writetime; /* 0x04 */
828 DWORD uk1; /* 0x0C */
829 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
830 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
831 DWORD uk8; /* 0x18 */
832 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
833 DWORD uk2; /* 0x20 */
834 DWORD nr_values; /* 0x24 number of values */
835 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
836 DWORD off_sk; /* 0x2c Offset of the sk-Record */
837 DWORD off_class; /* 0x30 Offset of the Class-Name */
838 DWORD uk3; /* 0x34 */
839 DWORD uk4; /* 0x38 */
840 DWORD uk5; /* 0x3c */
841 DWORD uk6; /* 0x40 */
842 DWORD uk7; /* 0x44 */
843 WORD name_len; /* 0x48 name-length */
844 WORD class_len; /* 0x4a class-name length */
845 char name[1]; /* 0x4c key-name */
846 } nt_nk;
848 typedef struct {
849 DWORD off_nk; /* 0x00 */
850 DWORD name; /* 0x04 */
851 } hash_rec;
853 typedef struct {
854 WORD id; /* 0x00 0x666c */
855 WORD nr_keys; /* 0x06 */
856 hash_rec hash_rec[1];
857 } nt_lf;
860 list of subkeys without hash
862 li --+-->nk
864 +-->nk
866 typedef struct {
867 WORD id; /* 0x00 0x696c */
868 WORD nr_keys;
869 DWORD off_nk[1];
870 } nt_li;
873 this is a intermediate node
875 ri --+-->li--+-->nk
877 | +-->nk
879 +-->li--+-->nk
881 +-->nk
883 typedef struct {
884 WORD id; /* 0x00 0x6972 */
885 WORD nr_li; /* 0x02 number off offsets */
886 DWORD off_li[1]; /* 0x04 points to li */
887 } nt_ri;
889 typedef struct {
890 WORD id; /* 0x00 'vk' */
891 WORD nam_len;
892 DWORD data_len;
893 DWORD data_off;
894 DWORD type;
895 WORD flag;
896 WORD uk1;
897 char name[1];
898 } nt_vk;
901 * gets a value
903 * vk->flag:
904 * 0 value is a default value
905 * 1 the value has a name
907 * vk->data_len
908 * len of the whole data block
909 * - reg_sz (unicode)
910 * bytes including the terminating \0 = 2*(number_of_chars+1)
911 * - reg_dword, reg_binary:
912 * if highest bit of data_len is set data_off contains the value
914 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
916 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
917 struct key_value value;
919 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
920 ERR("unknown block found (0x%04x), please report!\n", vk->id);
921 return FALSE;
924 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
925 value.type = vk->type;
926 value.len = (vk->data_len & 0x7fffffff);
927 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
929 _dump_value(&value,f);
930 free(value.nameW);
932 return TRUE;
935 /* it's called from _nt_dump_lf() */
936 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
939 * get the subkeys
941 * this structure contains the hash of a keyname and points to all
942 * subkeys
944 * exception: if the id is 'il' there are no hash values and every
945 * dword is a offset
947 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
949 int i;
951 if (lf->id == NT_REG_HASH_BLOCK_ID) {
952 if (subkeys != lf->nr_keys) goto error1;
954 for (i=0; i<lf->nr_keys; i++)
955 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
956 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
957 nt_li * li = (nt_li*)lf;
958 if (subkeys != li->nr_keys) goto error1;
960 for (i=0; i<li->nr_keys; i++)
961 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
962 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
963 nt_ri * ri = (nt_ri*)lf;
964 int li_subkeys = 0;
966 /* count all subkeys */
967 for (i=0; i<ri->nr_li; i++) {
968 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
969 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
970 li_subkeys += li->nr_keys;
973 /* check number */
974 if (subkeys != li_subkeys) goto error1;
976 /* loop through the keys */
977 for (i=0; i<ri->nr_li; i++) {
978 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
979 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
981 } else goto error2;
983 return TRUE;
985 error2:
986 if (lf->id == 0x686c)
987 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
988 else
989 ERR("unknown node id 0x%04x, please report!\n", lf->id);
990 return TRUE;
992 error1:
993 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
994 return FALSE;
996 error:
997 ERR("error reading lf block\n");
998 return FALSE;
1001 /* _nt_dump_nk [Internal] */
1002 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
1004 unsigned int n;
1005 DWORD *vl;
1006 LPSTR new_key_name = NULL;
1008 TRACE("%s\n", key_name);
1010 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
1011 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1012 return FALSE;
1015 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1016 ERR("registry file corrupt!\n");
1017 return FALSE;
1020 /* create the new key */
1021 if (level <= 0) {
1022 /* create new subkey name */
1023 size_t len = strlen(key_name);
1024 new_key_name = _xmalloc( len+nk->name_len+2 );
1025 memcpy( new_key_name, key_name, len );
1026 if (len) new_key_name[len++] = '\\';
1027 memcpy( new_key_name + len, nk->name, nk->name_len );
1028 new_key_name[len + nk->name_len] = 0;
1030 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1031 1) key has some values
1032 2) key has no values and no subkeys
1034 if (nk->nr_values > 0) {
1035 /* there are some values */
1036 fprintf(f,"\n[");
1037 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1038 fprintf(f,"]\n");
1040 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1041 /* no subkeys and no values */
1042 fprintf(f,"\n[");
1043 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1044 fprintf(f,"]\n");
1047 /* loop trough the value list */
1048 vl = (DWORD *)(base+nk->valuelist_off+4);
1049 for (n=0; n<nk->nr_values; n++) {
1050 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1051 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1052 free(new_key_name);
1053 return FALSE;
1056 } else new_key_name = _xstrdup(key_name);
1058 /* loop through the subkeys */
1059 if (nk->nr_subkeys) {
1060 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1061 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1062 free(new_key_name);
1063 return FALSE;
1067 free(new_key_name);
1068 return TRUE;
1071 /* end nt loader */
1073 /**********************************************************************************
1074 * _set_registry_levels [Internal]
1076 * set level to 0 for loading system files
1077 * set level to 1 for loading user files
1079 static void _set_registry_levels(int level,int saving,int period)
1081 SERVER_START_REQ( set_registry_levels )
1083 req->current = level;
1084 req->saving = saving;
1085 req->period = period;
1086 wine_server_call( req );
1088 SERVER_END_REQ;
1091 /* _save_at_exit [Internal] */
1092 static void _save_at_exit(HKEY hkey,LPCSTR path)
1094 LPCSTR confdir = wine_get_config_dir();
1096 SERVER_START_REQ( save_registry_atexit )
1098 req->hkey = hkey;
1099 wine_server_add_data( req, confdir, strlen(confdir) );
1100 wine_server_add_data( req, path, strlen(path)+1 );
1101 wine_server_call( req );
1103 SERVER_END_REQ;
1106 /******************************************************************************
1107 * _allocate_default_keys [Internal]
1108 * Registry initialisation, allocates some default keys.
1110 static void _allocate_default_keys(void)
1112 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1113 'P','e','r','f','S','t','a','t','s','\\',
1114 'S','t','a','t','D','a','t','a',0};
1115 HKEY hkey;
1116 OBJECT_ATTRIBUTES attr;
1117 UNICODE_STRING nameW;
1119 TRACE("(void)\n");
1121 attr.Length = sizeof(attr);
1122 attr.RootDirectory = 0;
1123 attr.ObjectName = &nameW;
1124 attr.Attributes = 0;
1125 attr.SecurityDescriptor = NULL;
1126 attr.SecurityQualityOfService = NULL;
1128 RtlInitUnicodeString( &nameW, StatDataW );
1129 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1132 static void get_windows_dir(WCHAR* buffer, unsigned len)
1134 OBJECT_ATTRIBUTES attr;
1135 UNICODE_STRING nameW, keyW;
1136 HKEY hkey;
1138 attr.Length = sizeof(attr);
1139 attr.RootDirectory = 0;
1140 attr.ObjectName = &nameW;
1141 attr.Attributes = 0;
1142 attr.SecurityDescriptor = NULL;
1143 attr.SecurityQualityOfService = NULL;
1145 if (RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1147 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
1149 char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1150 DWORD count;
1152 RtlCreateUnicodeStringFromAsciiz( &keyW, "Windows");
1153 if (!NtQueryValueKey( hkey, &keyW, KeyValuePartialInformation,
1154 tmp, sizeof(tmp), &count ))
1156 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1157 memcpy(buffer, str, min(((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->DataLength, len));
1159 RtlFreeUnicodeString( &keyW );
1161 RtlFreeUnicodeString( &nameW );
1166 #define REG_DONTLOAD -1
1167 #define REG_WIN31 0
1168 #define REG_WIN95 1
1169 #define REG_WINNT 2
1171 /* return the type of native registry [Internal] */
1172 static int _get_reg_type(const WCHAR* windir)
1174 WCHAR tmp[MAX_PATHNAME_LEN];
1175 int ret = REG_WIN31;
1176 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};
1177 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1179 /* test %windir%/system32/config/system --> winnt */
1180 strcpyW(tmp, windir);
1181 strcatW(tmp, nt_reg_pathW);
1182 if(GetFileAttributesW(tmp) != (DWORD)-1)
1183 ret = REG_WINNT;
1184 else
1186 /* test %windir%/system.dat --> win95 */
1187 strcpyW(tmp, windir);
1188 strcatW(tmp, win9x_reg_pathW);
1189 if(GetFileAttributesW(tmp) != (DWORD)-1)
1190 ret = REG_WIN95;
1193 return ret;
1196 /* load the registry file in wine format [Internal] */
1197 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1199 HANDLE file;
1200 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1201 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1203 SERVER_START_REQ( load_registry )
1205 req->hkey = hkey;
1206 req->file = file;
1207 wine_server_call( req );
1209 SERVER_END_REQ;
1210 CloseHandle( file );
1214 /* generate and return the name of the tmp file and associated stream [Internal] */
1215 static LPSTR _get_tmp_fn(FILE **f)
1217 LPSTR ret;
1218 int tmp_fd,count;
1220 ret = _xmalloc(50);
1221 for (count = 0;;) {
1222 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1223 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1224 if (errno != EEXIST) {
1225 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1226 free(ret);
1227 *f = NULL;
1228 return NULL;
1232 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1233 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1234 close(tmp_fd);
1235 free(ret);
1236 return NULL;
1239 return ret;
1242 /* convert win95 native registry file to wine format [Internal] */
1243 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1245 HANDLE hFile, hMapping;
1246 FILE *f;
1247 void *base;
1248 LPSTR ret = NULL;
1249 OBJECT_ATTRIBUTES attr;
1250 LARGE_INTEGER lg_int;
1251 NTSTATUS nts;
1252 SIZE_T len;
1254 _w95creg *creg;
1255 _w95rgkn *rgkn;
1256 _w95dke *dke, *root_dke;
1258 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1259 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1261 attr.Length = sizeof(attr);
1262 attr.RootDirectory = 0;
1263 attr.ObjectName = NULL;
1264 attr.Attributes = 0;
1265 attr.SecurityDescriptor = NULL;
1266 attr.SecurityQualityOfService = NULL;
1268 lg_int.QuadPart = 0;
1269 nts = NtCreateSection( &hMapping,
1270 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1271 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1272 if (nts != STATUS_SUCCESS) goto error1;
1274 base = NULL; len = 0;
1275 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1276 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1277 PAGE_READONLY);
1278 NtClose( hMapping );
1279 if (nts != STATUS_SUCCESS) goto error1;
1281 /* control signature */
1282 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1283 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1284 debugstr_w(fn));
1285 goto error;
1288 creg = base;
1289 /* load the header (rgkn) */
1290 rgkn = (_w95rgkn*)(creg + 1);
1291 if (rgkn->id != W95_REG_RGKN_ID) {
1292 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1293 goto error;
1295 if (rgkn->root_off != 0x20) {
1296 ERR("rgkn->root_off not 0x20, please report !\n");
1297 goto error;
1299 if (rgkn->last_dke > rgkn->size)
1301 ERR("registry file corrupt! last_dke > size!\n");
1302 goto error;
1304 /* verify last dke */
1305 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1306 if (dke->x1 != 0x80000000)
1307 { /* wrong magic */
1308 ERR("last dke invalid !\n");
1309 goto error;
1311 if (rgkn->size > creg->rgdb_off)
1313 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1314 goto error;
1316 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1317 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1319 ERR("registry file corrupt! invalid root dke !\n");
1320 goto error;
1323 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1324 fprintf(f,"WINE REGISTRY Version 2");
1325 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1326 fclose(f);
1328 error:
1329 if(ret == NULL) {
1330 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1331 ERR("Please report this.\n");
1332 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1335 NtUnmapViewOfSection( GetCurrentProcess(), base );
1336 error1:
1337 NtClose(hFile);
1338 return ret;
1341 /* convert winnt native registry file to wine format [Internal] */
1342 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1344 FILE *f;
1345 void *base;
1346 LPSTR ret = NULL;
1347 HANDLE hFile;
1348 HANDLE hMapping;
1349 OBJECT_ATTRIBUTES attr;
1350 LARGE_INTEGER lg_int;
1351 NTSTATUS nts;
1352 SIZE_T len;
1354 nt_regf *regf;
1355 nt_hbin *hbin;
1356 nt_hbin_sub *hbin_sub;
1357 nt_nk *nk;
1359 TRACE("%s\n", debugstr_w(fn));
1361 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1362 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1363 attr.Length = sizeof(attr);
1364 attr.RootDirectory = 0;
1365 attr.ObjectName = NULL;
1366 attr.Attributes = 0;
1367 attr.SecurityDescriptor = NULL;
1368 attr.SecurityQualityOfService = NULL;
1370 lg_int.QuadPart = 0;
1371 nts = NtCreateSection( &hMapping,
1372 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1373 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1374 if (nts != STATUS_SUCCESS) goto error1;
1376 base = NULL; len = 0;
1377 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1378 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1379 PAGE_READONLY);
1380 NtClose( hMapping );
1381 if (nts != STATUS_SUCCESS) goto error1;
1383 /* control signature */
1384 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1385 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1386 debugstr_w(fn));
1387 goto error;
1390 /* start block */
1391 regf = base;
1393 /* hbin block */
1394 hbin = (nt_hbin*)((char*) base + 0x1000);
1395 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1396 ERR( "hbin block invalid\n");
1397 goto error;
1400 /* hbin_sub block */
1401 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1402 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1403 ERR( "hbin_sub block invalid\n");
1404 goto error;
1407 /* nk block */
1408 nk = (nt_nk*)&(hbin_sub->data[0]);
1409 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1410 ERR( "special nk block not found\n");
1411 goto error;
1414 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1415 fprintf(f,"WINE REGISTRY Version 2");
1416 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1417 fclose(f);
1419 error:
1420 NtUnmapViewOfSection( GetCurrentProcess(), base );
1421 error1:
1422 NtClose(hFile);
1423 return ret;
1426 /* convert native registry to wine format and load it via server call [Internal] */
1427 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1429 LPSTR tmp = NULL;
1431 switch (reg_type) {
1432 case REG_WINNT:
1433 /* FIXME: following function doesn't really convert yet */
1434 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1435 break;
1436 case REG_WIN95:
1437 tmp = _convert_win95_registry_to_wine_format(fn,level);
1438 break;
1439 case REG_WIN31:
1440 ERR("Don't know how to convert native 3.1 registry yet.\n");
1441 break;
1442 default:
1443 ERR("Unknown registry format parameter (%d)\n",reg_type);
1444 break;
1447 if (tmp != NULL) {
1448 load_wine_registry(hkey,tmp);
1449 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1450 debugstr_w(fn), tmp);
1451 unlink(tmp);
1453 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1454 free(tmp);
1457 /* load all native windows registry files [Internal] */
1458 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1459 HKEY hkey_users_default )
1461 int reg_type;
1462 WCHAR windir[MAX_PATHNAME_LEN];
1463 WCHAR path[MAX_PATHNAME_LEN];
1464 OBJECT_ATTRIBUTES attr;
1465 UNICODE_STRING nameW;
1466 HKEY hkey, profile_key;
1467 char tmp[1024];
1468 DWORD dummy;
1470 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
1471 'S','o','f','t','w','a','r','e','\\',
1472 'W','i','n','e','\\','W','i','n','e','\\',
1473 'C','o','n','f','i','g','\\','W','i','n','e',0};
1474 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1475 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1476 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1477 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1478 'S','y','s','t','e','m','\\',
1479 'C','l','o','n','e',0};
1481 attr.Length = sizeof(attr);
1482 attr.RootDirectory = 0;
1483 attr.ObjectName = &nameW;
1484 attr.Attributes = 0;
1485 attr.SecurityDescriptor = NULL;
1486 attr.SecurityQualityOfService = NULL;
1488 RtlInitUnicodeString( &nameW, WineW );
1489 if (NtCreateKey( &profile_key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) profile_key = 0;
1491 get_windows_dir(windir, sizeof(windir));
1493 reg_type = _get_reg_type(windir);
1494 switch (reg_type) {
1495 case REG_WINNT: {
1496 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1497 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};
1498 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};
1499 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};
1500 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1501 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};
1503 /* user specific ntuser.dat */
1504 RtlInitUnicodeString( &nameW, ProfileW );
1505 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1506 tmp, sizeof(tmp), &dummy ))
1508 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1509 strcatW(path, ntuser_datW);
1510 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1512 else
1514 MESSAGE("When you are running with a native NT directory specify\n");
1515 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1516 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1517 break;
1520 /* default user.dat */
1521 if (hkey_users_default) {
1522 strcpyW(path, windir);
1523 strcatW(path, defaultW);
1524 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1528 * FIXME
1529 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1531 RtlInitUnicodeString( &nameW, System );
1532 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1534 strcpyW(path, windir);
1535 strcatW(path, systemW);
1536 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1537 NtClose( hkey );
1539 RtlInitUnicodeString( &nameW, Software );
1540 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1542 strcpyW(path, windir);
1543 strcatW(path, softwareW);
1544 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1545 NtClose( hkey );
1548 strcpyW(path, windir);
1549 strcatW(path, samW);
1550 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1552 strcpyW(path,windir);
1553 strcatW(path, securityW);
1554 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1556 /* this key is generated when the nt-core booted successfully */
1557 RtlInitUnicodeString( &nameW, Clone );
1558 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1559 break;
1562 case REG_WIN95:
1564 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1565 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1566 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1567 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1569 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1571 strcpyW(path, windir);
1572 strcatW(path, system_datW);
1573 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1575 RtlInitUnicodeString( &nameW, ClassesRootW );
1576 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1578 strcpyW(path, windir);
1579 strcatW(path, classes_datW);
1580 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1581 NtClose( hkey );
1584 RtlInitUnicodeString( &nameW, ProfileW );
1585 if (profile_key && !NtQueryValueKey( profile_key, &nameW, KeyValuePartialInformation,
1586 tmp, sizeof(tmp), &dummy ))
1588 /* user specific user.dat */
1589 strcpyW(path, (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data);
1590 strcatW(path, user_datW);
1591 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1593 /* default user.dat */
1594 if (hkey_users_default) {
1595 strcpyW(path, windir);
1596 strcatW(path, user_datW);
1597 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1599 } else {
1600 strcpyW(path, windir);
1601 strcatW(path, user_datW);
1602 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1604 break;
1607 case REG_WIN31:
1608 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1609 _w31_loadreg();
1610 break;
1612 case REG_DONTLOAD:
1613 TRACE("REG_DONTLOAD\n");
1614 break;
1616 default:
1617 ERR("switch: no match (%d)\n",reg_type);
1618 break;
1621 if (profile_key) NtClose( profile_key );
1624 /* load home registry files (stored in ~/.wine) [Internal] */
1625 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1626 HKEY hkey_users_default )
1628 LPCSTR confdir = wine_get_config_dir();
1629 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1631 strcpy(tmp,confdir);
1632 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1633 load_wine_registry(hkey_users_default,tmp);
1635 strcpy(tmp,confdir);
1636 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1637 load_wine_registry(hkey_current_user,tmp);
1639 strcpy(tmp,confdir);
1640 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1641 load_wine_registry(hkey_local_machine,tmp);
1643 free(tmp);
1647 /* load all registry (native and global and home) */
1648 void SHELL_LoadRegistry( void )
1650 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1651 OBJECT_ATTRIBUTES attr;
1652 UNICODE_STRING nameW;
1653 DWORD count;
1654 BOOL res;
1655 int all, period;
1656 char tmp[1024];
1658 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1659 static const WCHAR UserW[] = {'U','s','e','r',0};
1660 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1661 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1662 'S','o','f','t','w','a','r','e','\\',
1663 'W','i','n','e','\\',
1664 'W','i','n','e','\\',
1665 'C','o','n','f','i','g','\\',
1666 'R','e','g','i','s','t','r','y',0};
1667 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};
1668 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};
1669 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};
1670 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1671 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1672 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};
1673 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1675 TRACE("(void)\n");
1677 if (!CLIENT_IsBootThread()) return; /* already loaded */
1679 attr.Length = sizeof(attr);
1680 attr.RootDirectory = 0;
1681 attr.ObjectName = &nameW;
1682 attr.Attributes = 0;
1683 attr.SecurityDescriptor = NULL;
1684 attr.SecurityQualityOfService = NULL;
1686 RtlInitUnicodeString( &nameW, MachineW );
1687 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1688 RtlInitUnicodeString( &nameW, UserW );
1689 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1691 attr.RootDirectory = hkey_users;
1692 RtlInitUnicodeString( &nameW, DefaultW );
1693 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1695 ERR("Cannot create HKEY_USERS/.Default\n" );
1696 ExitProcess(1);
1698 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1700 _set_registry_levels(0,0,0);
1701 _allocate_default_keys();
1703 attr.RootDirectory = 0;
1704 RtlInitUnicodeString( &nameW, RegistryW );
1705 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1707 /* load windows registry if required */
1709 res = TRUE;
1710 attr.RootDirectory = hkey_config;
1711 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1712 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1714 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1715 res = !IS_OPTION_FALSE(str[0]);
1717 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1719 /* load global registry if required */
1721 res = TRUE;
1722 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1723 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1725 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1726 res = !IS_OPTION_FALSE(str[0]);
1728 if (res)
1730 /* load global registry files (stored in /etc/wine) */
1731 char *p, configfile[MAX_PATHNAME_LEN];
1733 /* Override ETCDIR? */
1734 configfile[0] = 0;
1735 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1736 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1738 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1739 RtlUnicodeToMultiByteN( configfile, sizeof(configfile), NULL,
1740 str, (strlenW(str) + 1) * sizeof(WCHAR));
1742 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1744 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1746 /* Load the global HKU hive directly from sysconfdir */
1747 p = configfile + strlen(configfile);
1748 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1749 load_wine_registry( hkey_users, configfile );
1751 /* Load the global machine defaults directly from sysconfdir */
1752 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1753 load_wine_registry( hkey_local_machine, configfile );
1756 _set_registry_levels(1,0,0);
1758 /* load home registry if required */
1760 res = TRUE;
1761 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
1762 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1764 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1765 res = !IS_OPTION_FALSE(str[0]);
1767 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1769 /* setup registry saving */
1771 all = FALSE;
1772 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
1773 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1775 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1776 all = IS_OPTION_FALSE(str[0]);
1779 period = 0;
1780 RtlInitUnicodeString( &nameW, PeriodicSaveW );
1781 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1783 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1784 period = (int)strtolW(str, NULL, 10);
1787 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1788 _set_registry_levels(1,!all,period*1000);
1790 /* setup keys to save */
1792 res = TRUE;
1793 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
1794 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1796 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1797 res = !IS_OPTION_FALSE(str[0]);
1799 if (res)
1801 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1802 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1803 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1806 NtClose(hkey_users_default);
1807 NtClose(hkey_current_user);
1808 NtClose(hkey_users);
1809 NtClose(hkey_local_machine);
1810 NtClose(hkey_config);