Make sure that MSG_PeekMessage uses an internal variable to avoid
[wine/hacks.git] / misc / registry.c
blob0afd6d0a984cd893511ea378be46684ec9965fa4
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
1001 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1003 req->current = level;
1004 req->saving = saving;
1005 req->period = period;
1006 server_call( REQ_SET_REGISTRY_LEVELS );
1008 SERVER_END_REQ;
1011 /* _save_at_exit [Internal] */
1012 static void _save_at_exit(HKEY hkey,LPCSTR path)
1014 LPCSTR confdir = get_config_dir();
1015 size_t len = strlen(confdir) + strlen(path) + 2;
1017 if (len > REQUEST_MAX_VAR_SIZE) {
1018 ERR( "config dir '%s' too long\n", confdir );
1019 return;
1021 SERVER_START_REQ
1023 struct save_registry_atexit_request *req = server_alloc_req( sizeof(*req), len );
1024 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1025 req->hkey = hkey;
1026 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1028 SERVER_END_REQ;
1031 /* configure save files and start the periodic saving timer [Internal] */
1032 static void _init_registry_saving( HKEY hkey_users_default )
1034 int all;
1035 int period;
1037 all = PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1038 period = PROFILE_GetWineIniInt("registry","PeriodicSave",0);
1040 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1041 _set_registry_levels(1,!all,period*1000);
1043 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1045 _save_at_exit(HKEY_CURRENT_USER,SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1046 _save_at_exit(HKEY_LOCAL_MACHINE,SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1047 _save_at_exit(hkey_users_default,SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1052 /******************************************************************************
1053 * _allocate_default_keys [Internal]
1054 * Registry initialisation, allocates some default keys.
1056 static void _allocate_default_keys(void) {
1057 HKEY hkey;
1058 char buf[200];
1060 TRACE("(void)\n");
1062 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1063 RegCloseKey(hkey);
1065 /* This was an Open, but since it is called before the real registries
1066 are loaded, it was changed to a Create - MTB 980507*/
1067 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1068 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1069 RegCloseKey(hkey);
1071 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1072 * CurrentVersion
1073 * CurrentBuildNumber
1074 * CurrentType
1075 * string RegisteredOwner
1076 * string RegisteredOrganization
1079 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1080 * string SysContact
1081 * string SysLocation
1082 * SysServices
1084 if (-1!=gethostname(buf,200)) {
1085 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1086 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1087 RegCloseKey(hkey);
1090 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1091 RegCloseKey(hkey);
1094 #define REG_DONTLOAD -1
1095 #define REG_WIN31 0
1096 #define REG_WIN95 1
1097 #define REG_WINNT 2
1099 /* return the type of native registry [Internal] */
1100 static int _get_reg_type(void)
1102 char windir[MAX_PATHNAME_LEN];
1103 char tmp[MAX_PATHNAME_LEN];
1104 int ret = REG_WIN31;
1106 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1108 /* test %windir%/system32/config/system --> winnt */
1109 strcpy(tmp, windir);
1110 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1111 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1112 ret = REG_WINNT;
1114 else
1116 /* test %windir%/system.dat --> win95 */
1117 strcpy(tmp, windir);
1118 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1119 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1120 ret = REG_WIN95;
1124 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1125 MESSAGE("When you are running with a native NT directory specify\n");
1126 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1127 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1128 ret = REG_DONTLOAD;
1131 return ret;
1134 #define WINE_REG_VER_ERROR -1
1135 #define WINE_REG_VER_1 0
1136 #define WINE_REG_VER_2 1
1137 #define WINE_REG_VER_OLD 2
1138 #define WINE_REG_VER_UNKNOWN 3
1140 /* return the version of wine registry file [Internal] */
1141 static int _get_wine_registry_file_format_version(LPCSTR fn)
1143 FILE *f;
1144 char tmp[50];
1145 int ver;
1147 if ((f=fopen(fn,"rt")) == NULL) {
1148 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1149 return WINE_REG_VER_ERROR;
1152 if (fgets(tmp,50,f) == NULL) {
1153 WARN("Error reading %s: %s\n",fn,strerror(errno));
1154 fclose(f);
1155 return WINE_REG_VER_ERROR;
1157 fclose(f);
1159 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1160 switch (ver) {
1161 case 1:
1162 return WINE_REG_VER_1;
1163 break;
1164 case 2:
1165 return WINE_REG_VER_2;
1166 break;
1167 default:
1168 return WINE_REG_VER_UNKNOWN;
1172 /* load the registry file in wine format [Internal] */
1173 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1175 int file_format;
1177 file_format = _get_wine_registry_file_format_version(fn);
1178 switch (file_format) {
1180 case WINE_REG_VER_1:
1181 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1182 break;
1184 case WINE_REG_VER_2: {
1185 HANDLE file;
1186 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1187 FILE_ATTRIBUTE_NORMAL, 0, TRUE )))
1189 SERVER_START_REQ
1191 struct load_registry_request *req = server_alloc_req( sizeof(*req), 0 );
1192 req->hkey = hkey;
1193 req->file = file;
1194 server_call( REQ_LOAD_REGISTRY );
1196 SERVER_END_REQ;
1197 CloseHandle( file );
1199 break;
1202 case WINE_REG_VER_UNKNOWN:
1203 WARN("Unable to load registry file %s: unknown format.\n",fn);
1204 break;
1206 case WINE_REG_VER_ERROR:
1207 break;
1211 /* generate and return the name of the tmp file and associated stream [Internal] */
1212 static LPSTR _get_tmp_fn(FILE **f)
1214 LPSTR ret;
1215 int tmp_fd,count;
1217 ret = _xmalloc(50);
1218 for (count = 0;;) {
1219 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1220 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1221 if (errno != EEXIST) {
1222 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1223 free(ret);
1224 *f = NULL;
1225 return NULL;
1229 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1230 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1231 close(tmp_fd);
1232 free(ret);
1233 return NULL;
1236 return ret;
1239 /* convert win95 native registry file to wine format [Internal] */
1240 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1242 int fd;
1243 FILE *f;
1244 DOS_FULL_NAME full_name;
1245 void *base;
1246 LPSTR ret = NULL;
1247 struct stat st;
1249 _w95creg *creg;
1250 _w95rgkn *rgkn;
1251 _w95dke *dke, *root_dke;
1253 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1255 /* map the registry into the memory */
1256 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1257 if ((fstat(fd, &st) == -1)) goto error1;
1258 if (!st.st_size) goto error1;
1259 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1261 /* control signature */
1262 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1263 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1264 goto error;
1267 creg = base;
1268 /* load the header (rgkn) */
1269 rgkn = (_w95rgkn*)(creg + 1);
1270 if (rgkn->id != W95_REG_RGKN_ID) {
1271 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1272 goto error;
1274 if (rgkn->root_off != 0x20) {
1275 ERR("rgkn->root_off not 0x20, please report !\n");
1276 goto error;
1278 if (rgkn->last_dke > rgkn->size)
1280 ERR("registry file corrupt! last_dke > size!\n");
1281 goto error;
1283 /* verify last dke */
1284 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1285 if (dke->x1 != 0x80000000)
1286 { /* wrong magic */
1287 ERR("last dke invalid !\n");
1288 goto error;
1290 if (rgkn->size > creg->rgdb_off)
1292 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1293 goto error;
1295 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1296 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1298 ERR("registry file corrupt! invalid root dke !\n");
1299 goto error;
1302 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1303 fprintf(f,"WINE REGISTRY Version 2");
1304 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1305 fclose(f);
1307 error:
1308 if(ret == NULL) {
1309 ERR("Unable to load native win95 registry file %s.\n",fn);
1310 ERR("Please report to a.mohr@mailto.de.\n");
1311 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1314 munmap(base, st.st_size);
1315 error1:
1316 close(fd);
1317 return ret;
1320 /* convert winnt native registry file to wine format [Internal] */
1321 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1323 int fd;
1324 FILE *f;
1325 DOS_FULL_NAME full_name;
1326 void *base;
1327 LPSTR ret = NULL;
1328 struct stat st;
1330 nt_regf *regf;
1331 nt_hbin *hbin;
1332 nt_hbin_sub *hbin_sub;
1333 nt_nk *nk;
1335 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1337 /* map the registry into the memory */
1338 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1339 if ((fstat(fd, &st) == -1)) goto error1;
1340 if (!st.st_size) goto error1;
1341 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1343 /* control signature */
1344 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1345 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1346 goto error;
1349 /* start block */
1350 regf = base;
1352 /* hbin block */
1353 hbin = (nt_hbin*)((char*) base + 0x1000);
1354 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1355 ERR( "hbin block invalid\n");
1356 goto error;
1359 /* hbin_sub block */
1360 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1361 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1362 ERR( "hbin_sub block invalid\n");
1363 goto error;
1366 /* nk block */
1367 nk = (nt_nk*)&(hbin_sub->data[0]);
1368 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1369 ERR( "special nk block not found\n");
1370 goto error;
1373 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1374 fprintf(f,"WINE REGISTRY Version 2");
1375 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1376 fclose(f);
1378 error:
1379 munmap(base,st.st_size);
1380 error1:
1381 close(fd);
1382 return ret;
1385 /* convert native native registry to wine format and load it via server call [Internal] */
1386 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1388 LPSTR tmp = NULL;
1390 switch (reg_type) {
1391 case REG_WINNT:
1392 /* FIXME: following function doesn't really convert yet */
1393 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1394 break;
1395 case REG_WIN95:
1396 tmp = _convert_win95_registry_to_wine_format(fn,level);
1397 break;
1398 case REG_WIN31:
1399 ERR("Don't know how to convert native 3.1 registry yet.\n");
1400 break;
1401 default:
1402 ERR("Unknown registry format parameter (%d)\n",reg_type);
1403 break;
1406 if (tmp != NULL) {
1407 load_wine_registry(hkey,tmp);
1408 TRACE("File %s successfuly converted to %s and loaded to registry.\n",fn,tmp);
1409 unlink(tmp);
1411 else WARN("Unable to convert %s (not exist?)\n",fn);
1412 free(tmp);
1415 /* load all native windows registry files [Internal] */
1416 static void _load_windows_registry( HKEY hkey_users_default )
1418 int reg_type;
1419 char windir[MAX_PATHNAME_LEN];
1420 char path[MAX_PATHNAME_LEN];
1422 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1424 reg_type = _get_reg_type();
1425 switch (reg_type) {
1426 case REG_WINNT: {
1427 HKEY hkey;
1429 /* user specific ntuser.dat */
1430 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1431 strcat(path,"\\ntuser.dat");
1432 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1435 /* default user.dat */
1436 if (hkey_users_default) {
1437 strcpy(path,windir);
1438 strcat(path,"\\system32\\config\\default");
1439 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1443 * FIXME
1444 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1447 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1448 strcpy(path,windir);
1449 strcat(path,"\\system32\\config\\system");
1450 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1451 RegCloseKey(hkey);
1454 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1455 strcpy(path,windir);
1456 strcat(path,"\\system32\\config\\software");
1457 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1458 RegCloseKey(hkey);
1461 strcpy(path,windir);
1462 strcat(path,"\\system32\\config\\sam");
1463 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1465 strcpy(path,windir);
1466 strcat(path,"\\system32\\config\\security");
1467 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1469 /* this key is generated when the nt-core booted successfully */
1470 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1471 break;
1474 case REG_WIN95:
1475 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1477 strcpy(path,windir);
1478 strcat(path,"\\system.dat");
1479 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1481 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1482 /* user specific user.dat */
1483 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1484 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1486 /* default user.dat */
1487 if (hkey_users_default) {
1488 strcpy(path,windir);
1489 strcat(path,"\\user.dat");
1490 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1492 } else {
1493 strcpy(path,windir);
1494 strcat(path,"\\user.dat");
1495 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1497 break;
1499 case REG_WIN31:
1500 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1501 _w31_loadreg();
1502 break;
1504 case REG_DONTLOAD:
1505 TRACE("REG_DONTLOAD\n");
1506 break;
1508 default:
1509 ERR("switch: no match (%d)\n",reg_type);
1510 break;
1515 /* load global registry files (stored in /etc/wine) [Internal] */
1516 static void _load_global_registry(void)
1518 TRACE("(void)\n");
1520 /* Load the global HKU hive directly from sysconfdir */
1521 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1523 /* Load the global machine defaults directly from sysconfdir */
1524 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1527 /* load home registry files (stored in ~/.wine) [Internal] */
1528 static void _load_home_registry( HKEY hkey_users_default )
1530 LPCSTR confdir = get_config_dir();
1531 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1533 strcpy(tmp,confdir);
1534 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1535 load_wine_registry(hkey_users_default,tmp);
1537 strcpy(tmp,confdir);
1538 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1539 load_wine_registry(HKEY_CURRENT_USER,tmp);
1541 strcpy(tmp,confdir);
1542 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1543 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1545 free(tmp);
1548 /* load all registry (native and global and home) */
1549 void SHELL_LoadRegistry( void )
1551 HKEY hkey_users_default;
1553 TRACE("(void)\n");
1555 if (!CLIENT_IsBootThread()) return; /* already loaded */
1557 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1559 ERR("Cannot create HKEY_USERS/.Default\n" );
1560 ExitProcess(1);
1563 _allocate_default_keys();
1564 _set_registry_levels(0,0,0);
1565 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1566 _load_windows_registry( hkey_users_default );
1567 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1568 _load_global_registry();
1569 _set_registry_levels(1,0,0);
1570 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1571 _load_home_registry( hkey_users_default );
1572 _init_registry_saving( hkey_users_default );
1573 RegCloseKey(hkey_users_default);
1576 /***************************************************************************/
1577 /* API FUNCTIONS */
1578 /***************************************************************************/
1580 /******************************************************************************
1581 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1582 * Immediately writes key to registry.
1583 * Only returns after data has been written to disk.
1585 * FIXME: does it really wait until data is written ?
1587 * PARAMS
1588 * hkey [I] Handle of key to write
1590 * RETURNS
1591 * Success: ERROR_SUCCESS
1592 * Failure: Error code
1594 DWORD WINAPI RegFlushKey( HKEY hkey )
1596 FIXME( "(%x): stub\n", hkey );
1597 return ERROR_SUCCESS;
1601 /******************************************************************************
1602 * RegUnLoadKeyA [ADVAPI32.172]
1604 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1606 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1607 return ERROR_SUCCESS;
1611 /******************************************************************************
1612 * RegRestoreKeyW [ADVAPI32.164]
1614 * PARAMS
1615 * hkey [I] Handle of key where restore begins
1616 * lpFile [I] Address of filename containing saved tree
1617 * dwFlags [I] Optional flags
1619 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1621 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1623 /* It seems to do this check before the hkey check */
1624 if (!lpFile || !*lpFile)
1625 return ERROR_INVALID_PARAMETER;
1627 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1629 /* Check for file existence */
1631 return ERROR_SUCCESS;
1635 /******************************************************************************
1636 * RegRestoreKeyA [ADVAPI32.163]
1638 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1640 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1641 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1642 HeapFree( GetProcessHeap(), 0, lpFileW );
1643 return ret;
1647 /******************************************************************************
1648 * RegReplaceKeyA [ADVAPI32.161]
1650 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1651 LPCSTR lpOldFile )
1653 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1654 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1655 return ERROR_SUCCESS;
1663 /* 16-bit functions */
1665 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1666 * some programs. Do not remove those cases. -MM
1668 static inline void fix_win16_hkey( HKEY *hkey )
1670 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1673 /******************************************************************************
1674 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1676 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1678 fix_win16_hkey( &hkey );
1679 return RegEnumKeyA( hkey, index, name, name_len );
1682 /******************************************************************************
1683 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1685 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1687 fix_win16_hkey( &hkey );
1688 return RegOpenKeyA( hkey, name, retkey );
1691 /******************************************************************************
1692 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1694 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1696 fix_win16_hkey( &hkey );
1697 return RegCreateKeyA( hkey, name, retkey );
1700 /******************************************************************************
1701 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1703 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1705 fix_win16_hkey( &hkey );
1706 return RegDeleteKeyA( hkey, name );
1709 /******************************************************************************
1710 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1712 DWORD WINAPI RegCloseKey16( HKEY hkey )
1714 fix_win16_hkey( &hkey );
1715 return RegCloseKey( hkey );
1718 /******************************************************************************
1719 * RegSetValue16 [KERNEL.221] [SHELL.5]
1721 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1723 fix_win16_hkey( &hkey );
1724 return RegSetValueA( hkey, name, type, data, count );
1727 /******************************************************************************
1728 * RegDeleteValue16 [KERNEL.222]
1730 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1732 fix_win16_hkey( &hkey );
1733 return RegDeleteValueA( hkey, name );
1736 /******************************************************************************
1737 * RegEnumValue16 [KERNEL.223]
1739 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1740 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1742 fix_win16_hkey( &hkey );
1743 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1746 /******************************************************************************
1747 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1749 * NOTES
1750 * Is this HACK still applicable?
1752 * HACK
1753 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1754 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1755 * Aldus FH4)
1757 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1759 fix_win16_hkey( &hkey );
1760 if (count) *count &= 0xffff;
1761 return RegQueryValueA( hkey, name, data, count );
1764 /******************************************************************************
1765 * RegQueryValueEx16 [KERNEL.225]
1767 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1768 LPBYTE data, LPDWORD count )
1770 fix_win16_hkey( &hkey );
1771 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1774 /******************************************************************************
1775 * RegSetValueEx16 [KERNEL.226]
1777 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1778 CONST BYTE *data, DWORD count )
1780 fix_win16_hkey( &hkey );
1781 if (!count && (type==REG_SZ)) count = strlen(data);
1782 return RegSetValueExA( hkey, name, reserved, type, data, count );
1785 /******************************************************************************
1786 * RegFlushKey16 [KERNEL.227]
1788 DWORD WINAPI RegFlushKey16( HKEY hkey )
1790 fix_win16_hkey( &hkey );
1791 return RegFlushKey( hkey );