Release 20010510.
[wine/multimedia.git] / misc / registry.c
blob5efb3c1912feeec8067763ee757affbcbe2c2b59
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 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include "winerror.h"
33 #include "file.h"
34 #include "heap.h"
35 #include "debugtools.h"
36 #include "options.h"
37 #include "winreg.h"
38 #include "server.h"
39 #ifdef HAVE_SYS_MMAN_H
40 # include <sys/mman.h>
41 #endif
42 #include "winnt.h"
45 DEFAULT_DEBUG_CHANNEL(reg);
47 /* FIXME: following defines should be configured global */
48 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
49 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
51 /* relative in ~user/.wine/ : */
52 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
53 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
54 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
56 /* _xmalloc [Internal] */
57 static void *_xmalloc( size_t size )
59 void *res;
61 res = malloc (size ? size : 1);
62 if (res == NULL) {
63 WARN("Virtual memory exhausted.\n");
64 exit (1);
66 return res;
69 /* _strdupnA [Internal] */
70 static LPSTR _strdupnA(LPCSTR str,size_t len)
72 LPSTR ret;
74 if (!str) return NULL;
75 ret = _xmalloc( len + 1 );
76 memcpy( ret, str, len );
77 ret[len] = 0x00;
78 return ret;
81 /* convert ansi string to unicode [Internal] */
82 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
84 LPWSTR ret;
85 size_t lenW;
87 if (!strA) return NULL;
88 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
89 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
90 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
91 ret[lenW] = 0;
92 return ret;
95 /* dump a Unicode string with proper escaping [Internal] */
96 /* FIXME: this code duplicates server/unicode.c */
97 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
99 static const char escapes[32] = ".......abtnvfr.............e....";
100 char buffer[256];
101 LPSTR pos = buffer;
102 int count = 0;
104 for (; len; str++, len--)
106 if (pos > buffer + sizeof(buffer) - 8)
108 fwrite( buffer, pos - buffer, 1, f );
109 count += pos - buffer;
110 pos = buffer;
112 if (*str > 127) /* hex escape */
114 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
115 pos += sprintf( pos, "\\x%04x", *str );
116 else
117 pos += sprintf( pos, "\\x%x", *str );
118 continue;
120 if (*str < 32) /* octal or C escape */
122 if (!*str && len == 1) continue; /* do not output terminating NULL */
123 if (escapes[*str] != '.')
124 pos += sprintf( pos, "\\%c", escapes[*str] );
125 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
126 pos += sprintf( pos, "\\%03o", *str );
127 else
128 pos += sprintf( pos, "\\%o", *str );
129 continue;
131 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
132 *pos++ = *str;
134 fwrite( buffer, pos - buffer, 1, f );
135 count += pos - buffer;
136 return count;
139 /* convert ansi string to unicode and dump with proper escaping [Internal] */
140 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
142 WCHAR *strW;
143 int ret;
145 if (strA == NULL) return 0;
146 strW = _strdupnAtoW(strA,len);
147 ret = _dump_strW(strW,len,f,escape);
148 free(strW);
149 return ret;
152 /* a key value */
153 /* FIXME: this code duplicates server/registry.c */
154 struct key_value {
155 WCHAR *nameW; /* value name */
156 int type; /* value type */
157 size_t len; /* value data length in bytes */
158 void *data; /* pointer to value data */
161 /* dump a value to a text file */
162 /* FIXME: this code duplicates server/registry.c */
163 static void _dump_value(struct key_value *value,FILE *f)
165 int i, count;
167 if (value->nameW[0]) {
168 fputc( '\"', f );
169 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
170 count += fprintf( f, "\"=" );
172 else count = fprintf( f, "@=" );
174 switch(value->type) {
175 case REG_SZ:
176 case REG_EXPAND_SZ:
177 case REG_MULTI_SZ:
178 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
179 fputc( '\"', f );
180 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
181 fputc( '\"', f );
182 break;
183 case REG_DWORD:
184 if (value->len == sizeof(DWORD)) {
185 DWORD dw;
186 memcpy( &dw, value->data, sizeof(DWORD) );
187 fprintf( f, "dword:%08lx", dw );
188 break;
190 /* else fall through */
191 default:
192 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
193 else count += fprintf( f, "hex(%x):", value->type );
194 for (i = 0; i < value->len; i++) {
195 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
196 if (i < value->len-1) {
197 fputc( ',', f );
198 if (++count > 76) {
199 fprintf( f, "\\\n " );
200 count = 2;
204 break;
206 fputc( '\n', f );
209 /******************************************************************/
210 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
212 reghack - windows 3.11 registry data format demo program.
214 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
215 a combined hash table and tree description, and finally a text table.
217 The header is obvious from the struct header. The taboff1 and taboff2
218 fields are always 0x20, and their usage is unknown.
220 The 8-byte entry table has various entry types.
222 tabent[0] is a root index. The second word has the index of the root of
223 the directory.
224 tabent[1..hashsize] is a hash table. The first word in the hash entry is
225 the index of the key/value that has that hash. Data with the same
226 hash value are on a circular list. The other three words in the
227 hash entry are always zero.
228 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
229 entry: dirent and keyent/valent. They are identified by context.
230 tabent[freeidx] is the first free entry. The first word in a free entry
231 is the index of the next free entry. The last has 0 as a link.
232 The other three words in the free list are probably irrelevant.
234 Entries in text table are preceded by a word at offset-2. This word
235 has the value (2*index)+1, where index is the referring keyent/valent
236 entry in the table. I have no suggestion for the 2* and the +1.
237 Following the word, there are N bytes of data, as per the keyent/valent
238 entry length. The offset of the keyent/valent entry is from the start
239 of the text table to the first data byte.
241 This information is not available from Microsoft. The data format is
242 deduced from the reg.dat file by me. Mistakes may
243 have been made. I claim no rights and give no guarantees for this program.
245 Tor Sjøwall, tor@sn.no
248 /* reg.dat header format */
249 struct _w31_header {
250 char cookie[8]; /* 'SHCC3.10' */
251 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
252 unsigned long taboff2; /* offset of index table (??) = 0x20 */
253 unsigned long tabcnt; /* number of entries in index table */
254 unsigned long textoff; /* offset of text part */
255 unsigned long textsize; /* byte size of text part */
256 unsigned short hashsize; /* hash size */
257 unsigned short freeidx; /* free index */
260 /* generic format of table entries */
261 struct _w31_tabent {
262 unsigned short w0, w1, w2, w3;
265 /* directory tabent: */
266 struct _w31_dirent {
267 unsigned short sibling_idx; /* table index of sibling dirent */
268 unsigned short child_idx; /* table index of child dirent */
269 unsigned short key_idx; /* table index of key keyent */
270 unsigned short value_idx; /* table index of value valent */
273 /* key tabent: */
274 struct _w31_keyent {
275 unsigned short hash_idx; /* hash chain index for string */
276 unsigned short refcnt; /* reference count */
277 unsigned short length; /* length of string */
278 unsigned short string_off; /* offset of string in text table */
281 /* value tabent: */
282 struct _w31_valent {
283 unsigned short hash_idx; /* hash chain index for string */
284 unsigned short refcnt; /* reference count */
285 unsigned short length; /* length of string */
286 unsigned short string_off; /* offset of string in text table */
289 /* recursive helper function to display a directory tree [Internal] */
290 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
292 struct _w31_dirent *dir;
293 struct _w31_keyent *key;
294 struct _w31_valent *val;
295 HKEY subkey = 0;
296 static char tail[400];
298 while (idx!=0) {
299 dir=(struct _w31_dirent*)&tab[idx];
301 if (dir->key_idx) {
302 key = (struct _w31_keyent*)&tab[dir->key_idx];
304 memcpy(tail,&txt[key->string_off],key->length);
305 tail[key->length]='\0';
306 /* all toplevel entries AND the entries in the
307 * toplevel subdirectory belong to \SOFTWARE\Classes
309 if (!level && !strcmp(tail,".classes")) {
310 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
311 idx=dir->sibling_idx;
312 continue;
314 if (subkey) RegCloseKey( subkey );
315 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
316 /* only add if leaf node or valued node */
317 if (dir->value_idx!=0||dir->child_idx==0) {
318 if (dir->value_idx) {
319 val=(struct _w31_valent*)&tab[dir->value_idx];
320 memcpy(tail,&txt[val->string_off],val->length);
321 tail[val->length]='\0';
322 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
325 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
326 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
327 idx=dir->sibling_idx;
329 if (subkey) RegCloseKey( subkey );
333 /******************************************************************************
334 * _w31_loadreg [Internal]
336 void _w31_loadreg(void)
338 HFILE hf;
339 struct _w31_header head;
340 struct _w31_tabent *tab;
341 unsigned char *txt;
342 unsigned int len;
343 OFSTRUCT ofs;
344 BY_HANDLE_FILE_INFORMATION hfinfo;
345 time_t lastmodified;
347 TRACE("(void)\n");
349 hf = OpenFile("reg.dat",&ofs,OF_READ);
350 if (hf==HFILE_ERROR) return;
352 /* read & dump header */
353 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
354 ERR("reg.dat is too short.\n");
355 _lclose(hf);
356 return;
358 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
359 ERR("reg.dat has bad signature.\n");
360 _lclose(hf);
361 return;
364 len = head.tabcnt * sizeof(struct _w31_tabent);
365 /* read and dump index table */
366 tab = _xmalloc(len);
367 if (len!=_lread(hf,tab,len)) {
368 ERR("couldn't read %d bytes.\n",len);
369 free(tab);
370 _lclose(hf);
371 return;
374 /* read text */
375 txt = _xmalloc(head.textsize);
376 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
377 ERR("couldn't seek to textblock.\n");
378 free(tab);
379 free(txt);
380 _lclose(hf);
381 return;
383 if (head.textsize!=_lread(hf,txt,head.textsize)) {
384 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
385 free(tab);
386 free(txt);
387 _lclose(hf);
388 return;
391 if (!GetFileInformationByHandle(hf,&hfinfo)) {
392 ERR("GetFileInformationByHandle failed?.\n");
393 free(tab);
394 free(txt);
395 _lclose(hf);
396 return;
398 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
399 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
400 free(tab);
401 free(txt);
402 _lclose(hf);
403 return;
406 /***********************************************************************************/
407 /* windows 95 registry loader */
408 /***********************************************************************************/
410 /* SECTION 1: main header
412 * once at offset 0
414 #define W95_REG_CREG_ID 0x47455243
416 typedef struct {
417 DWORD id; /* "CREG" = W95_REG_CREG_ID */
418 DWORD version; /* ???? 0x00010000 */
419 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
420 DWORD uk2; /* 0x0c */
421 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
422 WORD uk3;
423 DWORD uk[3];
424 /* rgkn */
425 } _w95creg;
427 /* SECTION 2: Directory information (tree structure)
429 * once on offset 0x20
431 * structure: [rgkn][dke]* (repeat till last_dke is reached)
433 #define W95_REG_RGKN_ID 0x4e4b4752
435 typedef struct {
436 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
437 DWORD size; /* Size of the RGKN-block */
438 DWORD root_off; /* Rel. Offset of the root-record */
439 DWORD last_dke; /* Offset to last DKE ? */
440 DWORD uk[4];
441 } _w95rgkn;
443 /* Disk Key Entry Structure
445 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
446 * hive itself. It looks the same like other keys. Even the ID-number can
447 * be any value.
449 * The "hash"-value is a value representing the key's name. Windows will not
450 * search for the name, but for a matching hash-value. if it finds one, it
451 * will compare the actual string info, otherwise continue with the next key.
452 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
453 * of the string which are smaller than 0x80 (128) to this D-Word.
455 * If you want to modify key names, also modify the hash-values, since they
456 * cannot be found again (although they would be displayed in REGEDIT)
457 * End of list-pointers are filled with 0xFFFFFFFF
459 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
460 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
461 * structure) and reading another RGDB_section.
463 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
464 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
465 * The remaining space between last_dke and the offset calculated from
466 * rgkn->size seems to be free for use for more dke:s.
467 * So it seems if more dke:s are added, they are added to that space and
468 * last_dke is grown, and in case that "free" space is out, the space
469 * gets grown and rgkn->size gets adjusted.
471 * there is a one to one relationship between dke and dkh
473 /* key struct, once per key */
474 typedef struct {
475 DWORD x1; /* Free entry indicator(?) */
476 DWORD hash; /* sum of bytes of keyname */
477 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
478 DWORD prevlvl; /* offset of previous key */
479 DWORD nextsub; /* offset of child key */
480 DWORD next; /* offset of sibling key */
481 WORD nrLS; /* id inside the rgdb block */
482 WORD nrMS; /* number of the rgdb block */
483 } _w95dke;
485 /* SECTION 3: key information, values and data
487 * structure:
488 * section: [blocks]* (repeat creg->rgdb_num times)
489 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
490 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
492 * An interesting relationship exists in RGDB_section. The DWORD value
493 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
494 * I have no idea at the moment what this means. (Kevin Cozens)
497 /* block header, once per block */
498 #define W95_REG_RGDB_ID 0x42444752
500 typedef struct {
501 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
502 DWORD size; /* 0x04 */
503 DWORD uk1; /* 0x08 */
504 DWORD uk2; /* 0x0c */
505 DWORD uk3; /* 0x10 */
506 DWORD uk4; /* 0x14 */
507 DWORD uk5; /* 0x18 */
508 DWORD uk6; /* 0x1c */
509 /* dkh */
510 } _w95rgdb;
512 /* Disk Key Header structure (RGDB part), once per key */
513 typedef struct {
514 DWORD nextkeyoff; /* 0x00 offset to next dkh */
515 WORD nrLS; /* 0x04 id inside the rgdb block */
516 WORD nrMS; /* 0x06 number of the rgdb block */
517 DWORD bytesused; /* 0x08 */
518 WORD keynamelen; /* 0x0c len of name */
519 WORD values; /* 0x0e number of values */
520 DWORD xx1; /* 0x10 */
521 char name[1]; /* 0x14 */
522 /* dkv */ /* 0x14 + keynamelen */
523 } _w95dkh;
525 /* Disk Key Value structure, once per value */
526 typedef struct {
527 DWORD type; /* 0x00 */
528 DWORD x1; /* 0x04 */
529 WORD valnamelen; /* 0x08 length of name, 0 is default key */
530 WORD valdatalen; /* 0x0A length of data */
531 char name[1]; /* 0x0c */
532 /* raw data */ /* 0x0c + valnamelen */
533 } _w95dkv;
535 /******************************************************************************
536 * _w95_lookup_dkh [Internal]
538 * seeks the dkh belonging to a dke
540 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
542 _w95rgdb * rgdb;
543 _w95dkh * dkh;
544 int i;
546 /* get the beginning of the rgdb datastore */
547 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
549 /* check: requested block < last_block) */
550 if (creg->rgdb_num <= nrMS) {
551 ERR("registry file corrupt! requested block no. beyond end.\n");
552 goto error;
555 /* find the right block */
556 for(i=0; i<nrMS ;i++) {
557 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
558 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
559 goto error;
561 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
564 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
566 do {
567 if(nrLS==dkh->nrLS ) return dkh;
568 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
569 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
571 error:
572 return NULL;
575 /******************************************************************************
576 * _w95_dump_dkv [Internal]
578 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
580 _w95dkv * dkv;
581 int i;
583 /* first value block */
584 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
586 /* loop trought the values */
587 for (i=0; i< dkh->values; i++) {
588 struct key_value value;
589 WCHAR *pdata;
591 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
592 value.type = dkv->type;
593 value.len = dkv->valdatalen;
595 value.data = &(dkv->name[dkv->valnamelen]);
596 pdata = NULL;
597 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
598 pdata = _strdupnAtoW(value.data,value.len);
599 value.len *= 2;
601 if (pdata != NULL) value.data = pdata;
603 _dump_value(&value,f);
604 free(value.nameW);
605 if (pdata != NULL) free(pdata);
607 /* next value */
608 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
610 return TRUE;
613 /******************************************************************************
614 * _w95_dump_dke [Internal]
616 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
618 _w95dkh * dkh;
619 LPSTR new_key_name = NULL;
621 /* special root key */
622 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
624 /* parse the one subkey */
625 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
626 /* has no sibling keys */
627 return FALSE;
630 /* search subblock */
631 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
632 ERR("dke pointing to missing dkh !\n");
633 return FALSE;
636 if (level <= 0) {
637 /* create new subkey name */
638 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
639 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
640 strncat(new_key_name,dkh->name,dkh->keynamelen);
642 /* walk sibling keys */
643 if (dke->next != 0xffffffff ) {
644 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
645 free(new_key_name);
646 return FALSE;
650 /* write the key path (something like [Software\\Microsoft\\..]) only if:
651 1) key has some values
652 2) key has no values and no subkeys
654 if (dkh->values > 0) {
655 /* there are some values */
656 fprintf(f,"\n[");
657 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
658 fprintf(f,"]\n");
659 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
660 free(new_key_name);
661 return FALSE;
664 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
665 /* no subkeys and no values */
666 fprintf(f,"\n[");
667 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
668 fprintf(f,"]\n");
670 } else new_key_name = _strdupnA(key_name,strlen(key_name));
672 /* next sub key */
673 if (dke->nextsub != 0xffffffff) {
674 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
675 free(new_key_name);
676 return FALSE;
680 free(new_key_name);
681 return TRUE;
683 /* end windows 95 loader */
685 /***********************************************************************************/
686 /* windows NT registry loader */
687 /***********************************************************************************/
689 /* NT REGISTRY LOADER */
691 #ifdef HAVE_SYS_MMAN_H
692 # include <sys/mman.h>
693 #endif
695 #ifndef MAP_FAILED
696 #define MAP_FAILED ((LPVOID)-1)
697 #endif
699 #define NT_REG_BLOCK_SIZE 0x1000
701 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
702 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
703 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
704 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
706 /* subblocks of nk */
707 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
708 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
709 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
711 #define NT_REG_KEY_BLOCK_TYPE 0x20
712 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
714 typedef struct {
715 DWORD id; /* 0x66676572 'regf'*/
716 DWORD uk1; /* 0x04 */
717 DWORD uk2; /* 0x08 */
718 FILETIME DateModified; /* 0x0c */
719 DWORD uk3; /* 0x14 */
720 DWORD uk4; /* 0x18 */
721 DWORD uk5; /* 0x1c */
722 DWORD uk6; /* 0x20 */
723 DWORD RootKeyBlock; /* 0x24 */
724 DWORD BlockSize; /* 0x28 */
725 DWORD uk7[116];
726 DWORD Checksum; /* at offset 0x1FC */
727 } nt_regf;
729 typedef struct {
730 DWORD blocksize;
731 BYTE data[1];
732 } nt_hbin_sub;
734 typedef struct {
735 DWORD id; /* 0x6E696268 'hbin' */
736 DWORD off_prev;
737 DWORD off_next;
738 DWORD uk1;
739 DWORD uk2; /* 0x10 */
740 DWORD uk3; /* 0x14 */
741 DWORD uk4; /* 0x18 */
742 DWORD size; /* 0x1C */
743 nt_hbin_sub hbin_sub; /* 0x20 */
744 } nt_hbin;
747 * the value_list consists of offsets to the values (vk)
749 typedef struct {
750 WORD SubBlockId; /* 0x00 0x6B6E */
751 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
752 FILETIME writetime; /* 0x04 */
753 DWORD uk1; /* 0x0C */
754 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
755 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
756 DWORD uk8; /* 0x18 */
757 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
758 DWORD uk2; /* 0x20 */
759 DWORD nr_values; /* 0x24 number of values */
760 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
761 DWORD off_sk; /* 0x2c Offset of the sk-Record */
762 DWORD off_class; /* 0x30 Offset of the Class-Name */
763 DWORD uk3; /* 0x34 */
764 DWORD uk4; /* 0x38 */
765 DWORD uk5; /* 0x3c */
766 DWORD uk6; /* 0x40 */
767 DWORD uk7; /* 0x44 */
768 WORD name_len; /* 0x48 name-length */
769 WORD class_len; /* 0x4a class-name length */
770 char name[1]; /* 0x4c key-name */
771 } nt_nk;
773 typedef struct {
774 DWORD off_nk; /* 0x00 */
775 DWORD name; /* 0x04 */
776 } hash_rec;
778 typedef struct {
779 WORD id; /* 0x00 0x666c */
780 WORD nr_keys; /* 0x06 */
781 hash_rec hash_rec[1];
782 } nt_lf;
785 list of subkeys without hash
787 li --+-->nk
789 +-->nk
791 typedef struct {
792 WORD id; /* 0x00 0x696c */
793 WORD nr_keys;
794 DWORD off_nk[1];
795 } nt_li;
798 this is a intermediate node
800 ri --+-->li--+-->nk
802 | +-->nk
804 +-->li--+-->nk
806 +-->nk
808 typedef struct {
809 WORD id; /* 0x00 0x6972 */
810 WORD nr_li; /* 0x02 number off offsets */
811 DWORD off_li[1]; /* 0x04 points to li */
812 } nt_ri;
814 typedef struct {
815 WORD id; /* 0x00 'vk' */
816 WORD nam_len;
817 DWORD data_len;
818 DWORD data_off;
819 DWORD type;
820 WORD flag;
821 WORD uk1;
822 char name[1];
823 } nt_vk;
826 * gets a value
828 * vk->flag:
829 * 0 value is a default value
830 * 1 the value has a name
832 * vk->data_len
833 * len of the whole data block
834 * - reg_sz (unicode)
835 * bytes including the terminating \0 = 2*(number_of_chars+1)
836 * - reg_dword, reg_binary:
837 * if highest bit of data_len is set data_off contains the value
839 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
841 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
842 struct key_value value;
844 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
845 ERR("unknown block found (0x%04x), please report!\n", vk->id);
846 return FALSE;
849 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
850 value.type = vk->type;
851 value.len = (vk->data_len & 0x7fffffff);
852 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
854 _dump_value(&value,f);
855 free(value.nameW);
857 return TRUE;
860 /* it's called from _nt_dump_lf() */
861 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
864 * get the subkeys
866 * this structure contains the hash of a keyname and points to all
867 * subkeys
869 * exception: if the id is 'il' there are no hash values and every
870 * dword is a offset
872 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
874 int i;
876 if (lf->id == NT_REG_HASH_BLOCK_ID) {
877 if (subkeys != lf->nr_keys) goto error1;
879 for (i=0; i<lf->nr_keys; i++)
880 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
881 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
882 nt_li * li = (nt_li*)lf;
883 if (subkeys != li->nr_keys) goto error1;
885 for (i=0; i<li->nr_keys; i++)
886 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
887 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
888 nt_ri * ri = (nt_ri*)lf;
889 int li_subkeys = 0;
891 /* count all subkeys */
892 for (i=0; i<ri->nr_li; i++) {
893 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
894 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
895 li_subkeys += li->nr_keys;
898 /* check number */
899 if (subkeys != li_subkeys) goto error1;
901 /* loop through the keys */
902 for (i=0; i<ri->nr_li; i++) {
903 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
904 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
906 } else goto error2;
908 return TRUE;
910 error2:
911 ERR("unknown node id 0x%04x, please report!\n", lf->id);
912 return TRUE;
914 error1:
915 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
916 return FALSE;
918 error:
919 ERR("error reading lf block\n");
920 return FALSE;
923 /* _nt_dump_nk [Internal] */
924 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
926 unsigned int n;
927 DWORD *vl;
928 LPSTR new_key_name = NULL;
931 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
932 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
933 return FALSE;
936 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
937 ERR("registry file corrupt!\n");
938 return FALSE;
941 /* create the new key */
942 if (level <= 0) {
943 /* create new subkey name */
944 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
945 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
946 strncat(new_key_name,nk->name,nk->name_len);
948 /* write the key path (something like [Software\\Microsoft\\..]) only if:
949 1) key has some values
950 2) key has no values and no subkeys
952 if (nk->nr_values > 0) {
953 /* there are some values */
954 fprintf(f,"\n[");
955 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
956 fprintf(f,"]\n");
958 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
959 /* no subkeys and no values */
960 fprintf(f,"\n[");
961 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
962 fprintf(f,"]\n");
965 /* loop trough the value list */
966 vl = (DWORD *)(base+nk->valuelist_off+4);
967 for (n=0; n<nk->nr_values; n++) {
968 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
969 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
970 free(new_key_name);
971 return FALSE;
974 } else new_key_name = _strdupnA(key_name,strlen(key_name));
976 /* loop through the subkeys */
977 if (nk->nr_subkeys) {
978 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
979 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
980 free(new_key_name);
981 return FALSE;
985 free(new_key_name);
986 return TRUE;
989 /* end nt loader */
991 /**********************************************************************************
992 * _set_registry_levels [Internal]
994 * set level to 0 for loading system files
995 * set level to 1 for loading user files
997 static void _set_registry_levels(int level,int saving,int period)
999 SERVER_START_REQ( set_registry_levels )
1001 req->current = level;
1002 req->saving = saving;
1003 req->period = period;
1004 SERVER_CALL();
1006 SERVER_END_REQ;
1009 /* _save_at_exit [Internal] */
1010 static void _save_at_exit(HKEY hkey,LPCSTR path)
1012 LPCSTR confdir = get_config_dir();
1013 size_t len = strlen(confdir) + strlen(path) + 2;
1015 if (len > REQUEST_MAX_VAR_SIZE) {
1016 ERR( "config dir '%s' too long\n", confdir );
1017 return;
1019 SERVER_START_VAR_REQ( save_registry_atexit, len )
1021 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1022 req->hkey = hkey;
1023 SERVER_CALL();
1025 SERVER_END_VAR_REQ;
1028 /* configure save files and start the periodic saving timer [Internal] */
1029 static void _init_registry_saving( HKEY hkey_users_default )
1031 int all;
1032 int period;
1034 all = PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1035 period = PROFILE_GetWineIniInt("registry","PeriodicSave",0);
1037 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1038 _set_registry_levels(1,!all,period*1000);
1040 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1042 _save_at_exit(HKEY_CURRENT_USER,SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1043 _save_at_exit(HKEY_LOCAL_MACHINE,SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1044 _save_at_exit(hkey_users_default,SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1049 /******************************************************************************
1050 * _allocate_default_keys [Internal]
1051 * Registry initialisation, allocates some default keys.
1053 static void _allocate_default_keys(void) {
1054 HKEY hkey;
1055 char buf[200];
1057 TRACE("(void)\n");
1059 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1060 RegCloseKey(hkey);
1062 /* This was an Open, but since it is called before the real registries
1063 are loaded, it was changed to a Create - MTB 980507*/
1064 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1065 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1066 RegCloseKey(hkey);
1068 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1069 * CurrentVersion
1070 * CurrentBuildNumber
1071 * CurrentType
1072 * string RegisteredOwner
1073 * string RegisteredOrganization
1076 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1077 * string SysContact
1078 * string SysLocation
1079 * SysServices
1081 if (-1!=gethostname(buf,200)) {
1082 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1083 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1084 RegCloseKey(hkey);
1087 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1088 RegCloseKey(hkey);
1091 #define REG_DONTLOAD -1
1092 #define REG_WIN31 0
1093 #define REG_WIN95 1
1094 #define REG_WINNT 2
1096 /* return the type of native registry [Internal] */
1097 static int _get_reg_type(void)
1099 char windir[MAX_PATHNAME_LEN];
1100 char tmp[MAX_PATHNAME_LEN];
1101 int ret = REG_WIN31;
1103 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1105 /* test %windir%/system32/config/system --> winnt */
1106 strcpy(tmp, windir);
1107 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1108 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1109 ret = REG_WINNT;
1111 else
1113 /* test %windir%/system.dat --> win95 */
1114 strcpy(tmp, windir);
1115 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1116 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1117 ret = REG_WIN95;
1121 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1122 MESSAGE("When you are running with a native NT directory specify\n");
1123 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1124 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1125 ret = REG_DONTLOAD;
1128 return ret;
1131 #define WINE_REG_VER_ERROR -1
1132 #define WINE_REG_VER_1 0
1133 #define WINE_REG_VER_2 1
1134 #define WINE_REG_VER_OLD 2
1135 #define WINE_REG_VER_UNKNOWN 3
1137 /* return the version of wine registry file [Internal] */
1138 static int _get_wine_registry_file_format_version(LPCSTR fn)
1140 FILE *f;
1141 char tmp[50];
1142 int ver;
1144 if ((f=fopen(fn,"rt")) == NULL) {
1145 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1146 return WINE_REG_VER_ERROR;
1149 if (fgets(tmp,50,f) == NULL) {
1150 WARN("Error reading %s: %s\n",fn,strerror(errno));
1151 fclose(f);
1152 return WINE_REG_VER_ERROR;
1154 fclose(f);
1156 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1157 switch (ver) {
1158 case 1:
1159 return WINE_REG_VER_1;
1160 break;
1161 case 2:
1162 return WINE_REG_VER_2;
1163 break;
1164 default:
1165 return WINE_REG_VER_UNKNOWN;
1169 /* load the registry file in wine format [Internal] */
1170 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1172 int file_format;
1174 file_format = _get_wine_registry_file_format_version(fn);
1175 switch (file_format) {
1177 case WINE_REG_VER_1:
1178 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1179 break;
1181 case WINE_REG_VER_2: {
1182 HANDLE file;
1183 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1184 FILE_ATTRIBUTE_NORMAL, 0, TRUE )))
1186 SERVER_START_REQ( load_registry )
1188 req->hkey = hkey;
1189 req->file = file;
1190 SERVER_CALL();
1192 SERVER_END_REQ;
1193 CloseHandle( file );
1195 break;
1198 case WINE_REG_VER_UNKNOWN:
1199 WARN("Unable to load registry file %s: unknown format.\n",fn);
1200 break;
1202 case WINE_REG_VER_ERROR:
1203 break;
1207 /* generate and return the name of the tmp file and associated stream [Internal] */
1208 static LPSTR _get_tmp_fn(FILE **f)
1210 LPSTR ret;
1211 int tmp_fd,count;
1213 ret = _xmalloc(50);
1214 for (count = 0;;) {
1215 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1216 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1217 if (errno != EEXIST) {
1218 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1219 free(ret);
1220 *f = NULL;
1221 return NULL;
1225 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1226 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1227 close(tmp_fd);
1228 free(ret);
1229 return NULL;
1232 return ret;
1235 /* convert win95 native registry file to wine format [Internal] */
1236 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1238 int fd;
1239 FILE *f;
1240 DOS_FULL_NAME full_name;
1241 void *base;
1242 LPSTR ret = NULL;
1243 struct stat st;
1245 _w95creg *creg;
1246 _w95rgkn *rgkn;
1247 _w95dke *dke, *root_dke;
1249 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1251 /* map the registry into the memory */
1252 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1253 if ((fstat(fd, &st) == -1)) goto error1;
1254 if (!st.st_size) goto error1;
1255 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1257 /* control signature */
1258 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1259 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1260 goto error;
1263 creg = base;
1264 /* load the header (rgkn) */
1265 rgkn = (_w95rgkn*)(creg + 1);
1266 if (rgkn->id != W95_REG_RGKN_ID) {
1267 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1268 goto error;
1270 if (rgkn->root_off != 0x20) {
1271 ERR("rgkn->root_off not 0x20, please report !\n");
1272 goto error;
1274 if (rgkn->last_dke > rgkn->size)
1276 ERR("registry file corrupt! last_dke > size!\n");
1277 goto error;
1279 /* verify last dke */
1280 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1281 if (dke->x1 != 0x80000000)
1282 { /* wrong magic */
1283 ERR("last dke invalid !\n");
1284 goto error;
1286 if (rgkn->size > creg->rgdb_off)
1288 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1289 goto error;
1291 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1292 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1294 ERR("registry file corrupt! invalid root dke !\n");
1295 goto error;
1298 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1299 fprintf(f,"WINE REGISTRY Version 2");
1300 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1301 fclose(f);
1303 error:
1304 if(ret == NULL) {
1305 ERR("Unable to load native win95 registry file %s.\n",fn);
1306 ERR("Please report to a.mohr@mailto.de.\n");
1307 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1310 munmap(base, st.st_size);
1311 error1:
1312 close(fd);
1313 return ret;
1316 /* convert winnt native registry file to wine format [Internal] */
1317 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1319 int fd;
1320 FILE *f;
1321 DOS_FULL_NAME full_name;
1322 void *base;
1323 LPSTR ret = NULL;
1324 struct stat st;
1326 nt_regf *regf;
1327 nt_hbin *hbin;
1328 nt_hbin_sub *hbin_sub;
1329 nt_nk *nk;
1331 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1333 /* map the registry into the memory */
1334 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1335 if ((fstat(fd, &st) == -1)) goto error1;
1336 if (!st.st_size) goto error1;
1337 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1339 /* control signature */
1340 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1341 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1342 goto error;
1345 /* start block */
1346 regf = base;
1348 /* hbin block */
1349 hbin = (nt_hbin*)((char*) base + 0x1000);
1350 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1351 ERR( "hbin block invalid\n");
1352 goto error;
1355 /* hbin_sub block */
1356 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1357 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1358 ERR( "hbin_sub block invalid\n");
1359 goto error;
1362 /* nk block */
1363 nk = (nt_nk*)&(hbin_sub->data[0]);
1364 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1365 ERR( "special nk block not found\n");
1366 goto error;
1369 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1370 fprintf(f,"WINE REGISTRY Version 2");
1371 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1372 fclose(f);
1374 error:
1375 munmap(base,st.st_size);
1376 error1:
1377 close(fd);
1378 return ret;
1381 /* convert native native registry to wine format and load it via server call [Internal] */
1382 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1384 LPSTR tmp = NULL;
1386 switch (reg_type) {
1387 case REG_WINNT:
1388 /* FIXME: following function doesn't really convert yet */
1389 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1390 break;
1391 case REG_WIN95:
1392 tmp = _convert_win95_registry_to_wine_format(fn,level);
1393 break;
1394 case REG_WIN31:
1395 ERR("Don't know how to convert native 3.1 registry yet.\n");
1396 break;
1397 default:
1398 ERR("Unknown registry format parameter (%d)\n",reg_type);
1399 break;
1402 if (tmp != NULL) {
1403 load_wine_registry(hkey,tmp);
1404 TRACE("File %s successfuly converted to %s and loaded to registry.\n",fn,tmp);
1405 unlink(tmp);
1407 else WARN("Unable to convert %s (not exist?)\n",fn);
1408 free(tmp);
1411 /* load all native windows registry files [Internal] */
1412 static void _load_windows_registry( HKEY hkey_users_default )
1414 int reg_type;
1415 char windir[MAX_PATHNAME_LEN];
1416 char path[MAX_PATHNAME_LEN];
1418 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1420 reg_type = _get_reg_type();
1421 switch (reg_type) {
1422 case REG_WINNT: {
1423 HKEY hkey;
1425 /* user specific ntuser.dat */
1426 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1427 strcat(path,"\\ntuser.dat");
1428 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1431 /* default user.dat */
1432 if (hkey_users_default) {
1433 strcpy(path,windir);
1434 strcat(path,"\\system32\\config\\default");
1435 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1439 * FIXME
1440 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1443 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1444 strcpy(path,windir);
1445 strcat(path,"\\system32\\config\\system");
1446 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1447 RegCloseKey(hkey);
1450 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1451 strcpy(path,windir);
1452 strcat(path,"\\system32\\config\\software");
1453 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1454 RegCloseKey(hkey);
1457 strcpy(path,windir);
1458 strcat(path,"\\system32\\config\\sam");
1459 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1461 strcpy(path,windir);
1462 strcat(path,"\\system32\\config\\security");
1463 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1465 /* this key is generated when the nt-core booted successfully */
1466 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1467 break;
1470 case REG_WIN95:
1471 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1473 strcpy(path,windir);
1474 strcat(path,"\\system.dat");
1475 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1477 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1478 /* user specific user.dat */
1479 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1480 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1482 /* default user.dat */
1483 if (hkey_users_default) {
1484 strcpy(path,windir);
1485 strcat(path,"\\user.dat");
1486 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1488 } else {
1489 strcpy(path,windir);
1490 strcat(path,"\\user.dat");
1491 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1493 break;
1495 case REG_WIN31:
1496 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1497 _w31_loadreg();
1498 break;
1500 case REG_DONTLOAD:
1501 TRACE("REG_DONTLOAD\n");
1502 break;
1504 default:
1505 ERR("switch: no match (%d)\n",reg_type);
1506 break;
1511 /* load global registry files (stored in /etc/wine) [Internal] */
1512 static void _load_global_registry(void)
1514 TRACE("(void)\n");
1516 /* Load the global HKU hive directly from sysconfdir */
1517 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1519 /* Load the global machine defaults directly from sysconfdir */
1520 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1523 /* load home registry files (stored in ~/.wine) [Internal] */
1524 static void _load_home_registry( HKEY hkey_users_default )
1526 LPCSTR confdir = get_config_dir();
1527 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1529 strcpy(tmp,confdir);
1530 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1531 load_wine_registry(hkey_users_default,tmp);
1533 strcpy(tmp,confdir);
1534 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1535 load_wine_registry(HKEY_CURRENT_USER,tmp);
1537 strcpy(tmp,confdir);
1538 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1539 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1541 free(tmp);
1544 /* load all registry (native and global and home) */
1545 void SHELL_LoadRegistry( void )
1547 HKEY hkey_users_default;
1549 TRACE("(void)\n");
1551 if (!CLIENT_IsBootThread()) return; /* already loaded */
1553 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1555 ERR("Cannot create HKEY_USERS/.Default\n" );
1556 ExitProcess(1);
1559 _allocate_default_keys();
1560 _set_registry_levels(0,0,0);
1561 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1562 _load_windows_registry( hkey_users_default );
1563 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1564 _load_global_registry();
1565 _set_registry_levels(1,0,0);
1566 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1567 _load_home_registry( hkey_users_default );
1568 _init_registry_saving( hkey_users_default );
1569 RegCloseKey(hkey_users_default);
1572 /***************************************************************************/
1573 /* API FUNCTIONS */
1574 /***************************************************************************/
1576 /******************************************************************************
1577 * RegFlushKey [KERNEL.227] [ADVAPI32.@]
1578 * Immediately writes key to registry.
1579 * Only returns after data has been written to disk.
1581 * FIXME: does it really wait until data is written ?
1583 * PARAMS
1584 * hkey [I] Handle of key to write
1586 * RETURNS
1587 * Success: ERROR_SUCCESS
1588 * Failure: Error code
1590 DWORD WINAPI RegFlushKey( HKEY hkey )
1592 FIXME( "(%x): stub\n", hkey );
1593 return ERROR_SUCCESS;
1597 /******************************************************************************
1598 * RegUnLoadKeyA [ADVAPI32.@]
1600 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1602 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1603 return ERROR_SUCCESS;
1607 /******************************************************************************
1608 * RegRestoreKeyW [ADVAPI32.@]
1610 * PARAMS
1611 * hkey [I] Handle of key where restore begins
1612 * lpFile [I] Address of filename containing saved tree
1613 * dwFlags [I] Optional flags
1615 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1617 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1619 /* It seems to do this check before the hkey check */
1620 if (!lpFile || !*lpFile)
1621 return ERROR_INVALID_PARAMETER;
1623 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1625 /* Check for file existence */
1627 return ERROR_SUCCESS;
1631 /******************************************************************************
1632 * RegRestoreKeyA [ADVAPI32.@]
1634 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1636 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1637 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1638 HeapFree( GetProcessHeap(), 0, lpFileW );
1639 return ret;
1643 /******************************************************************************
1644 * RegReplaceKeyA [ADVAPI32.@]
1646 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1647 LPCSTR lpOldFile )
1649 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1650 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1651 return ERROR_SUCCESS;
1659 /* 16-bit functions */
1661 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1662 * some programs. Do not remove those cases. -MM
1664 static inline void fix_win16_hkey( HKEY *hkey )
1666 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1669 /******************************************************************************
1670 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1672 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1674 fix_win16_hkey( &hkey );
1675 return RegEnumKeyA( hkey, index, name, name_len );
1678 /******************************************************************************
1679 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1681 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1683 fix_win16_hkey( &hkey );
1684 return RegOpenKeyA( hkey, name, retkey );
1687 /******************************************************************************
1688 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1690 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1692 fix_win16_hkey( &hkey );
1693 return RegCreateKeyA( hkey, name, retkey );
1696 /******************************************************************************
1697 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1699 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1701 fix_win16_hkey( &hkey );
1702 return RegDeleteKeyA( hkey, name );
1705 /******************************************************************************
1706 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1708 DWORD WINAPI RegCloseKey16( HKEY hkey )
1710 fix_win16_hkey( &hkey );
1711 return RegCloseKey( hkey );
1714 /******************************************************************************
1715 * RegSetValue16 [KERNEL.221] [SHELL.5]
1717 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1719 fix_win16_hkey( &hkey );
1720 return RegSetValueA( hkey, name, type, data, count );
1723 /******************************************************************************
1724 * RegDeleteValue16 [KERNEL.222]
1726 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1728 fix_win16_hkey( &hkey );
1729 return RegDeleteValueA( hkey, name );
1732 /******************************************************************************
1733 * RegEnumValue16 [KERNEL.223]
1735 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1736 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1738 fix_win16_hkey( &hkey );
1739 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1742 /******************************************************************************
1743 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1745 * NOTES
1746 * Is this HACK still applicable?
1748 * HACK
1749 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1750 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1751 * Aldus FH4)
1753 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1755 fix_win16_hkey( &hkey );
1756 if (count) *count &= 0xffff;
1757 return RegQueryValueA( hkey, name, data, count );
1760 /******************************************************************************
1761 * RegQueryValueEx16 [KERNEL.225]
1763 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1764 LPBYTE data, LPDWORD count )
1766 fix_win16_hkey( &hkey );
1767 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1770 /******************************************************************************
1771 * RegSetValueEx16 [KERNEL.226]
1773 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1774 CONST BYTE *data, DWORD count )
1776 fix_win16_hkey( &hkey );
1777 if (!count && (type==REG_SZ)) count = strlen(data);
1778 return RegSetValueExA( hkey, name, reserved, type, data, count );
1781 /******************************************************************************
1782 * RegFlushKey16 [KERNEL.227]
1784 DWORD WINAPI RegFlushKey16( HKEY hkey )
1786 fix_win16_hkey( &hkey );
1787 return RegFlushKey( hkey );