- Reorganization and cleanup of selection code.
[wine/testsucceed.git] / misc / registry.c
blobd7e20639431424555793f5178f5bb4546f8df17e
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 "winerror.h"
54 #include "winnt.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 /* FIXME: following defines should be configured global */
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/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 /* _xmalloc [Internal] */
81 static void *_xmalloc( size_t size )
83 void *res;
85 res = malloc (size ? size : 1);
86 if (res == NULL) {
87 WARN("Virtual memory exhausted.\n");
88 exit (1);
90 return res;
93 /* _strdupnA [Internal] */
94 static LPSTR _strdupnA(LPCSTR str,size_t len)
96 LPSTR ret;
98 if (!str) return NULL;
99 ret = _xmalloc( len + 1 );
100 memcpy( ret, str, len );
101 ret[len] = 0x00;
102 return ret;
105 /* convert ansi string to unicode [Internal] */
106 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
108 LPWSTR ret;
109 size_t lenW;
111 if (!strA) return NULL;
112 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
113 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
114 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
115 ret[lenW] = 0;
116 return ret;
119 /* dump a Unicode string with proper escaping [Internal] */
120 /* FIXME: this code duplicates server/unicode.c */
121 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
123 static const char escapes[32] = ".......abtnvfr.............e....";
124 char buffer[256];
125 LPSTR pos = buffer;
126 int count = 0;
128 for (; len; str++, len--)
130 if (pos > buffer + sizeof(buffer) - 8)
132 fwrite( buffer, pos - buffer, 1, f );
133 count += pos - buffer;
134 pos = buffer;
136 if (*str > 127) /* hex escape */
138 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
139 pos += sprintf( pos, "\\x%04x", *str );
140 else
141 pos += sprintf( pos, "\\x%x", *str );
142 continue;
144 if (*str < 32) /* octal or C escape */
146 if (!*str && len == 1) continue; /* do not output terminating NULL */
147 if (escapes[*str] != '.')
148 pos += sprintf( pos, "\\%c", escapes[*str] );
149 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
150 pos += sprintf( pos, "\\%03o", *str );
151 else
152 pos += sprintf( pos, "\\%o", *str );
153 continue;
155 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
156 *pos++ = *str;
158 fwrite( buffer, pos - buffer, 1, f );
159 count += pos - buffer;
160 return count;
163 /* convert ansi string to unicode and dump with proper escaping [Internal] */
164 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
166 WCHAR *strW;
167 int ret;
169 if (strA == NULL) return 0;
170 strW = _strdupnAtoW(strA,len);
171 ret = _dump_strW(strW,len,f,escape);
172 free(strW);
173 return ret;
176 /* a key value */
177 /* FIXME: this code duplicates server/registry.c */
178 struct key_value {
179 WCHAR *nameW; /* value name */
180 int type; /* value type */
181 size_t len; /* value data length in bytes */
182 void *data; /* pointer to value data */
185 /* dump a value to a text file */
186 /* FIXME: this code duplicates server/registry.c */
187 static void _dump_value(struct key_value *value,FILE *f)
189 int i, count;
191 if (value->nameW[0]) {
192 fputc( '\"', f );
193 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
194 count += fprintf( f, "\"=" );
196 else count = fprintf( f, "@=" );
198 switch(value->type) {
199 case REG_SZ:
200 case REG_EXPAND_SZ:
201 case REG_MULTI_SZ:
202 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
203 fputc( '\"', f );
204 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
205 fputc( '\"', f );
206 break;
207 case REG_DWORD:
208 if (value->len == sizeof(DWORD)) {
209 DWORD dw;
210 memcpy( &dw, value->data, sizeof(DWORD) );
211 fprintf( f, "dword:%08lx", dw );
212 break;
214 /* else fall through */
215 default:
216 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
217 else count += fprintf( f, "hex(%x):", value->type );
218 for (i = 0; i < value->len; i++) {
219 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
220 if (i < value->len-1) {
221 fputc( ',', f );
222 if (++count > 76) {
223 fprintf( f, "\\\n " );
224 count = 2;
228 break;
230 fputc( '\n', f );
233 /******************************************************************/
234 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
236 reghack - windows 3.11 registry data format demo program.
238 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
239 a combined hash table and tree description, and finally a text table.
241 The header is obvious from the struct header. The taboff1 and taboff2
242 fields are always 0x20, and their usage is unknown.
244 The 8-byte entry table has various entry types.
246 tabent[0] is a root index. The second word has the index of the root of
247 the directory.
248 tabent[1..hashsize] is a hash table. The first word in the hash entry is
249 the index of the key/value that has that hash. Data with the same
250 hash value are on a circular list. The other three words in the
251 hash entry are always zero.
252 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
253 entry: dirent and keyent/valent. They are identified by context.
254 tabent[freeidx] is the first free entry. The first word in a free entry
255 is the index of the next free entry. The last has 0 as a link.
256 The other three words in the free list are probably irrelevant.
258 Entries in text table are preceded by a word at offset-2. This word
259 has the value (2*index)+1, where index is the referring keyent/valent
260 entry in the table. I have no suggestion for the 2* and the +1.
261 Following the word, there are N bytes of data, as per the keyent/valent
262 entry length. The offset of the keyent/valent entry is from the start
263 of the text table to the first data byte.
265 This information is not available from Microsoft. The data format is
266 deduced from the reg.dat file by me. Mistakes may
267 have been made. I claim no rights and give no guarantees for this program.
269 Tor Sjøwall, tor@sn.no
272 /* reg.dat header format */
273 struct _w31_header {
274 char cookie[8]; /* 'SHCC3.10' */
275 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
276 unsigned long taboff2; /* offset of index table (??) = 0x20 */
277 unsigned long tabcnt; /* number of entries in index table */
278 unsigned long textoff; /* offset of text part */
279 unsigned long textsize; /* byte size of text part */
280 unsigned short hashsize; /* hash size */
281 unsigned short freeidx; /* free index */
284 /* generic format of table entries */
285 struct _w31_tabent {
286 unsigned short w0, w1, w2, w3;
289 /* directory tabent: */
290 struct _w31_dirent {
291 unsigned short sibling_idx; /* table index of sibling dirent */
292 unsigned short child_idx; /* table index of child dirent */
293 unsigned short key_idx; /* table index of key keyent */
294 unsigned short value_idx; /* table index of value valent */
297 /* key tabent: */
298 struct _w31_keyent {
299 unsigned short hash_idx; /* hash chain index for string */
300 unsigned short refcnt; /* reference count */
301 unsigned short length; /* length of string */
302 unsigned short string_off; /* offset of string in text table */
305 /* value tabent: */
306 struct _w31_valent {
307 unsigned short hash_idx; /* hash chain index for string */
308 unsigned short refcnt; /* reference count */
309 unsigned short length; /* length of string */
310 unsigned short string_off; /* offset of string in text table */
313 /* recursive helper function to display a directory tree [Internal] */
314 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
316 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
317 struct _w31_dirent *dir;
318 struct _w31_keyent *key;
319 struct _w31_valent *val;
320 HKEY subkey = 0;
321 OBJECT_ATTRIBUTES attr;
322 UNICODE_STRING nameW, valueW;
323 static WCHAR tail[400];
325 attr.Length = sizeof(attr);
326 attr.RootDirectory = hkey;
327 attr.ObjectName = &nameW;
328 attr.Attributes = 0;
329 attr.SecurityDescriptor = NULL;
330 attr.SecurityQualityOfService = NULL;
331 RtlInitUnicodeString( &valueW, NULL );
333 while (idx!=0) {
334 dir=(struct _w31_dirent*)&tab[idx];
336 if (dir->key_idx) {
337 DWORD len;
338 key = (struct _w31_keyent*)&tab[dir->key_idx];
340 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
341 &txt[key->string_off], key->length);
342 tail[len/sizeof(WCHAR)] = 0;
344 /* all toplevel entries AND the entries in the
345 * toplevel subdirectory belong to \SOFTWARE\Classes
347 if (!level && !strcmpW(tail,classesW))
349 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
350 idx=dir->sibling_idx;
351 continue;
354 if (subkey) NtClose( subkey );
355 RtlInitUnicodeString( &nameW, tail );
356 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
358 /* only add if leaf node or valued node */
359 if (dir->value_idx!=0||dir->child_idx==0) {
360 if (dir->value_idx) {
361 DWORD len;
362 val=(struct _w31_valent*)&tab[dir->value_idx];
363 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
364 &txt[val->string_off], val->length);
365 tail[len/sizeof(WCHAR)] = 0;
366 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
369 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
370 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
371 idx=dir->sibling_idx;
373 if (subkey) NtClose( subkey );
377 /******************************************************************************
378 * _w31_loadreg [Internal]
380 void _w31_loadreg(void)
382 HFILE hf;
383 HKEY root;
384 OBJECT_ATTRIBUTES attr;
385 UNICODE_STRING nameW;
386 struct _w31_header head;
387 struct _w31_tabent *tab;
388 unsigned char *txt;
389 unsigned int len;
390 OFSTRUCT ofs;
391 BY_HANDLE_FILE_INFORMATION hfinfo;
392 time_t lastmodified;
394 TRACE("(void)\n");
396 hf = OpenFile("reg.dat",&ofs,OF_READ);
397 if (hf==HFILE_ERROR) return;
399 /* read & dump header */
400 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
401 ERR("reg.dat is too short.\n");
402 _lclose(hf);
403 return;
405 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
406 ERR("reg.dat has bad signature.\n");
407 _lclose(hf);
408 return;
411 len = head.tabcnt * sizeof(struct _w31_tabent);
412 /* read and dump index table */
413 tab = _xmalloc(len);
414 if (len!=_lread(hf,tab,len)) {
415 ERR("couldn't read %d bytes.\n",len);
416 free(tab);
417 _lclose(hf);
418 return;
421 /* read text */
422 txt = _xmalloc(head.textsize);
423 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
424 ERR("couldn't seek to textblock.\n");
425 free(tab);
426 free(txt);
427 _lclose(hf);
428 return;
430 if (head.textsize!=_lread(hf,txt,head.textsize)) {
431 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
432 free(tab);
433 free(txt);
434 _lclose(hf);
435 return;
438 if (!GetFileInformationByHandle(hf,&hfinfo)) {
439 ERR("GetFileInformationByHandle failed?.\n");
440 free(tab);
441 free(txt);
442 _lclose(hf);
443 return;
445 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
447 attr.Length = sizeof(attr);
448 attr.RootDirectory = 0;
449 attr.ObjectName = &nameW;
450 attr.Attributes = 0;
451 attr.SecurityDescriptor = NULL;
452 attr.SecurityQualityOfService = NULL;
453 RtlInitUnicodeString( &nameW, ClassesRootW );
455 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
457 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
458 NtClose( root );
460 free(tab);
461 free(txt);
462 _lclose(hf);
463 return;
466 /***********************************************************************************/
467 /* windows 95 registry loader */
468 /***********************************************************************************/
470 /* SECTION 1: main header
472 * once at offset 0
474 #define W95_REG_CREG_ID 0x47455243
476 typedef struct {
477 DWORD id; /* "CREG" = W95_REG_CREG_ID */
478 DWORD version; /* ???? 0x00010000 */
479 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
480 DWORD uk2; /* 0x0c */
481 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
482 WORD uk3;
483 DWORD uk[3];
484 /* rgkn */
485 } _w95creg;
487 /* SECTION 2: Directory information (tree structure)
489 * once on offset 0x20
491 * structure: [rgkn][dke]* (repeat till last_dke is reached)
493 #define W95_REG_RGKN_ID 0x4e4b4752
495 typedef struct {
496 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
497 DWORD size; /* Size of the RGKN-block */
498 DWORD root_off; /* Rel. Offset of the root-record */
499 DWORD last_dke; /* Offset to last DKE ? */
500 DWORD uk[4];
501 } _w95rgkn;
503 /* Disk Key Entry Structure
505 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
506 * hive itself. It looks the same like other keys. Even the ID-number can
507 * be any value.
509 * The "hash"-value is a value representing the key's name. Windows will not
510 * search for the name, but for a matching hash-value. if it finds one, it
511 * will compare the actual string info, otherwise continue with the next key.
512 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
513 * of the string which are smaller than 0x80 (128) to this D-Word.
515 * If you want to modify key names, also modify the hash-values, since they
516 * cannot be found again (although they would be displayed in REGEDIT)
517 * End of list-pointers are filled with 0xFFFFFFFF
519 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
520 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
521 * structure) and reading another RGDB_section.
523 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
524 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
525 * The remaining space between last_dke and the offset calculated from
526 * rgkn->size seems to be free for use for more dke:s.
527 * So it seems if more dke:s are added, they are added to that space and
528 * last_dke is grown, and in case that "free" space is out, the space
529 * gets grown and rgkn->size gets adjusted.
531 * there is a one to one relationship between dke and dkh
533 /* key struct, once per key */
534 typedef struct {
535 DWORD x1; /* Free entry indicator(?) */
536 DWORD hash; /* sum of bytes of keyname */
537 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
538 DWORD prevlvl; /* offset of previous key */
539 DWORD nextsub; /* offset of child key */
540 DWORD next; /* offset of sibling key */
541 WORD nrLS; /* id inside the rgdb block */
542 WORD nrMS; /* number of the rgdb block */
543 } _w95dke;
545 /* SECTION 3: key information, values and data
547 * structure:
548 * section: [blocks]* (repeat creg->rgdb_num times)
549 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
550 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
552 * An interesting relationship exists in RGDB_section. The DWORD value
553 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
554 * I have no idea at the moment what this means. (Kevin Cozens)
557 /* block header, once per block */
558 #define W95_REG_RGDB_ID 0x42444752
560 typedef struct {
561 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
562 DWORD size; /* 0x04 */
563 DWORD uk1; /* 0x08 */
564 DWORD uk2; /* 0x0c */
565 DWORD uk3; /* 0x10 */
566 DWORD uk4; /* 0x14 */
567 DWORD uk5; /* 0x18 */
568 DWORD uk6; /* 0x1c */
569 /* dkh */
570 } _w95rgdb;
572 /* Disk Key Header structure (RGDB part), once per key */
573 typedef struct {
574 DWORD nextkeyoff; /* 0x00 offset to next dkh */
575 WORD nrLS; /* 0x04 id inside the rgdb block */
576 WORD nrMS; /* 0x06 number of the rgdb block */
577 DWORD bytesused; /* 0x08 */
578 WORD keynamelen; /* 0x0c len of name */
579 WORD values; /* 0x0e number of values */
580 DWORD xx1; /* 0x10 */
581 char name[1]; /* 0x14 */
582 /* dkv */ /* 0x14 + keynamelen */
583 } _w95dkh;
585 /* Disk Key Value structure, once per value */
586 typedef struct {
587 DWORD type; /* 0x00 */
588 DWORD x1; /* 0x04 */
589 WORD valnamelen; /* 0x08 length of name, 0 is default key */
590 WORD valdatalen; /* 0x0A length of data */
591 char name[1]; /* 0x0c */
592 /* raw data */ /* 0x0c + valnamelen */
593 } _w95dkv;
595 /******************************************************************************
596 * _w95_lookup_dkh [Internal]
598 * seeks the dkh belonging to a dke
600 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
602 _w95rgdb * rgdb;
603 _w95dkh * dkh;
604 int i;
606 /* get the beginning of the rgdb datastore */
607 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
609 /* check: requested block < last_block) */
610 if (creg->rgdb_num <= nrMS) {
611 ERR("registry file corrupt! requested block no. beyond end.\n");
612 goto error;
615 /* find the right block */
616 for(i=0; i<nrMS ;i++) {
617 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
618 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
619 goto error;
621 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
624 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
626 do {
627 if(nrLS==dkh->nrLS ) return dkh;
628 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
629 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
631 error:
632 return NULL;
635 /******************************************************************************
636 * _w95_dump_dkv [Internal]
638 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
640 _w95dkv * dkv;
641 int i;
643 /* first value block */
644 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
646 /* loop through the values */
647 for (i=0; i< dkh->values; i++) {
648 struct key_value value;
649 WCHAR *pdata;
651 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
652 value.type = dkv->type;
653 value.len = dkv->valdatalen;
655 value.data = &(dkv->name[dkv->valnamelen]);
656 pdata = NULL;
657 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
658 pdata = _strdupnAtoW(value.data,value.len);
659 value.len *= 2;
661 if (pdata != NULL) value.data = pdata;
663 _dump_value(&value,f);
664 free(value.nameW);
665 if (pdata != NULL) free(pdata);
667 /* next value */
668 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
670 return TRUE;
673 /******************************************************************************
674 * _w95_dump_dke [Internal]
676 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
678 _w95dkh * dkh;
679 LPSTR new_key_name = NULL;
681 /* special root key */
682 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
684 /* parse the one subkey */
685 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
686 /* has no sibling keys */
687 return FALSE;
690 /* search subblock */
691 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
692 ERR("dke pointing to missing dkh !\n");
693 return FALSE;
696 if (level <= 0) {
697 /* create new subkey name */
698 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
699 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
700 strncat(new_key_name,dkh->name,dkh->keynamelen);
702 /* walk sibling keys */
703 if (dke->next != 0xffffffff ) {
704 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
705 free(new_key_name);
706 return FALSE;
710 /* write the key path (something like [Software\\Microsoft\\..]) only if:
711 1) key has some values
712 2) key has no values and no subkeys
714 if (dkh->values > 0) {
715 /* there are some values */
716 fprintf(f,"\n[");
717 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
718 fprintf(f,"]\n");
719 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
720 free(new_key_name);
721 return FALSE;
724 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
725 /* no subkeys and no values */
726 fprintf(f,"\n[");
727 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
728 fprintf(f,"]\n");
730 } else new_key_name = _strdupnA(key_name,strlen(key_name));
732 /* next sub key */
733 if (dke->nextsub != 0xffffffff) {
734 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
735 free(new_key_name);
736 return FALSE;
740 free(new_key_name);
741 return TRUE;
743 /* end windows 95 loader */
745 /***********************************************************************************/
746 /* windows NT registry loader */
747 /***********************************************************************************/
749 /* NT REGISTRY LOADER */
751 #ifdef HAVE_SYS_MMAN_H
752 # include <sys/mman.h>
753 #endif
755 #ifndef MAP_FAILED
756 #define MAP_FAILED ((LPVOID)-1)
757 #endif
759 #define NT_REG_BLOCK_SIZE 0x1000
761 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
762 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
763 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
764 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
766 /* subblocks of nk */
767 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
768 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
769 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
771 #define NT_REG_KEY_BLOCK_TYPE 0x20
772 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
774 typedef struct {
775 DWORD id; /* 0x66676572 'regf'*/
776 DWORD uk1; /* 0x04 */
777 DWORD uk2; /* 0x08 */
778 FILETIME DateModified; /* 0x0c */
779 DWORD uk3; /* 0x14 */
780 DWORD uk4; /* 0x18 */
781 DWORD uk5; /* 0x1c */
782 DWORD uk6; /* 0x20 */
783 DWORD RootKeyBlock; /* 0x24 */
784 DWORD BlockSize; /* 0x28 */
785 DWORD uk7[116];
786 DWORD Checksum; /* at offset 0x1FC */
787 } nt_regf;
789 typedef struct {
790 DWORD blocksize;
791 BYTE data[1];
792 } nt_hbin_sub;
794 typedef struct {
795 DWORD id; /* 0x6E696268 'hbin' */
796 DWORD off_prev;
797 DWORD off_next;
798 DWORD uk1;
799 DWORD uk2; /* 0x10 */
800 DWORD uk3; /* 0x14 */
801 DWORD uk4; /* 0x18 */
802 DWORD size; /* 0x1C */
803 nt_hbin_sub hbin_sub; /* 0x20 */
804 } nt_hbin;
807 * the value_list consists of offsets to the values (vk)
809 typedef struct {
810 WORD SubBlockId; /* 0x00 0x6B6E */
811 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
812 FILETIME writetime; /* 0x04 */
813 DWORD uk1; /* 0x0C */
814 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
815 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
816 DWORD uk8; /* 0x18 */
817 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
818 DWORD uk2; /* 0x20 */
819 DWORD nr_values; /* 0x24 number of values */
820 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
821 DWORD off_sk; /* 0x2c Offset of the sk-Record */
822 DWORD off_class; /* 0x30 Offset of the Class-Name */
823 DWORD uk3; /* 0x34 */
824 DWORD uk4; /* 0x38 */
825 DWORD uk5; /* 0x3c */
826 DWORD uk6; /* 0x40 */
827 DWORD uk7; /* 0x44 */
828 WORD name_len; /* 0x48 name-length */
829 WORD class_len; /* 0x4a class-name length */
830 char name[1]; /* 0x4c key-name */
831 } nt_nk;
833 typedef struct {
834 DWORD off_nk; /* 0x00 */
835 DWORD name; /* 0x04 */
836 } hash_rec;
838 typedef struct {
839 WORD id; /* 0x00 0x666c */
840 WORD nr_keys; /* 0x06 */
841 hash_rec hash_rec[1];
842 } nt_lf;
845 list of subkeys without hash
847 li --+-->nk
849 +-->nk
851 typedef struct {
852 WORD id; /* 0x00 0x696c */
853 WORD nr_keys;
854 DWORD off_nk[1];
855 } nt_li;
858 this is a intermediate node
860 ri --+-->li--+-->nk
862 | +-->nk
864 +-->li--+-->nk
866 +-->nk
868 typedef struct {
869 WORD id; /* 0x00 0x6972 */
870 WORD nr_li; /* 0x02 number off offsets */
871 DWORD off_li[1]; /* 0x04 points to li */
872 } nt_ri;
874 typedef struct {
875 WORD id; /* 0x00 'vk' */
876 WORD nam_len;
877 DWORD data_len;
878 DWORD data_off;
879 DWORD type;
880 WORD flag;
881 WORD uk1;
882 char name[1];
883 } nt_vk;
886 * gets a value
888 * vk->flag:
889 * 0 value is a default value
890 * 1 the value has a name
892 * vk->data_len
893 * len of the whole data block
894 * - reg_sz (unicode)
895 * bytes including the terminating \0 = 2*(number_of_chars+1)
896 * - reg_dword, reg_binary:
897 * if highest bit of data_len is set data_off contains the value
899 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
901 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
902 struct key_value value;
904 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
905 ERR("unknown block found (0x%04x), please report!\n", vk->id);
906 return FALSE;
909 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
910 value.type = vk->type;
911 value.len = (vk->data_len & 0x7fffffff);
912 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
914 _dump_value(&value,f);
915 free(value.nameW);
917 return TRUE;
920 /* it's called from _nt_dump_lf() */
921 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
924 * get the subkeys
926 * this structure contains the hash of a keyname and points to all
927 * subkeys
929 * exception: if the id is 'il' there are no hash values and every
930 * dword is a offset
932 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
934 int i;
936 if (lf->id == NT_REG_HASH_BLOCK_ID) {
937 if (subkeys != lf->nr_keys) goto error1;
939 for (i=0; i<lf->nr_keys; i++)
940 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
941 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
942 nt_li * li = (nt_li*)lf;
943 if (subkeys != li->nr_keys) goto error1;
945 for (i=0; i<li->nr_keys; i++)
946 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
947 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
948 nt_ri * ri = (nt_ri*)lf;
949 int li_subkeys = 0;
951 /* count all subkeys */
952 for (i=0; i<ri->nr_li; i++) {
953 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
954 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
955 li_subkeys += li->nr_keys;
958 /* check number */
959 if (subkeys != li_subkeys) goto error1;
961 /* loop through the keys */
962 for (i=0; i<ri->nr_li; i++) {
963 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
964 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
966 } else goto error2;
968 return TRUE;
970 error2:
971 if (lf->id == 0x686c)
972 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
973 else
974 ERR("unknown node id 0x%04x, please report!\n", lf->id);
975 return TRUE;
977 error1:
978 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
979 return FALSE;
981 error:
982 ERR("error reading lf block\n");
983 return FALSE;
986 /* _nt_dump_nk [Internal] */
987 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
989 unsigned int n;
990 DWORD *vl;
991 LPSTR new_key_name = NULL;
993 TRACE("%s\n", key_name);
995 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
996 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
997 return FALSE;
1000 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1001 ERR("registry file corrupt!\n");
1002 return FALSE;
1005 /* create the new key */
1006 if (level <= 0) {
1007 /* create new subkey name */
1008 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
1009 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
1010 strncat(new_key_name,nk->name,nk->name_len);
1012 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1013 1) key has some values
1014 2) key has no values and no subkeys
1016 if (nk->nr_values > 0) {
1017 /* there are some values */
1018 fprintf(f,"\n[");
1019 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1020 fprintf(f,"]\n");
1022 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1023 /* no subkeys and no values */
1024 fprintf(f,"\n[");
1025 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1026 fprintf(f,"]\n");
1029 /* loop trough the value list */
1030 vl = (DWORD *)(base+nk->valuelist_off+4);
1031 for (n=0; n<nk->nr_values; n++) {
1032 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1033 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1034 free(new_key_name);
1035 return FALSE;
1038 } else new_key_name = _strdupnA(key_name,strlen(key_name));
1040 /* loop through the subkeys */
1041 if (nk->nr_subkeys) {
1042 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1043 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1044 free(new_key_name);
1045 return FALSE;
1049 free(new_key_name);
1050 return TRUE;
1053 /* end nt loader */
1055 /**********************************************************************************
1056 * _set_registry_levels [Internal]
1058 * set level to 0 for loading system files
1059 * set level to 1 for loading user files
1061 static void _set_registry_levels(int level,int saving,int period)
1063 SERVER_START_REQ( set_registry_levels )
1065 req->current = level;
1066 req->saving = saving;
1067 req->period = period;
1068 wine_server_call( req );
1070 SERVER_END_REQ;
1073 /* _save_at_exit [Internal] */
1074 static void _save_at_exit(HKEY hkey,LPCSTR path)
1076 LPCSTR confdir = wine_get_config_dir();
1078 SERVER_START_REQ( save_registry_atexit )
1080 req->hkey = hkey;
1081 wine_server_add_data( req, confdir, strlen(confdir) );
1082 wine_server_add_data( req, path, strlen(path)+1 );
1083 wine_server_call( req );
1085 SERVER_END_REQ;
1088 /* configure save files and start the periodic saving timer [Internal] */
1089 static void _init_registry_saving( HKEY hkey_local_machine, HKEY hkey_current_user,
1090 HKEY hkey_users_default )
1092 int all;
1093 int period = 0;
1094 WCHAR buffer[20];
1095 static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0};
1096 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1097 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1098 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};
1099 static const WCHAR empty_strW[] = { 0 };
1101 all = !PROFILE_GetWineIniBool(registryW, SaveOnlyUpdatedKeysW, 1);
1102 PROFILE_GetWineIniString( registryW, PeriodicSaveW, empty_strW, buffer, 20 );
1103 if (buffer[0]) period = (int)strtolW(buffer, NULL, 10);
1105 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1106 _set_registry_levels(1,!all,period*1000);
1108 if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1))
1110 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1111 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1112 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1117 /******************************************************************************
1118 * _allocate_default_keys [Internal]
1119 * Registry initialisation, allocates some default keys.
1121 static void _allocate_default_keys(void)
1123 HKEY hkey;
1124 OBJECT_ATTRIBUTES attr;
1125 UNICODE_STRING nameW, valueW;
1126 WCHAR computer_name[200];
1127 DWORD size = sizeof(computer_name)/sizeof(WCHAR);
1129 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1130 'P','e','r','f','S','t','a','t','s','\\',
1131 'S','t','a','t','D','a','t','a',0};
1132 static const WCHAR ComputerW[] = {'M','a','c','h','i','n','e','\\',
1133 'S','y','s','t','e','m','\\',
1134 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1135 'C','o','n','t','r','o','l','\\',
1136 'C','o','m','p','u','t','e','r','N','a','m','e','\\',
1137 'C','o','m','p','u','t','e','r','N','a','m','e',0};
1138 static const WCHAR ComputerNameW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
1140 TRACE("(void)\n");
1142 attr.Length = sizeof(attr);
1143 attr.RootDirectory = 0;
1144 attr.ObjectName = &nameW;
1145 attr.Attributes = 0;
1146 attr.SecurityDescriptor = NULL;
1147 attr.SecurityQualityOfService = NULL;
1149 RtlInitUnicodeString( &nameW, StatDataW );
1150 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1152 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1153 * CurrentVersion
1154 * CurrentBuildNumber
1155 * CurrentType
1156 * string RegisteredOwner
1157 * string RegisteredOrganization
1160 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1161 * string SysContact
1162 * string SysLocation
1163 * SysServices
1165 if (GetComputerNameW( computer_name, &size ))
1167 RtlInitUnicodeString( &nameW, ComputerW );
1168 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1170 RtlInitUnicodeString( &valueW, ComputerNameW );
1171 NtSetValueKey( hkey, &valueW, 0, REG_SZ, computer_name,
1172 (strlenW(computer_name) + 1) * sizeof(WCHAR) );
1173 NtClose(hkey);
1178 #define REG_DONTLOAD -1
1179 #define REG_WIN31 0
1180 #define REG_WIN95 1
1181 #define REG_WINNT 2
1183 /* return the type of native registry [Internal] */
1184 static int _get_reg_type(void)
1186 WCHAR windir[MAX_PATHNAME_LEN];
1187 WCHAR tmp[MAX_PATHNAME_LEN];
1188 int ret = REG_WIN31;
1189 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};
1190 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1191 static const WCHAR WineW[] = {'W','i','n','e',0};
1192 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1193 static const WCHAR empty_strW[] = { 0 };
1195 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1197 /* test %windir%/system32/config/system --> winnt */
1198 strcpyW(tmp, windir);
1199 strcatW(tmp, nt_reg_pathW);
1200 if(GetFileAttributesW(tmp) != (DWORD)-1)
1201 ret = REG_WINNT;
1202 else
1204 /* test %windir%/system.dat --> win95 */
1205 strcpyW(tmp, windir);
1206 strcatW(tmp, win9x_reg_pathW);
1207 if(GetFileAttributesW(tmp) != (DWORD)-1)
1208 ret = REG_WIN95;
1211 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, tmp, MAX_PATHNAME_LEN )))
1213 MESSAGE("When you are running with a native NT directory specify\n");
1214 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1215 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1216 ret = REG_DONTLOAD;
1219 return ret;
1222 #define WINE_REG_VER_ERROR -1
1223 #define WINE_REG_VER_1 0
1224 #define WINE_REG_VER_2 1
1225 #define WINE_REG_VER_OLD 2
1226 #define WINE_REG_VER_UNKNOWN 3
1228 /* return the version of wine registry file [Internal] */
1229 static int _get_wine_registry_file_format_version(LPCSTR fn)
1231 FILE *f;
1232 char tmp[50];
1233 int ver;
1235 if ((f=fopen(fn,"rt")) == NULL) {
1236 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1237 return WINE_REG_VER_ERROR;
1240 if (fgets(tmp,50,f) == NULL) {
1241 WARN("Error reading %s: %s\n",fn,strerror(errno));
1242 fclose(f);
1243 return WINE_REG_VER_ERROR;
1245 fclose(f);
1247 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1248 switch (ver) {
1249 case 1:
1250 return WINE_REG_VER_1;
1251 break;
1252 case 2:
1253 return WINE_REG_VER_2;
1254 break;
1255 default:
1256 return WINE_REG_VER_UNKNOWN;
1260 /* load the registry file in wine format [Internal] */
1261 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1263 int file_format;
1265 file_format = _get_wine_registry_file_format_version(fn);
1266 switch (file_format) {
1268 case WINE_REG_VER_1:
1269 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1270 break;
1272 case WINE_REG_VER_2: {
1273 HANDLE file;
1274 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1275 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1277 SERVER_START_REQ( load_registry )
1279 req->hkey = hkey;
1280 req->file = file;
1281 wine_server_call( req );
1283 SERVER_END_REQ;
1284 CloseHandle( file );
1286 break;
1289 case WINE_REG_VER_UNKNOWN:
1290 WARN("Unable to load registry file %s: unknown format.\n",fn);
1291 break;
1293 case WINE_REG_VER_ERROR:
1294 break;
1298 /* generate and return the name of the tmp file and associated stream [Internal] */
1299 static LPSTR _get_tmp_fn(FILE **f)
1301 LPSTR ret;
1302 int tmp_fd,count;
1304 ret = _xmalloc(50);
1305 for (count = 0;;) {
1306 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1307 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1308 if (errno != EEXIST) {
1309 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1310 free(ret);
1311 *f = NULL;
1312 return NULL;
1316 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1317 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1318 close(tmp_fd);
1319 free(ret);
1320 return NULL;
1323 return ret;
1326 /* convert win95 native registry file to wine format [Internal] */
1327 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1329 int fd;
1330 FILE *f;
1331 DOS_FULL_NAME full_name;
1332 void *base;
1333 LPSTR ret = NULL;
1334 struct stat st;
1336 _w95creg *creg;
1337 _w95rgkn *rgkn;
1338 _w95dke *dke, *root_dke;
1340 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1342 /* map the registry into the memory */
1343 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1344 if ((fstat(fd, &st) == -1)) goto error1;
1345 if (!st.st_size) goto error1;
1346 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1348 /* control signature */
1349 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1350 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1351 debugstr_w(fn));
1352 goto error;
1355 creg = base;
1356 /* load the header (rgkn) */
1357 rgkn = (_w95rgkn*)(creg + 1);
1358 if (rgkn->id != W95_REG_RGKN_ID) {
1359 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1360 goto error;
1362 if (rgkn->root_off != 0x20) {
1363 ERR("rgkn->root_off not 0x20, please report !\n");
1364 goto error;
1366 if (rgkn->last_dke > rgkn->size)
1368 ERR("registry file corrupt! last_dke > size!\n");
1369 goto error;
1371 /* verify last dke */
1372 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1373 if (dke->x1 != 0x80000000)
1374 { /* wrong magic */
1375 ERR("last dke invalid !\n");
1376 goto error;
1378 if (rgkn->size > creg->rgdb_off)
1380 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1381 goto error;
1383 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1384 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1386 ERR("registry file corrupt! invalid root dke !\n");
1387 goto error;
1390 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1391 fprintf(f,"WINE REGISTRY Version 2");
1392 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1393 fclose(f);
1395 error:
1396 if(ret == NULL) {
1397 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1398 ERR("Please report this.\n");
1399 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1402 munmap(base, st.st_size);
1403 error1:
1404 close(fd);
1405 return ret;
1408 /* convert winnt native registry file to wine format [Internal] */
1409 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1411 FILE *f;
1412 void *base;
1413 LPSTR ret = NULL;
1414 HANDLE hFile;
1415 HANDLE hMapping;
1417 nt_regf *regf;
1418 nt_hbin *hbin;
1419 nt_hbin_sub *hbin_sub;
1420 nt_nk *nk;
1422 TRACE("%s\n", debugstr_w(fn));
1424 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1425 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1426 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1427 if (!hMapping) goto error1;
1428 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1429 CloseHandle( hMapping );
1430 if (!base) goto error1;
1432 /* control signature */
1433 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1434 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1435 debugstr_w(fn));
1436 goto error;
1439 /* start block */
1440 regf = base;
1442 /* hbin block */
1443 hbin = (nt_hbin*)((char*) base + 0x1000);
1444 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1445 ERR( "hbin block invalid\n");
1446 goto error;
1449 /* hbin_sub block */
1450 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1451 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1452 ERR( "hbin_sub block invalid\n");
1453 goto error;
1456 /* nk block */
1457 nk = (nt_nk*)&(hbin_sub->data[0]);
1458 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1459 ERR( "special nk block not found\n");
1460 goto error;
1463 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1464 fprintf(f,"WINE REGISTRY Version 2");
1465 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1466 fclose(f);
1468 error:
1469 UnmapViewOfFile( base );
1470 error1:
1471 CloseHandle(hFile);
1472 return ret;
1475 /* convert native registry to wine format and load it via server call [Internal] */
1476 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1478 LPSTR tmp = NULL;
1480 switch (reg_type) {
1481 case REG_WINNT:
1482 /* FIXME: following function doesn't really convert yet */
1483 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1484 break;
1485 case REG_WIN95:
1486 tmp = _convert_win95_registry_to_wine_format(fn,level);
1487 break;
1488 case REG_WIN31:
1489 ERR("Don't know how to convert native 3.1 registry yet.\n");
1490 break;
1491 default:
1492 ERR("Unknown registry format parameter (%d)\n",reg_type);
1493 break;
1496 if (tmp != NULL) {
1497 load_wine_registry(hkey,tmp);
1498 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1499 debugstr_w(fn), tmp);
1500 unlink(tmp);
1502 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1503 free(tmp);
1506 /* load all native windows registry files [Internal] */
1507 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1508 HKEY hkey_users_default )
1510 int reg_type;
1511 WCHAR windir[MAX_PATHNAME_LEN];
1512 WCHAR path[MAX_PATHNAME_LEN];
1513 OBJECT_ATTRIBUTES attr;
1514 UNICODE_STRING nameW;
1515 HKEY hkey;
1517 static const WCHAR WineW[] = {'W','i','n','e',0};
1518 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1519 static const WCHAR empty_strW[] = { 0 };
1520 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1521 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1522 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1523 'S','y','s','t','e','m','\\',
1524 'C','l','o','n','e',0};
1526 attr.Length = sizeof(attr);
1527 attr.RootDirectory = 0;
1528 attr.ObjectName = &nameW;
1529 attr.Attributes = 0;
1530 attr.SecurityDescriptor = NULL;
1531 attr.SecurityQualityOfService = NULL;
1533 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1535 reg_type = _get_reg_type();
1536 switch (reg_type) {
1537 case REG_WINNT: {
1538 HKEY hkey;
1539 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1540 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};
1541 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};
1542 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};
1543 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1544 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};
1546 /* user specific ntuser.dat */
1547 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1548 strcatW(path, ntuser_datW);
1549 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1552 /* default user.dat */
1553 if (hkey_users_default) {
1554 strcpyW(path, windir);
1555 strcatW(path, defaultW);
1556 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1560 * FIXME
1561 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1563 RtlInitUnicodeString( &nameW, System );
1564 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1566 strcpyW(path, windir);
1567 strcatW(path, systemW);
1568 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1569 NtClose( hkey );
1571 RtlInitUnicodeString( &nameW, Software );
1572 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1574 strcpyW(path, windir);
1575 strcatW(path, softwareW);
1576 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1577 NtClose( hkey );
1580 strcpyW(path, windir);
1581 strcatW(path, samW);
1582 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1584 strcpyW(path,windir);
1585 strcatW(path, securityW);
1586 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1588 /* this key is generated when the nt-core booted successfully */
1589 RtlInitUnicodeString( &nameW, Clone );
1590 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1591 break;
1594 case REG_WIN95:
1596 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1597 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1598 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1599 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1601 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1603 strcpyW(path, windir);
1604 strcatW(path, system_datW);
1605 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1607 RtlInitUnicodeString( &nameW, ClassesRootW );
1608 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1610 strcpyW(path, windir);
1611 strcatW(path, classes_datW);
1612 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1613 NtClose( hkey );
1616 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1617 /* user specific user.dat */
1618 strcatW(path, user_datW);
1619 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1621 /* default user.dat */
1622 if (hkey_users_default) {
1623 strcpyW(path, windir);
1624 strcatW(path, user_datW);
1625 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1627 } else {
1628 strcpyW(path, windir);
1629 strcatW(path, user_datW);
1630 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1632 break;
1635 case REG_WIN31:
1636 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1637 _w31_loadreg();
1638 break;
1640 case REG_DONTLOAD:
1641 TRACE("REG_DONTLOAD\n");
1642 break;
1644 default:
1645 ERR("switch: no match (%d)\n",reg_type);
1646 break;
1651 /* load global registry files (stored in /etc/wine) [Internal] */
1652 static void _load_global_registry( HKEY hkey_local_machine, HKEY hkey_users )
1654 TRACE("(void)\n");
1656 /* Load the global HKU hive directly from sysconfdir */
1657 load_wine_registry( hkey_users, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1659 /* Load the global machine defaults directly from sysconfdir */
1660 load_wine_registry( hkey_local_machine, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1663 /* load home registry files (stored in ~/.wine) [Internal] */
1664 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1665 HKEY hkey_users_default )
1667 LPCSTR confdir = wine_get_config_dir();
1668 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1670 strcpy(tmp,confdir);
1671 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1672 load_wine_registry(hkey_users_default,tmp);
1674 strcpy(tmp,confdir);
1675 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1676 load_wine_registry(hkey_current_user,tmp);
1678 strcpy(tmp,confdir);
1679 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1680 load_wine_registry(hkey_local_machine,tmp);
1682 free(tmp);
1685 /* load all registry (native and global and home) */
1686 void SHELL_LoadRegistry( void )
1688 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user;
1689 OBJECT_ATTRIBUTES attr;
1690 UNICODE_STRING nameW;
1692 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1693 static const WCHAR UserW[] = {'U','s','e','r',0};
1694 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1695 static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0};
1696 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};
1697 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};
1698 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};
1700 TRACE("(void)\n");
1702 if (!CLIENT_IsBootThread()) return; /* already loaded */
1704 attr.Length = sizeof(attr);
1705 attr.RootDirectory = 0;
1706 attr.ObjectName = &nameW;
1707 attr.Attributes = 0;
1708 attr.SecurityDescriptor = NULL;
1709 attr.SecurityQualityOfService = NULL;
1711 RtlInitUnicodeString( &nameW, MachineW );
1712 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1713 RtlInitUnicodeString( &nameW, UserW );
1714 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1716 attr.RootDirectory = hkey_users;
1717 RtlInitUnicodeString( &nameW, DefaultW );
1718 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1720 ERR("Cannot create HKEY_USERS/.Default\n" );
1721 ExitProcess(1);
1723 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1725 _set_registry_levels(0,0,0);
1726 _allocate_default_keys();
1727 if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1))
1728 _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1729 if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1))
1730 _load_global_registry( hkey_local_machine, hkey_users );
1731 _set_registry_levels(1,0,0);
1732 if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1))
1733 _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1734 _init_registry_saving( hkey_local_machine, hkey_current_user, hkey_users_default );
1735 NtClose(hkey_users_default);
1736 NtClose(hkey_current_user);
1737 NtClose(hkey_users);
1738 NtClose(hkey_local_machine);