Support resources in cross-compiled tests.
[wine/wine-kai.git] / misc / registry.c
blobb2800df6289fc16ff76c78f8d3f833ae263f2198
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 #include "windef.h"
54 #include "winerror.h"
55 #include "winreg.h"
57 #include "wine/winbase16.h"
58 #include "wine/library.h"
59 #include "wine/server.h"
60 #include "wine/unicode.h"
61 #include "file.h"
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(reg);
67 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
68 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
70 /* relative in ~user/.wine/ : */
71 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
72 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
73 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
75 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
76 'S','o','f','t','w','a','r','e','\\',
77 'C','l','a','s','s','e','s',0};
79 #define IS_OPTION_FALSE(ch) \
80 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
82 /* _xmalloc [Internal] */
83 static void *_xmalloc( size_t size )
85 void *res;
87 res = malloc (size ? size : 1);
88 if (res == NULL) {
89 WARN("Virtual memory exhausted.\n");
90 exit (1);
92 return res;
95 /* _strdupnA [Internal] */
96 static LPSTR _strdupnA(LPCSTR str,size_t len)
98 LPSTR ret;
100 if (!str) return NULL;
101 ret = _xmalloc( len + 1 );
102 memcpy( ret, str, len );
103 ret[len] = 0x00;
104 return ret;
107 /* convert ansi string to unicode [Internal] */
108 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
110 LPWSTR ret;
111 size_t lenW;
113 if (!strA) return NULL;
114 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
115 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
116 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
117 ret[lenW] = 0;
118 return ret;
121 /* dump a Unicode string with proper escaping [Internal] */
122 /* FIXME: this code duplicates server/unicode.c */
123 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
125 static const char escapes[32] = ".......abtnvfr.............e....";
126 char buffer[256];
127 LPSTR pos = buffer;
128 int count = 0;
130 for (; len; str++, len--)
132 if (pos > buffer + sizeof(buffer) - 8)
134 fwrite( buffer, pos - buffer, 1, f );
135 count += pos - buffer;
136 pos = buffer;
138 if (*str > 127) /* hex escape */
140 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
141 pos += sprintf( pos, "\\x%04x", *str );
142 else
143 pos += sprintf( pos, "\\x%x", *str );
144 continue;
146 if (*str < 32) /* octal or C escape */
148 if (!*str && len == 1) continue; /* do not output terminating NULL */
149 if (escapes[*str] != '.')
150 pos += sprintf( pos, "\\%c", escapes[*str] );
151 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
152 pos += sprintf( pos, "\\%03o", *str );
153 else
154 pos += sprintf( pos, "\\%o", *str );
155 continue;
157 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
158 *pos++ = *str;
160 fwrite( buffer, pos - buffer, 1, f );
161 count += pos - buffer;
162 return count;
165 /* convert ansi string to unicode and dump with proper escaping [Internal] */
166 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
168 WCHAR *strW;
169 int ret;
171 if (strA == NULL) return 0;
172 strW = _strdupnAtoW(strA,len);
173 ret = _dump_strW(strW,len,f,escape);
174 free(strW);
175 return ret;
178 /* a key value */
179 /* FIXME: this code duplicates server/registry.c */
180 struct key_value {
181 WCHAR *nameW; /* value name */
182 int type; /* value type */
183 size_t len; /* value data length in bytes */
184 void *data; /* pointer to value data */
187 /* dump a value to a text file */
188 /* FIXME: this code duplicates server/registry.c */
189 static void _dump_value(struct key_value *value,FILE *f)
191 int i, count;
193 if (value->nameW[0]) {
194 fputc( '\"', f );
195 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
196 count += fprintf( f, "\"=" );
198 else count = fprintf( f, "@=" );
200 switch(value->type) {
201 case REG_SZ:
202 case REG_EXPAND_SZ:
203 case REG_MULTI_SZ:
204 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
205 fputc( '\"', f );
206 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
207 fputc( '\"', f );
208 break;
209 case REG_DWORD:
210 if (value->len == sizeof(DWORD)) {
211 DWORD dw;
212 memcpy( &dw, value->data, sizeof(DWORD) );
213 fprintf( f, "dword:%08lx", dw );
214 break;
216 /* else fall through */
217 default:
218 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
219 else count += fprintf( f, "hex(%x):", value->type );
220 for (i = 0; i < value->len; i++) {
221 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
222 if (i < value->len-1) {
223 fputc( ',', f );
224 if (++count > 76) {
225 fprintf( f, "\\\n " );
226 count = 2;
230 break;
232 fputc( '\n', f );
235 /******************************************************************/
236 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
238 reghack - windows 3.11 registry data format demo program.
240 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
241 a combined hash table and tree description, and finally a text table.
243 The header is obvious from the struct header. The taboff1 and taboff2
244 fields are always 0x20, and their usage is unknown.
246 The 8-byte entry table has various entry types.
248 tabent[0] is a root index. The second word has the index of the root of
249 the directory.
250 tabent[1..hashsize] is a hash table. The first word in the hash entry is
251 the index of the key/value that has that hash. Data with the same
252 hash value are on a circular list. The other three words in the
253 hash entry are always zero.
254 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
255 entry: dirent and keyent/valent. They are identified by context.
256 tabent[freeidx] is the first free entry. The first word in a free entry
257 is the index of the next free entry. The last has 0 as a link.
258 The other three words in the free list are probably irrelevant.
260 Entries in text table are preceded by a word at offset-2. This word
261 has the value (2*index)+1, where index is the referring keyent/valent
262 entry in the table. I have no suggestion for the 2* and the +1.
263 Following the word, there are N bytes of data, as per the keyent/valent
264 entry length. The offset of the keyent/valent entry is from the start
265 of the text table to the first data byte.
267 This information is not available from Microsoft. The data format is
268 deduced from the reg.dat file by me. Mistakes may
269 have been made. I claim no rights and give no guarantees for this program.
271 Tor Sjøwall, tor@sn.no
274 /* reg.dat header format */
275 struct _w31_header {
276 char cookie[8]; /* 'SHCC3.10' */
277 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
278 unsigned long taboff2; /* offset of index table (??) = 0x20 */
279 unsigned long tabcnt; /* number of entries in index table */
280 unsigned long textoff; /* offset of text part */
281 unsigned long textsize; /* byte size of text part */
282 unsigned short hashsize; /* hash size */
283 unsigned short freeidx; /* free index */
286 /* generic format of table entries */
287 struct _w31_tabent {
288 unsigned short w0, w1, w2, w3;
291 /* directory tabent: */
292 struct _w31_dirent {
293 unsigned short sibling_idx; /* table index of sibling dirent */
294 unsigned short child_idx; /* table index of child dirent */
295 unsigned short key_idx; /* table index of key keyent */
296 unsigned short value_idx; /* table index of value valent */
299 /* key tabent: */
300 struct _w31_keyent {
301 unsigned short hash_idx; /* hash chain index for string */
302 unsigned short refcnt; /* reference count */
303 unsigned short length; /* length of string */
304 unsigned short string_off; /* offset of string in text table */
307 /* value tabent: */
308 struct _w31_valent {
309 unsigned short hash_idx; /* hash chain index for string */
310 unsigned short refcnt; /* reference count */
311 unsigned short length; /* length of string */
312 unsigned short string_off; /* offset of string in text table */
315 /* recursive helper function to display a directory tree [Internal] */
316 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
318 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
319 struct _w31_dirent *dir;
320 struct _w31_keyent *key;
321 struct _w31_valent *val;
322 HKEY subkey = 0;
323 OBJECT_ATTRIBUTES attr;
324 UNICODE_STRING nameW, valueW;
325 static WCHAR tail[400];
327 attr.Length = sizeof(attr);
328 attr.RootDirectory = hkey;
329 attr.ObjectName = &nameW;
330 attr.Attributes = 0;
331 attr.SecurityDescriptor = NULL;
332 attr.SecurityQualityOfService = NULL;
333 RtlInitUnicodeString( &valueW, NULL );
335 while (idx!=0) {
336 dir=(struct _w31_dirent*)&tab[idx];
338 if (dir->key_idx) {
339 DWORD len;
340 key = (struct _w31_keyent*)&tab[dir->key_idx];
342 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
343 &txt[key->string_off], key->length);
344 tail[len/sizeof(WCHAR)] = 0;
346 /* all toplevel entries AND the entries in the
347 * toplevel subdirectory belong to \SOFTWARE\Classes
349 if (!level && !strcmpW(tail,classesW))
351 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
352 idx=dir->sibling_idx;
353 continue;
356 if (subkey) NtClose( subkey );
357 RtlInitUnicodeString( &nameW, tail );
358 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
360 /* only add if leaf node or valued node */
361 if (dir->value_idx!=0||dir->child_idx==0) {
362 if (dir->value_idx) {
363 DWORD len;
364 val=(struct _w31_valent*)&tab[dir->value_idx];
365 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
366 &txt[val->string_off], val->length);
367 tail[len/sizeof(WCHAR)] = 0;
368 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
371 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
372 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
373 idx=dir->sibling_idx;
375 if (subkey) NtClose( subkey );
379 /******************************************************************************
380 * _w31_loadreg [Internal]
382 void _w31_loadreg(void)
384 HFILE hf;
385 HKEY root;
386 OBJECT_ATTRIBUTES attr;
387 UNICODE_STRING nameW;
388 struct _w31_header head;
389 struct _w31_tabent *tab;
390 unsigned char *txt;
391 unsigned int len;
392 OFSTRUCT ofs;
393 BY_HANDLE_FILE_INFORMATION hfinfo;
394 time_t lastmodified;
396 TRACE("(void)\n");
398 hf = OpenFile("reg.dat",&ofs,OF_READ);
399 if (hf==HFILE_ERROR) return;
401 /* read & dump header */
402 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
403 ERR("reg.dat is too short.\n");
404 _lclose(hf);
405 return;
407 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
408 ERR("reg.dat has bad signature.\n");
409 _lclose(hf);
410 return;
413 len = head.tabcnt * sizeof(struct _w31_tabent);
414 /* read and dump index table */
415 tab = _xmalloc(len);
416 if (len!=_lread(hf,tab,len)) {
417 ERR("couldn't read %d bytes.\n",len);
418 free(tab);
419 _lclose(hf);
420 return;
423 /* read text */
424 txt = _xmalloc(head.textsize);
425 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
426 ERR("couldn't seek to textblock.\n");
427 free(tab);
428 free(txt);
429 _lclose(hf);
430 return;
432 if (head.textsize!=_lread(hf,txt,head.textsize)) {
433 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
434 free(tab);
435 free(txt);
436 _lclose(hf);
437 return;
440 if (!GetFileInformationByHandle((HANDLE)hf,&hfinfo)) {
441 ERR("GetFileInformationByHandle failed?.\n");
442 free(tab);
443 free(txt);
444 _lclose(hf);
445 return;
447 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
449 attr.Length = sizeof(attr);
450 attr.RootDirectory = 0;
451 attr.ObjectName = &nameW;
452 attr.Attributes = 0;
453 attr.SecurityDescriptor = NULL;
454 attr.SecurityQualityOfService = NULL;
455 RtlInitUnicodeString( &nameW, ClassesRootW );
457 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
459 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
460 NtClose( root );
462 free(tab);
463 free(txt);
464 _lclose(hf);
465 return;
468 /***********************************************************************************/
469 /* windows 95 registry loader */
470 /***********************************************************************************/
472 /* SECTION 1: main header
474 * once at offset 0
476 #define W95_REG_CREG_ID 0x47455243
478 typedef struct {
479 DWORD id; /* "CREG" = W95_REG_CREG_ID */
480 DWORD version; /* ???? 0x00010000 */
481 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
482 DWORD uk2; /* 0x0c */
483 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
484 WORD uk3;
485 DWORD uk[3];
486 /* rgkn */
487 } _w95creg;
489 /* SECTION 2: Directory information (tree structure)
491 * once on offset 0x20
493 * structure: [rgkn][dke]* (repeat till last_dke is reached)
495 #define W95_REG_RGKN_ID 0x4e4b4752
497 typedef struct {
498 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
499 DWORD size; /* Size of the RGKN-block */
500 DWORD root_off; /* Rel. Offset of the root-record */
501 DWORD last_dke; /* Offset to last DKE ? */
502 DWORD uk[4];
503 } _w95rgkn;
505 /* Disk Key Entry Structure
507 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
508 * hive itself. It looks the same like other keys. Even the ID-number can
509 * be any value.
511 * The "hash"-value is a value representing the key's name. Windows will not
512 * search for the name, but for a matching hash-value. if it finds one, it
513 * will compare the actual string info, otherwise continue with the next key.
514 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
515 * of the string which are smaller than 0x80 (128) to this D-Word.
517 * If you want to modify key names, also modify the hash-values, since they
518 * cannot be found again (although they would be displayed in REGEDIT)
519 * End of list-pointers are filled with 0xFFFFFFFF
521 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
522 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
523 * structure) and reading another RGDB_section.
525 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
526 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
527 * The remaining space between last_dke and the offset calculated from
528 * rgkn->size seems to be free for use for more dke:s.
529 * So it seems if more dke:s are added, they are added to that space and
530 * last_dke is grown, and in case that "free" space is out, the space
531 * gets grown and rgkn->size gets adjusted.
533 * there is a one to one relationship between dke and dkh
535 /* key struct, once per key */
536 typedef struct {
537 DWORD x1; /* Free entry indicator(?) */
538 DWORD hash; /* sum of bytes of keyname */
539 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
540 DWORD prevlvl; /* offset of previous key */
541 DWORD nextsub; /* offset of child key */
542 DWORD next; /* offset of sibling key */
543 WORD nrLS; /* id inside the rgdb block */
544 WORD nrMS; /* number of the rgdb block */
545 } _w95dke;
547 /* SECTION 3: key information, values and data
549 * structure:
550 * section: [blocks]* (repeat creg->rgdb_num times)
551 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
552 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
554 * An interesting relationship exists in RGDB_section. The DWORD value
555 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
556 * I have no idea at the moment what this means. (Kevin Cozens)
559 /* block header, once per block */
560 #define W95_REG_RGDB_ID 0x42444752
562 typedef struct {
563 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
564 DWORD size; /* 0x04 */
565 DWORD uk1; /* 0x08 */
566 DWORD uk2; /* 0x0c */
567 DWORD uk3; /* 0x10 */
568 DWORD uk4; /* 0x14 */
569 DWORD uk5; /* 0x18 */
570 DWORD uk6; /* 0x1c */
571 /* dkh */
572 } _w95rgdb;
574 /* Disk Key Header structure (RGDB part), once per key */
575 typedef struct {
576 DWORD nextkeyoff; /* 0x00 offset to next dkh */
577 WORD nrLS; /* 0x04 id inside the rgdb block */
578 WORD nrMS; /* 0x06 number of the rgdb block */
579 DWORD bytesused; /* 0x08 */
580 WORD keynamelen; /* 0x0c len of name */
581 WORD values; /* 0x0e number of values */
582 DWORD xx1; /* 0x10 */
583 char name[1]; /* 0x14 */
584 /* dkv */ /* 0x14 + keynamelen */
585 } _w95dkh;
587 /* Disk Key Value structure, once per value */
588 typedef struct {
589 DWORD type; /* 0x00 */
590 DWORD x1; /* 0x04 */
591 WORD valnamelen; /* 0x08 length of name, 0 is default key */
592 WORD valdatalen; /* 0x0A length of data */
593 char name[1]; /* 0x0c */
594 /* raw data */ /* 0x0c + valnamelen */
595 } _w95dkv;
597 /******************************************************************************
598 * _w95_lookup_dkh [Internal]
600 * seeks the dkh belonging to a dke
602 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
604 _w95rgdb * rgdb;
605 _w95dkh * dkh;
606 int i;
608 /* get the beginning of the rgdb datastore */
609 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
611 /* check: requested block < last_block) */
612 if (creg->rgdb_num <= nrMS) {
613 ERR("registry file corrupt! requested block no. beyond end.\n");
614 goto error;
617 /* find the right block */
618 for(i=0; i<nrMS ;i++) {
619 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
620 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
621 goto error;
623 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
626 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
628 do {
629 if(nrLS==dkh->nrLS ) return dkh;
630 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
631 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
633 error:
634 return NULL;
637 /******************************************************************************
638 * _w95_dump_dkv [Internal]
640 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
642 _w95dkv * dkv;
643 int i;
645 /* first value block */
646 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
648 /* loop through the values */
649 for (i=0; i< dkh->values; i++) {
650 struct key_value value;
651 WCHAR *pdata;
653 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
654 value.type = dkv->type;
655 value.len = dkv->valdatalen;
657 value.data = &(dkv->name[dkv->valnamelen]);
658 pdata = NULL;
659 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
660 pdata = _strdupnAtoW(value.data,value.len);
661 value.len *= 2;
663 if (pdata != NULL) value.data = pdata;
665 _dump_value(&value,f);
666 free(value.nameW);
667 if (pdata != NULL) free(pdata);
669 /* next value */
670 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
672 return TRUE;
675 /******************************************************************************
676 * _w95_dump_dke [Internal]
678 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
680 _w95dkh * dkh;
681 LPSTR new_key_name = NULL;
683 /* special root key */
684 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
686 /* parse the one subkey */
687 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
688 /* has no sibling keys */
689 return FALSE;
692 /* search subblock */
693 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
694 ERR("dke pointing to missing dkh !\n");
695 return FALSE;
698 if (level <= 0) {
699 /* create new subkey name */
700 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
701 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
702 strncat(new_key_name,dkh->name,dkh->keynamelen);
704 /* walk sibling keys */
705 if (dke->next != 0xffffffff ) {
706 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
707 free(new_key_name);
708 return FALSE;
712 /* write the key path (something like [Software\\Microsoft\\..]) only if:
713 1) key has some values
714 2) key has no values and no subkeys
716 if (dkh->values > 0) {
717 /* there are some values */
718 fprintf(f,"\n[");
719 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
720 fprintf(f,"]\n");
721 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
722 free(new_key_name);
723 return FALSE;
726 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
727 /* no subkeys and no values */
728 fprintf(f,"\n[");
729 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
730 fprintf(f,"]\n");
732 } else new_key_name = _strdupnA(key_name,strlen(key_name));
734 /* next sub key */
735 if (dke->nextsub != 0xffffffff) {
736 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
737 free(new_key_name);
738 return FALSE;
742 free(new_key_name);
743 return TRUE;
745 /* end windows 95 loader */
747 /***********************************************************************************/
748 /* windows NT registry loader */
749 /***********************************************************************************/
751 /* NT REGISTRY LOADER */
753 #ifdef HAVE_SYS_MMAN_H
754 # include <sys/mman.h>
755 #endif
757 #ifndef MAP_FAILED
758 #define MAP_FAILED ((LPVOID)-1)
759 #endif
761 #define NT_REG_BLOCK_SIZE 0x1000
763 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
764 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
765 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
766 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
768 /* subblocks of nk */
769 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
770 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
771 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
773 #define NT_REG_KEY_BLOCK_TYPE 0x20
774 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
776 typedef struct {
777 DWORD id; /* 0x66676572 'regf'*/
778 DWORD uk1; /* 0x04 */
779 DWORD uk2; /* 0x08 */
780 FILETIME DateModified; /* 0x0c */
781 DWORD uk3; /* 0x14 */
782 DWORD uk4; /* 0x18 */
783 DWORD uk5; /* 0x1c */
784 DWORD uk6; /* 0x20 */
785 DWORD RootKeyBlock; /* 0x24 */
786 DWORD BlockSize; /* 0x28 */
787 DWORD uk7[116];
788 DWORD Checksum; /* at offset 0x1FC */
789 } nt_regf;
791 typedef struct {
792 DWORD blocksize;
793 BYTE data[1];
794 } nt_hbin_sub;
796 typedef struct {
797 DWORD id; /* 0x6E696268 'hbin' */
798 DWORD off_prev;
799 DWORD off_next;
800 DWORD uk1;
801 DWORD uk2; /* 0x10 */
802 DWORD uk3; /* 0x14 */
803 DWORD uk4; /* 0x18 */
804 DWORD size; /* 0x1C */
805 nt_hbin_sub hbin_sub; /* 0x20 */
806 } nt_hbin;
809 * the value_list consists of offsets to the values (vk)
811 typedef struct {
812 WORD SubBlockId; /* 0x00 0x6B6E */
813 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
814 FILETIME writetime; /* 0x04 */
815 DWORD uk1; /* 0x0C */
816 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
817 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
818 DWORD uk8; /* 0x18 */
819 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
820 DWORD uk2; /* 0x20 */
821 DWORD nr_values; /* 0x24 number of values */
822 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
823 DWORD off_sk; /* 0x2c Offset of the sk-Record */
824 DWORD off_class; /* 0x30 Offset of the Class-Name */
825 DWORD uk3; /* 0x34 */
826 DWORD uk4; /* 0x38 */
827 DWORD uk5; /* 0x3c */
828 DWORD uk6; /* 0x40 */
829 DWORD uk7; /* 0x44 */
830 WORD name_len; /* 0x48 name-length */
831 WORD class_len; /* 0x4a class-name length */
832 char name[1]; /* 0x4c key-name */
833 } nt_nk;
835 typedef struct {
836 DWORD off_nk; /* 0x00 */
837 DWORD name; /* 0x04 */
838 } hash_rec;
840 typedef struct {
841 WORD id; /* 0x00 0x666c */
842 WORD nr_keys; /* 0x06 */
843 hash_rec hash_rec[1];
844 } nt_lf;
847 list of subkeys without hash
849 li --+-->nk
851 +-->nk
853 typedef struct {
854 WORD id; /* 0x00 0x696c */
855 WORD nr_keys;
856 DWORD off_nk[1];
857 } nt_li;
860 this is a intermediate node
862 ri --+-->li--+-->nk
864 | +-->nk
866 +-->li--+-->nk
868 +-->nk
870 typedef struct {
871 WORD id; /* 0x00 0x6972 */
872 WORD nr_li; /* 0x02 number off offsets */
873 DWORD off_li[1]; /* 0x04 points to li */
874 } nt_ri;
876 typedef struct {
877 WORD id; /* 0x00 'vk' */
878 WORD nam_len;
879 DWORD data_len;
880 DWORD data_off;
881 DWORD type;
882 WORD flag;
883 WORD uk1;
884 char name[1];
885 } nt_vk;
888 * gets a value
890 * vk->flag:
891 * 0 value is a default value
892 * 1 the value has a name
894 * vk->data_len
895 * len of the whole data block
896 * - reg_sz (unicode)
897 * bytes including the terminating \0 = 2*(number_of_chars+1)
898 * - reg_dword, reg_binary:
899 * if highest bit of data_len is set data_off contains the value
901 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
903 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
904 struct key_value value;
906 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
907 ERR("unknown block found (0x%04x), please report!\n", vk->id);
908 return FALSE;
911 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
912 value.type = vk->type;
913 value.len = (vk->data_len & 0x7fffffff);
914 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
916 _dump_value(&value,f);
917 free(value.nameW);
919 return TRUE;
922 /* it's called from _nt_dump_lf() */
923 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
926 * get the subkeys
928 * this structure contains the hash of a keyname and points to all
929 * subkeys
931 * exception: if the id is 'il' there are no hash values and every
932 * dword is a offset
934 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
936 int i;
938 if (lf->id == NT_REG_HASH_BLOCK_ID) {
939 if (subkeys != lf->nr_keys) goto error1;
941 for (i=0; i<lf->nr_keys; i++)
942 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
943 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
944 nt_li * li = (nt_li*)lf;
945 if (subkeys != li->nr_keys) goto error1;
947 for (i=0; i<li->nr_keys; i++)
948 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
949 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
950 nt_ri * ri = (nt_ri*)lf;
951 int li_subkeys = 0;
953 /* count all subkeys */
954 for (i=0; i<ri->nr_li; i++) {
955 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
956 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
957 li_subkeys += li->nr_keys;
960 /* check number */
961 if (subkeys != li_subkeys) goto error1;
963 /* loop through the keys */
964 for (i=0; i<ri->nr_li; i++) {
965 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
966 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
968 } else goto error2;
970 return TRUE;
972 error2:
973 if (lf->id == 0x686c)
974 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
975 else
976 ERR("unknown node id 0x%04x, please report!\n", lf->id);
977 return TRUE;
979 error1:
980 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
981 return FALSE;
983 error:
984 ERR("error reading lf block\n");
985 return FALSE;
988 /* _nt_dump_nk [Internal] */
989 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
991 unsigned int n;
992 DWORD *vl;
993 LPSTR new_key_name = NULL;
995 TRACE("%s\n", key_name);
997 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
998 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
999 return FALSE;
1002 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1003 ERR("registry file corrupt!\n");
1004 return FALSE;
1007 /* create the new key */
1008 if (level <= 0) {
1009 /* create new subkey name */
1010 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
1011 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
1012 strncat(new_key_name,nk->name,nk->name_len);
1014 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1015 1) key has some values
1016 2) key has no values and no subkeys
1018 if (nk->nr_values > 0) {
1019 /* there are some values */
1020 fprintf(f,"\n[");
1021 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1022 fprintf(f,"]\n");
1024 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1025 /* no subkeys and no values */
1026 fprintf(f,"\n[");
1027 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1028 fprintf(f,"]\n");
1031 /* loop trough the value list */
1032 vl = (DWORD *)(base+nk->valuelist_off+4);
1033 for (n=0; n<nk->nr_values; n++) {
1034 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1035 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1036 free(new_key_name);
1037 return FALSE;
1040 } else new_key_name = _strdupnA(key_name,strlen(key_name));
1042 /* loop through the subkeys */
1043 if (nk->nr_subkeys) {
1044 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1045 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1046 free(new_key_name);
1047 return FALSE;
1051 free(new_key_name);
1052 return TRUE;
1055 /* end nt loader */
1057 /**********************************************************************************
1058 * _set_registry_levels [Internal]
1060 * set level to 0 for loading system files
1061 * set level to 1 for loading user files
1063 static void _set_registry_levels(int level,int saving,int period)
1065 SERVER_START_REQ( set_registry_levels )
1067 req->current = level;
1068 req->saving = saving;
1069 req->period = period;
1070 wine_server_call( req );
1072 SERVER_END_REQ;
1075 /* _save_at_exit [Internal] */
1076 static void _save_at_exit(HKEY hkey,LPCSTR path)
1078 LPCSTR confdir = wine_get_config_dir();
1080 SERVER_START_REQ( save_registry_atexit )
1082 req->hkey = hkey;
1083 wine_server_add_data( req, confdir, strlen(confdir) );
1084 wine_server_add_data( req, path, strlen(path)+1 );
1085 wine_server_call( req );
1087 SERVER_END_REQ;
1090 /******************************************************************************
1091 * _allocate_default_keys [Internal]
1092 * Registry initialisation, allocates some default keys.
1094 static void _allocate_default_keys(void)
1096 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1097 'P','e','r','f','S','t','a','t','s','\\',
1098 'S','t','a','t','D','a','t','a',0};
1099 HKEY hkey;
1100 OBJECT_ATTRIBUTES attr;
1101 UNICODE_STRING nameW;
1103 TRACE("(void)\n");
1105 attr.Length = sizeof(attr);
1106 attr.RootDirectory = 0;
1107 attr.ObjectName = &nameW;
1108 attr.Attributes = 0;
1109 attr.SecurityDescriptor = NULL;
1110 attr.SecurityQualityOfService = NULL;
1112 RtlInitUnicodeString( &nameW, StatDataW );
1113 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1116 #define REG_DONTLOAD -1
1117 #define REG_WIN31 0
1118 #define REG_WIN95 1
1119 #define REG_WINNT 2
1121 /* return the type of native registry [Internal] */
1122 static int _get_reg_type(void)
1124 WCHAR windir[MAX_PATHNAME_LEN];
1125 WCHAR tmp[MAX_PATHNAME_LEN];
1126 int ret = REG_WIN31;
1127 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};
1128 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1130 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1132 /* test %windir%/system32/config/system --> winnt */
1133 strcpyW(tmp, windir);
1134 strcatW(tmp, nt_reg_pathW);
1135 if(GetFileAttributesW(tmp) != (DWORD)-1)
1136 ret = REG_WINNT;
1137 else
1139 /* test %windir%/system.dat --> win95 */
1140 strcpyW(tmp, windir);
1141 strcatW(tmp, win9x_reg_pathW);
1142 if(GetFileAttributesW(tmp) != (DWORD)-1)
1143 ret = REG_WIN95;
1146 return ret;
1149 #define WINE_REG_VER_ERROR -1
1150 #define WINE_REG_VER_1 0
1151 #define WINE_REG_VER_2 1
1152 #define WINE_REG_VER_OLD 2
1153 #define WINE_REG_VER_UNKNOWN 3
1155 /* return the version of wine registry file [Internal] */
1156 static int _get_wine_registry_file_format_version(LPCSTR fn)
1158 FILE *f;
1159 char tmp[50];
1160 int ver;
1162 if ((f=fopen(fn,"rt")) == NULL) {
1163 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1164 return WINE_REG_VER_ERROR;
1167 if (fgets(tmp,50,f) == NULL) {
1168 WARN("Error reading %s: %s\n",fn,strerror(errno));
1169 fclose(f);
1170 return WINE_REG_VER_ERROR;
1172 fclose(f);
1174 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1175 switch (ver) {
1176 case 1:
1177 return WINE_REG_VER_1;
1178 break;
1179 case 2:
1180 return WINE_REG_VER_2;
1181 break;
1182 default:
1183 return WINE_REG_VER_UNKNOWN;
1187 /* load the registry file in wine format [Internal] */
1188 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1190 int file_format;
1192 file_format = _get_wine_registry_file_format_version(fn);
1193 switch (file_format) {
1195 case WINE_REG_VER_1:
1196 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1197 break;
1199 case WINE_REG_VER_2: {
1200 HANDLE file;
1201 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1202 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1204 SERVER_START_REQ( load_registry )
1206 req->hkey = hkey;
1207 req->file = file;
1208 wine_server_call( req );
1210 SERVER_END_REQ;
1211 CloseHandle( file );
1213 break;
1216 case WINE_REG_VER_UNKNOWN:
1217 WARN("Unable to load registry file %s: unknown format.\n",fn);
1218 break;
1220 case WINE_REG_VER_ERROR:
1221 break;
1225 /* generate and return the name of the tmp file and associated stream [Internal] */
1226 static LPSTR _get_tmp_fn(FILE **f)
1228 LPSTR ret;
1229 int tmp_fd,count;
1231 ret = _xmalloc(50);
1232 for (count = 0;;) {
1233 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1234 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1235 if (errno != EEXIST) {
1236 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1237 free(ret);
1238 *f = NULL;
1239 return NULL;
1243 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1244 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1245 close(tmp_fd);
1246 free(ret);
1247 return NULL;
1250 return ret;
1253 /* convert win95 native registry file to wine format [Internal] */
1254 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1256 int fd;
1257 FILE *f;
1258 DOS_FULL_NAME full_name;
1259 void *base;
1260 LPSTR ret = NULL;
1261 struct stat st;
1263 _w95creg *creg;
1264 _w95rgkn *rgkn;
1265 _w95dke *dke, *root_dke;
1267 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1269 /* map the registry into the memory */
1270 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1271 if ((fstat(fd, &st) == -1)) goto error1;
1272 if (!st.st_size) goto error1;
1273 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1275 /* control signature */
1276 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1277 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1278 debugstr_w(fn));
1279 goto error;
1282 creg = base;
1283 /* load the header (rgkn) */
1284 rgkn = (_w95rgkn*)(creg + 1);
1285 if (rgkn->id != W95_REG_RGKN_ID) {
1286 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1287 goto error;
1289 if (rgkn->root_off != 0x20) {
1290 ERR("rgkn->root_off not 0x20, please report !\n");
1291 goto error;
1293 if (rgkn->last_dke > rgkn->size)
1295 ERR("registry file corrupt! last_dke > size!\n");
1296 goto error;
1298 /* verify last dke */
1299 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1300 if (dke->x1 != 0x80000000)
1301 { /* wrong magic */
1302 ERR("last dke invalid !\n");
1303 goto error;
1305 if (rgkn->size > creg->rgdb_off)
1307 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1308 goto error;
1310 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1311 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1313 ERR("registry file corrupt! invalid root dke !\n");
1314 goto error;
1317 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1318 fprintf(f,"WINE REGISTRY Version 2");
1319 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1320 fclose(f);
1322 error:
1323 if(ret == NULL) {
1324 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1325 ERR("Please report this.\n");
1326 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1329 munmap(base, st.st_size);
1330 error1:
1331 close(fd);
1332 return ret;
1335 /* convert winnt native registry file to wine format [Internal] */
1336 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1338 FILE *f;
1339 void *base;
1340 LPSTR ret = NULL;
1341 HANDLE hFile;
1342 HANDLE hMapping;
1343 OBJECT_ATTRIBUTES attr;
1344 LARGE_INTEGER lg_int;
1345 NTSTATUS nts;
1346 SIZE_T len;
1348 nt_regf *regf;
1349 nt_hbin *hbin;
1350 nt_hbin_sub *hbin_sub;
1351 nt_nk *nk;
1353 TRACE("%s\n", debugstr_w(fn));
1355 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1356 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1357 attr.Length = sizeof(attr);
1358 attr.RootDirectory = 0;
1359 attr.ObjectName = NULL;
1360 attr.Attributes = 0;
1361 attr.SecurityDescriptor = NULL;
1362 attr.SecurityQualityOfService = NULL;
1364 lg_int.QuadPart = 0;
1365 nts = NtCreateSection( &hMapping,
1366 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1367 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1368 if (nts != STATUS_SUCCESS) goto error1;
1370 base = NULL; len = 0;
1371 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1372 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1373 PAGE_READONLY);
1374 NtClose( hMapping );
1375 if (nts != STATUS_SUCCESS) goto error1;
1377 /* control signature */
1378 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1379 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1380 debugstr_w(fn));
1381 goto error;
1384 /* start block */
1385 regf = base;
1387 /* hbin block */
1388 hbin = (nt_hbin*)((char*) base + 0x1000);
1389 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1390 ERR( "hbin block invalid\n");
1391 goto error;
1394 /* hbin_sub block */
1395 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1396 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1397 ERR( "hbin_sub block invalid\n");
1398 goto error;
1401 /* nk block */
1402 nk = (nt_nk*)&(hbin_sub->data[0]);
1403 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1404 ERR( "special nk block not found\n");
1405 goto error;
1408 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1409 fprintf(f,"WINE REGISTRY Version 2");
1410 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1411 fclose(f);
1413 error:
1414 NtUnmapViewOfSection( GetCurrentProcess(), base );
1415 error1:
1416 NtClose(hFile);
1417 return ret;
1420 /* convert native registry to wine format and load it via server call [Internal] */
1421 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1423 LPSTR tmp = NULL;
1425 switch (reg_type) {
1426 case REG_WINNT:
1427 /* FIXME: following function doesn't really convert yet */
1428 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1429 break;
1430 case REG_WIN95:
1431 tmp = _convert_win95_registry_to_wine_format(fn,level);
1432 break;
1433 case REG_WIN31:
1434 ERR("Don't know how to convert native 3.1 registry yet.\n");
1435 break;
1436 default:
1437 ERR("Unknown registry format parameter (%d)\n",reg_type);
1438 break;
1441 if (tmp != NULL) {
1442 load_wine_registry(hkey,tmp);
1443 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1444 debugstr_w(fn), tmp);
1445 unlink(tmp);
1447 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1448 free(tmp);
1451 /* load all native windows registry files [Internal] */
1452 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1453 HKEY hkey_users_default )
1455 int reg_type;
1456 WCHAR windir[MAX_PATHNAME_LEN];
1457 WCHAR path[MAX_PATHNAME_LEN];
1458 OBJECT_ATTRIBUTES attr;
1459 UNICODE_STRING nameW;
1460 HKEY hkey;
1462 static const WCHAR WineW[] = {'W','i','n','e',0};
1463 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1464 static const WCHAR empty_strW[] = { 0 };
1465 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1466 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1467 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1468 'S','y','s','t','e','m','\\',
1469 'C','l','o','n','e',0};
1471 attr.Length = sizeof(attr);
1472 attr.RootDirectory = 0;
1473 attr.ObjectName = &nameW;
1474 attr.Attributes = 0;
1475 attr.SecurityDescriptor = NULL;
1476 attr.SecurityQualityOfService = NULL;
1478 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1480 reg_type = _get_reg_type();
1481 switch (reg_type) {
1482 case REG_WINNT: {
1483 HKEY hkey;
1484 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1485 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};
1486 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};
1487 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};
1488 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1489 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};
1491 /* user specific ntuser.dat */
1492 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1493 strcatW(path, ntuser_datW);
1494 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1496 else
1498 MESSAGE("When you are running with a native NT directory specify\n");
1499 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1500 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1501 break;
1504 /* default user.dat */
1505 if (hkey_users_default) {
1506 strcpyW(path, windir);
1507 strcatW(path, defaultW);
1508 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1512 * FIXME
1513 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1515 RtlInitUnicodeString( &nameW, System );
1516 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1518 strcpyW(path, windir);
1519 strcatW(path, systemW);
1520 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1521 NtClose( hkey );
1523 RtlInitUnicodeString( &nameW, Software );
1524 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1526 strcpyW(path, windir);
1527 strcatW(path, softwareW);
1528 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1529 NtClose( hkey );
1532 strcpyW(path, windir);
1533 strcatW(path, samW);
1534 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1536 strcpyW(path,windir);
1537 strcatW(path, securityW);
1538 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1540 /* this key is generated when the nt-core booted successfully */
1541 RtlInitUnicodeString( &nameW, Clone );
1542 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1543 break;
1546 case REG_WIN95:
1548 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1549 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1550 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1551 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1553 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1555 strcpyW(path, windir);
1556 strcatW(path, system_datW);
1557 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1559 RtlInitUnicodeString( &nameW, ClassesRootW );
1560 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1562 strcpyW(path, windir);
1563 strcatW(path, classes_datW);
1564 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1565 NtClose( hkey );
1568 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1569 /* user specific user.dat */
1570 strcatW(path, user_datW);
1571 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1573 /* default user.dat */
1574 if (hkey_users_default) {
1575 strcpyW(path, windir);
1576 strcatW(path, user_datW);
1577 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1579 } else {
1580 strcpyW(path, windir);
1581 strcatW(path, user_datW);
1582 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1584 break;
1587 case REG_WIN31:
1588 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1589 _w31_loadreg();
1590 break;
1592 case REG_DONTLOAD:
1593 TRACE("REG_DONTLOAD\n");
1594 break;
1596 default:
1597 ERR("switch: no match (%d)\n",reg_type);
1598 break;
1603 /* load home registry files (stored in ~/.wine) [Internal] */
1604 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1605 HKEY hkey_users_default )
1607 LPCSTR confdir = wine_get_config_dir();
1608 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1610 strcpy(tmp,confdir);
1611 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1612 load_wine_registry(hkey_users_default,tmp);
1614 strcpy(tmp,confdir);
1615 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1616 load_wine_registry(hkey_current_user,tmp);
1618 strcpy(tmp,confdir);
1619 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1620 load_wine_registry(hkey_local_machine,tmp);
1622 free(tmp);
1626 /* load all registry (native and global and home) */
1627 void SHELL_LoadRegistry( void )
1629 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1630 OBJECT_ATTRIBUTES attr;
1631 UNICODE_STRING nameW;
1632 DWORD count;
1633 BOOL res;
1634 int all, period;
1635 char tmp[1024];
1637 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1638 static const WCHAR UserW[] = {'U','s','e','r',0};
1639 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1640 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1641 'S','o','f','t','w','a','r','e','\\',
1642 'W','i','n','e','\\',
1643 'W','i','n','e','\\',
1644 'C','o','n','f','i','g','\\',
1645 'R','e','g','i','s','t','r','y',0};
1646 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};
1647 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};
1648 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};
1649 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1650 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1651 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};
1652 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1654 TRACE("(void)\n");
1656 if (!CLIENT_IsBootThread()) return; /* already loaded */
1658 attr.Length = sizeof(attr);
1659 attr.RootDirectory = 0;
1660 attr.ObjectName = &nameW;
1661 attr.Attributes = 0;
1662 attr.SecurityDescriptor = NULL;
1663 attr.SecurityQualityOfService = NULL;
1665 RtlInitUnicodeString( &nameW, MachineW );
1666 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1667 RtlInitUnicodeString( &nameW, UserW );
1668 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1670 attr.RootDirectory = hkey_users;
1671 RtlInitUnicodeString( &nameW, DefaultW );
1672 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1674 ERR("Cannot create HKEY_USERS/.Default\n" );
1675 ExitProcess(1);
1677 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1679 _set_registry_levels(0,0,0);
1680 _allocate_default_keys();
1682 attr.RootDirectory = 0;
1683 RtlInitUnicodeString( &nameW, RegistryW );
1684 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1686 /* load windows registry if required */
1688 res = TRUE;
1689 attr.RootDirectory = hkey_config;
1690 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1691 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1693 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1694 res = !IS_OPTION_FALSE(str[0]);
1696 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1698 /* load global registry if required */
1700 res = TRUE;
1701 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1702 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1704 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1705 res = !IS_OPTION_FALSE(str[0]);
1707 if (res)
1709 /* load global registry files (stored in /etc/wine) */
1710 char *p, configfile[MAX_PATHNAME_LEN];
1712 /* Override ETCDIR? */
1713 configfile[0] = 0;
1714 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1715 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1717 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1718 WideCharToMultiByte(CP_ACP, 0, str, -1, configfile, sizeof(configfile), NULL, NULL);
1720 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1722 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1724 /* Load the global HKU hive directly from sysconfdir */
1725 p = configfile + strlen(configfile);
1726 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1727 load_wine_registry( hkey_users, configfile );
1729 /* Load the global machine defaults directly from sysconfdir */
1730 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1731 load_wine_registry( hkey_local_machine, configfile );
1734 _set_registry_levels(1,0,0);
1736 /* load home registry if required */
1738 res = TRUE;
1739 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
1740 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1742 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1743 res = !IS_OPTION_FALSE(str[0]);
1745 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1747 /* setup registry saving */
1749 all = FALSE;
1750 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
1751 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1753 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1754 all = IS_OPTION_FALSE(str[0]);
1757 period = 0;
1758 RtlInitUnicodeString( &nameW, PeriodicSaveW );
1759 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1761 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1762 period = (int)strtolW(str, NULL, 10);
1765 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1766 _set_registry_levels(1,!all,period*1000);
1768 /* setup keys to save */
1770 res = TRUE;
1771 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
1772 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1774 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1775 res = !IS_OPTION_FALSE(str[0]);
1777 if (res)
1779 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1780 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1781 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1784 NtClose(hkey_users_default);
1785 NtClose(hkey_current_user);
1786 NtClose(hkey_users);
1787 NtClose(hkey_local_machine);
1788 NtClose(hkey_config);