Added more conversion routines (rate conversion is implemented).
[wine.git] / misc / registry.c
blob8ca97551c4733f8687e57a81bfa37b9d26b0c856
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 <limits.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
33 #endif
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/fcntl.h>
37 #include <sys/stat.h>
38 #include <time.h>
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "wine/winbase16.h"
43 #include "winerror.h"
44 #include "file.h"
45 #include "heap.h"
46 #include "debugtools.h"
47 #include "options.h"
48 #include "winreg.h"
49 #include "server.h"
50 #include "services.h"
52 DEFAULT_DEBUG_CHANNEL(reg);
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
57 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
58 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
60 /* relative in ~user/.wine/ : */
61 #define SAVE_CURRENT_USER "user.reg"
62 #define SAVE_DEFAULT_USER "userdef.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
67 static void *xmalloc( size_t size )
69 void *res;
71 res = malloc (size ? size : 1);
72 if (res == NULL) {
73 WARN("Virtual memory exhausted.\n");
74 exit (1);
76 return res;
80 /******************************************************************************
81 * REGISTRY_Init [Internal]
82 * Registry initialisation, allocates some default keys.
84 static void REGISTRY_Init(void) {
85 HKEY hkey;
86 char buf[200];
88 TRACE("(void)\n");
90 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
91 RegCloseKey(hkey);
93 /* This was an Open, but since it is called before the real registries
94 are loaded, it was changed to a Create - MTB 980507*/
95 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
96 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
97 RegCloseKey(hkey);
99 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
100 * CurrentVersion
101 * CurrentBuildNumber
102 * CurrentType
103 * string RegisteredOwner
104 * string RegisteredOrganization
107 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
108 * string SysContact
109 * string SysLocation
110 * SysServices
112 if (-1!=gethostname(buf,200)) {
113 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
114 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
115 RegCloseKey(hkey);
120 /************************ LOAD Registry Function ****************************/
124 /******************************************************************************
125 * _find_or_add_key [Internal]
127 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
129 HKEY subkey;
130 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
131 if (keyname) free( keyname );
132 return subkey;
135 /******************************************************************************
136 * _find_or_add_value [Internal]
138 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
140 RegSetValueExW( hkey, name, 0, type, data, len );
141 if (name) free( name );
142 if (data) free( data );
146 /******************************************************************************
147 * _wine_read_line [Internal]
149 * reads a line including dynamically enlarging the readbuffer and throwing
150 * away comments
152 static int _wine_read_line( FILE *F, char **buf, int *len )
154 char *s,*curread;
155 int mylen,curoff;
157 curread = *buf;
158 mylen = *len;
159 **buf = '\0';
160 while (1) {
161 while (1) {
162 s=fgets(curread,mylen,F);
163 if (s==NULL)
164 return 0; /* EOF */
165 if (NULL==(s=strchr(curread,'\n'))) {
166 /* buffer wasn't large enough */
167 curoff = strlen(*buf);
168 curread = realloc(*buf,*len*2);
169 if(curread == NULL) {
170 WARN("Out of memory");
171 return 0;
173 *buf = curread;
174 curread+= curoff;
175 mylen = *len; /* we filled up the buffer and
176 * got new '*len' bytes to fill
178 *len = *len * 2;
179 } else {
180 *s='\0';
181 break;
184 /* throw away comments */
185 if (**buf=='#' || **buf==';') {
186 curread = *buf;
187 mylen = *len;
188 continue;
190 if (s) /* got end of line */
191 break;
193 return 1;
197 /******************************************************************************
198 * _wine_read_USTRING [Internal]
200 * converts a char* into a UNICODE string (up to a special char)
201 * and returns the position exactly after that string
203 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
205 char *s;
206 LPWSTR ws;
208 /* read up to "=" or "\0" or "\n" */
209 s = buf;
210 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
211 ws = *str;
212 while (*s && (*s!='\n') && (*s!='=')) {
213 if (*s!='\\')
214 *ws++=*((unsigned char*)s++);
215 else {
216 s++;
217 if (!*s) {
218 /* Dangling \ ... may only happen if a registry
219 * write was short. FIXME: What to do?
221 break;
223 if (*s=='\\') {
224 *ws++='\\';
225 s++;
226 continue;
228 if (*s!='u') {
229 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
230 *ws++='\\';
231 *ws++=*s++;
232 } else {
233 char xbuf[5];
234 int wc;
236 s++;
237 memcpy(xbuf,s,4);xbuf[4]='\0';
238 if (!sscanf(xbuf,"%x",&wc))
239 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
240 s+=4;
241 *ws++ =(unsigned short)wc;
245 *ws = 0;
246 return s;
250 /******************************************************************************
251 * _wine_loadsubkey [Internal]
253 * NOTES
254 * It seems like this is returning a boolean. Should it?
256 * RETURNS
257 * Success: 1
258 * Failure: 0
260 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
262 HKEY subkey;
263 int i;
264 char *s;
265 LPWSTR name;
267 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
269 /* Good. We already got a line here ... so parse it */
270 subkey = 0;
271 while (1) {
272 i=0;s=*buf;
273 while (*s=='\t') {
274 s++;
275 i++;
277 if (i>level) {
278 if (!subkey) {
279 WARN("Got a subhierarchy without resp. key?\n");
280 return 0;
282 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
283 if (!_wine_read_line(F,buf,buflen))
284 goto done;
285 continue;
288 /* let the caller handle this line */
289 if (i<level || **buf=='\0')
290 goto done;
292 /* it can be: a value or a keyname. Parse the name first */
293 s=_wine_read_USTRING(s,&name);
295 /* switch() default: hack to avoid gotos */
296 switch (0) {
297 default:
298 if (*s=='\0') {
299 if (subkey) RegCloseKey( subkey );
300 subkey=_find_or_add_key(hkey,name);
301 } else {
302 LPBYTE data;
303 int len,lastmodified,type;
305 if (*s!='=') {
306 WARN("Unexpected character: %c\n",*s);
307 break;
309 s++;
310 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
311 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
312 break;
314 /* skip the 2 , */
315 s=strchr(s,',');s++;
316 s=strchr(s,',');
317 if (!s++) {
318 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
319 break;
321 if (type == REG_SZ || type == REG_EXPAND_SZ) {
322 s=_wine_read_USTRING(s,(LPWSTR*)&data);
323 len = lstrlenW((LPWSTR)data)*2+2;
324 } else {
325 len=strlen(s)/2;
326 data = (LPBYTE)xmalloc(len+1);
327 for (i=0;i<len;i++) {
328 data[i]=0;
329 if (*s>='0' && *s<='9')
330 data[i]=(*s-'0')<<4;
331 if (*s>='a' && *s<='f')
332 data[i]=(*s-'a'+'\xa')<<4;
333 if (*s>='A' && *s<='F')
334 data[i]=(*s-'A'+'\xa')<<4;
335 s++;
336 if (*s>='0' && *s<='9')
337 data[i]|=*s-'0';
338 if (*s>='a' && *s<='f')
339 data[i]|=*s-'a'+'\xa';
340 if (*s>='A' && *s<='F')
341 data[i]|=*s-'A'+'\xa';
342 s++;
345 _find_or_add_value(hkey,name,type,data,len);
348 /* read the next line */
349 if (!_wine_read_line(F,buf,buflen))
350 goto done;
352 done:
353 if (subkey) RegCloseKey( subkey );
354 return 1;
358 /******************************************************************************
359 * _wine_loadsubreg [Internal]
361 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
363 int ver;
364 char *buf;
365 int buflen;
367 buf=xmalloc(10);buflen=10;
368 if (!_wine_read_line(F,&buf,&buflen)) {
369 free(buf);
370 return 0;
372 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
373 free(buf);
374 return 0;
376 if (ver!=1) {
377 if (ver == 2) /* new version */
379 HANDLE file;
380 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
381 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
383 SERVER_START_REQ
385 struct load_registry_request *req = server_alloc_req( sizeof(*req), 0 );
386 req->hkey = hkey;
387 req->file = file;
388 server_call( REQ_LOAD_REGISTRY );
390 SERVER_END_REQ;
391 CloseHandle( file );
393 free( buf );
394 return 1;
396 else
398 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
399 free(buf);
400 return 0;
403 if (!_wine_read_line(F,&buf,&buflen)) {
404 free(buf);
405 return 0;
407 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
408 free(buf);
409 return 0;
411 free(buf);
412 return 1;
416 /******************************************************************************
417 * _wine_loadreg [Internal]
419 static int _wine_loadreg( HKEY hkey, char *fn )
421 FILE *F;
423 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
425 F = fopen(fn,"rb");
426 if (F==NULL) {
427 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
428 return -1;
430 _wine_loadsubreg(F,hkey,fn);
431 fclose(F);
432 return 0;
435 /* NT REGISTRY LOADER */
437 #ifdef HAVE_SYS_MMAN_H
438 # include <sys/mman.h>
439 #endif
441 #ifndef MAP_FAILED
442 #define MAP_FAILED ((LPVOID)-1)
443 #endif
445 #define NT_REG_BLOCK_SIZE 0x1000
447 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
448 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
449 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
450 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
452 /* subblocks of nk */
453 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
454 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
455 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
457 #define NT_REG_KEY_BLOCK_TYPE 0x20
458 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
460 typedef struct
462 DWORD id; /* 0x66676572 'regf'*/
463 DWORD uk1; /* 0x04 */
464 DWORD uk2; /* 0x08 */
465 FILETIME DateModified; /* 0x0c */
466 DWORD uk3; /* 0x14 */
467 DWORD uk4; /* 0x18 */
468 DWORD uk5; /* 0x1c */
469 DWORD uk6; /* 0x20 */
470 DWORD RootKeyBlock; /* 0x24 */
471 DWORD BlockSize; /* 0x28 */
472 DWORD uk7[116];
473 DWORD Checksum; /* at offset 0x1FC */
474 } nt_regf;
476 typedef struct
478 DWORD blocksize;
479 BYTE data[1];
480 } nt_hbin_sub;
482 typedef struct
484 DWORD id; /* 0x6E696268 'hbin' */
485 DWORD off_prev;
486 DWORD off_next;
487 DWORD uk1;
488 DWORD uk2; /* 0x10 */
489 DWORD uk3; /* 0x14 */
490 DWORD uk4; /* 0x18 */
491 DWORD size; /* 0x1C */
492 nt_hbin_sub hbin_sub; /* 0x20 */
493 } nt_hbin;
496 * the value_list consists of offsets to the values (vk)
498 typedef struct
500 WORD SubBlockId; /* 0x00 0x6B6E */
501 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
502 FILETIME writetime; /* 0x04 */
503 DWORD uk1; /* 0x0C */
504 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
505 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
506 DWORD uk8; /* 0x18 */
507 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
508 DWORD uk2; /* 0x20 */
509 DWORD nr_values; /* 0x24 number of values */
510 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
511 DWORD off_sk; /* 0x2c Offset of the sk-Record */
512 DWORD off_class; /* 0x30 Offset of the Class-Name */
513 DWORD uk3; /* 0x34 */
514 DWORD uk4; /* 0x38 */
515 DWORD uk5; /* 0x3c */
516 DWORD uk6; /* 0x40 */
517 DWORD uk7; /* 0x44 */
518 WORD name_len; /* 0x48 name-length */
519 WORD class_len; /* 0x4a class-name length */
520 char name[1]; /* 0x4c key-name */
521 } nt_nk;
523 typedef struct
525 DWORD off_nk; /* 0x00 */
526 DWORD name; /* 0x04 */
527 } hash_rec;
529 typedef struct
531 WORD id; /* 0x00 0x666c */
532 WORD nr_keys; /* 0x06 */
533 hash_rec hash_rec[1];
534 } nt_lf;
537 list of subkeys without hash
539 li --+-->nk
541 +-->nk
543 typedef struct
545 WORD id; /* 0x00 0x696c */
546 WORD nr_keys;
547 DWORD off_nk[1];
548 } nt_li;
551 this is a intermediate node
553 ri --+-->li--+-->nk
555 | +-->nk
557 +-->li--+-->nk
559 +-->nk
561 typedef struct
563 WORD id; /* 0x00 0x6972 */
564 WORD nr_li; /* 0x02 number off offsets */
565 DWORD off_li[1]; /* 0x04 points to li */
566 } nt_ri;
568 typedef struct
570 WORD id; /* 0x00 'vk' */
571 WORD nam_len;
572 DWORD data_len;
573 DWORD data_off;
574 DWORD type;
575 WORD flag;
576 WORD uk1;
577 char name[1];
578 } nt_vk;
580 LPSTR _strdupnA( LPCSTR str, int len )
582 LPSTR ret;
584 if (!str) return NULL;
585 ret = xmalloc( len + 1 );
586 memcpy( ret, str, len );
587 ret[len] = 0x00;
588 return ret;
591 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
592 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
593 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
597 * gets a value
599 * vk->flag:
600 * 0 value is a default value
601 * 1 the value has a name
603 * vk->data_len
604 * len of the whole data block
605 * - reg_sz (unicode)
606 * bytes including the terminating \0 = 2*(number_of_chars+1)
607 * - reg_dword, reg_binary:
608 * if highest bit of data_len is set data_off contains the value
610 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
612 WCHAR name [256];
613 DWORD len, ret;
614 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
616 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
618 if (!(len = MultiByteToWideChar( CP_ACP, 0, vk->name, vk->nam_len, name, 256 )) && vk->nam_len)
620 ERR("name too large '%.*s' (%d)\n", vk->nam_len, vk->name, vk->nam_len );
621 return FALSE;
623 name[len] = 0;
625 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
626 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
627 (vk->data_len & 0x7fffffff) );
628 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
629 return TRUE;
630 error:
631 ERR("unknown block found (0x%04x), please report!\n", vk->id);
632 return FALSE;
636 * get the subkeys
638 * this structure contains the hash of a keyname and points to all
639 * subkeys
641 * exception: if the id is 'il' there are no hash values and every
642 * dword is a offset
644 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
646 int i;
648 if (lf->id == NT_REG_HASH_BLOCK_ID)
650 if (subkeys != lf->nr_keys) goto error1;
652 for (i=0; i<lf->nr_keys; i++)
654 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
657 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
659 nt_li * li = (nt_li*)lf;
660 if (subkeys != li->nr_keys) goto error1;
662 for (i=0; i<li->nr_keys; i++)
664 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
667 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
669 nt_ri * ri = (nt_ri*)lf;
670 int li_subkeys = 0;
672 /* count all subkeys */
673 for (i=0; i<ri->nr_li; i++)
675 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
676 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
677 li_subkeys += li->nr_keys;
680 /* check number */
681 if (subkeys != li_subkeys) goto error1;
683 /* loop through the keys */
684 for (i=0; i<ri->nr_li; i++)
686 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
687 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
690 else
692 goto error2;
694 return TRUE;
696 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
697 return TRUE;
699 error1: ERR("registry file corrupt! (inconsistent number of subkeys)\n");
700 return FALSE;
702 error: ERR("error reading lf block\n");
703 return FALSE;
706 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
708 char * name;
709 int i;
710 DWORD * vl;
711 HKEY subkey = hkey;
713 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
715 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
716 goto error;
719 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
720 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
722 ERR("registry file corrupt!\n");
723 goto error;
726 /* create the new key */
727 if(level <= 0)
729 name = _strdupnA( nk->name, nk->name_len);
730 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
731 free(name);
734 /* loop through the subkeys */
735 if (nk->nr_subkeys)
737 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
738 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
741 /* loop trough the value list */
742 vl = (DWORD *)(base+nk->valuelist_off+4);
743 for (i=0; i<nk->nr_values; i++)
745 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
746 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
749 RegCloseKey(subkey);
750 return TRUE;
752 error1: RegCloseKey(subkey);
753 error: return FALSE;
756 /* end nt loader */
758 /* windows 95 registry loader */
760 /* SECTION 1: main header
762 * once at offset 0
764 #define W95_REG_CREG_ID 0x47455243
766 typedef struct
768 DWORD id; /* "CREG" = W95_REG_CREG_ID */
769 DWORD version; /* ???? 0x00010000 */
770 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
771 DWORD uk2; /* 0x0c */
772 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
773 WORD uk3;
774 DWORD uk[3];
775 /* rgkn */
776 } _w95creg;
778 /* SECTION 2: Directory information (tree structure)
780 * once on offset 0x20
782 * structure: [rgkn][dke]* (repeat till last_dke is reached)
784 #define W95_REG_RGKN_ID 0x4e4b4752
786 typedef struct
788 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
789 DWORD size; /* Size of the RGKN-block */
790 DWORD root_off; /* Rel. Offset of the root-record */
791 DWORD last_dke; /* Offset to last DKE ? */
792 DWORD uk[4];
793 } _w95rgkn;
795 /* Disk Key Entry Structure
797 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
798 * hive itself. It looks the same like other keys. Even the ID-number can
799 * be any value.
801 * The "hash"-value is a value representing the key's name. Windows will not
802 * search for the name, but for a matching hash-value. if it finds one, it
803 * will compare the actual string info, otherwise continue with the next key.
804 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
805 * of the string which are smaller than 0x80 (128) to this D-Word.
807 * If you want to modify key names, also modify the hash-values, since they
808 * cannot be found again (although they would be displayed in REGEDIT)
809 * End of list-pointers are filled with 0xFFFFFFFF
811 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
812 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
813 * structure) and reading another RGDB_section.
815 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
816 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
817 * The remaining space between last_dke and the offset calculated from
818 * rgkn->size seems to be free for use for more dke:s.
819 * So it seems if more dke:s are added, they are added to that space and
820 * last_dke is grown, and in case that "free" space is out, the space
821 * gets grown and rgkn->size gets adjusted.
823 * there is a one to one relationship between dke and dkh
825 /* key struct, once per key */
826 typedef struct
828 DWORD x1; /* Free entry indicator(?) */
829 DWORD hash; /* sum of bytes of keyname */
830 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
831 DWORD prevlvl; /* offset of previous key */
832 DWORD nextsub; /* offset of child key */
833 DWORD next; /* offset of sibling key */
834 WORD nrLS; /* id inside the rgdb block */
835 WORD nrMS; /* number of the rgdb block */
836 } _w95dke;
838 /* SECTION 3: key information, values and data
840 * structure:
841 * section: [blocks]* (repeat creg->rgdb_num times)
842 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
843 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
845 * An interesting relationship exists in RGDB_section. The DWORD value
846 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
847 * I have no idea at the moment what this means. (Kevin Cozens)
850 /* block header, once per block */
851 #define W95_REG_RGDB_ID 0x42444752
853 typedef struct
855 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
856 DWORD size; /* 0x04 */
857 DWORD uk1; /* 0x08 */
858 DWORD uk2; /* 0x0c */
859 DWORD uk3; /* 0x10 */
860 DWORD uk4; /* 0x14 */
861 DWORD uk5; /* 0x18 */
862 DWORD uk6; /* 0x1c */
863 /* dkh */
864 } _w95rgdb;
866 /* Disk Key Header structure (RGDB part), once per key */
867 typedef struct
869 DWORD nextkeyoff; /* 0x00 offset to next dkh */
870 WORD nrLS; /* 0x04 id inside the rgdb block */
871 WORD nrMS; /* 0x06 number of the rgdb block */
872 DWORD bytesused; /* 0x08 */
873 WORD keynamelen; /* 0x0c len of name */
874 WORD values; /* 0x0e number of values */
875 DWORD xx1; /* 0x10 */
876 char name[1]; /* 0x14 */
877 /* dkv */ /* 0x14 + keynamelen */
878 } _w95dkh;
880 /* Disk Key Value structure, once per value */
881 typedef struct
883 DWORD type; /* 0x00 */
884 DWORD x1; /* 0x04 */
885 WORD valnamelen; /* 0x08 length of name, 0 is default key */
886 WORD valdatalen; /* 0x0A length of data */
887 char name[1]; /* 0x0c */
888 /* raw data */ /* 0x0c + valnamelen */
889 } _w95dkv;
891 /******************************************************************************
892 * _w95_lookup_dkh [Internal]
894 * seeks the dkh belonging to a dke
896 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
898 _w95rgdb * rgdb;
899 _w95dkh * dkh;
900 int i;
902 /* get the beginning of the rgdb datastore */
903 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
905 /* check: requested block < last_block) */
906 if (creg->rgdb_num <= nrMS)
908 ERR("registry file corrupt! requested block no. beyond end.\n");
909 goto error;
912 /* find the right block */
913 for(i=0; i<nrMS ;i++)
915 if(rgdb->id != W95_REG_RGDB_ID) /* check the magic */
917 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
918 goto error;
920 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
923 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
927 if(nrLS==dkh->nrLS ) return dkh;
928 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
929 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
931 error: return NULL;
934 /******************************************************************************
935 * _w95_parse_dkv [Internal]
937 static int _w95_parse_dkv (
938 HKEY hkey,
939 _w95dkh * dkh,
940 int nrLS,
941 int nrMS )
943 _w95dkv * dkv;
944 int i;
945 DWORD ret;
946 char * name;
948 /* first value block */
949 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
951 /* loop trought the values */
952 for (i=0; i< dkh->values; i++)
954 name = _strdupnA(dkv->name, dkv->valnamelen);
955 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
956 if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
957 free (name);
959 /* next value */
960 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
962 return TRUE;
965 /******************************************************************************
966 * _w95_parse_dke [Internal]
968 static int _w95_parse_dke(
969 HKEY hkey,
970 _w95creg * creg,
971 _w95rgkn *rgkn,
972 _w95dke * dke,
973 int level )
975 _w95dkh * dkh;
976 HKEY hsubkey = hkey;
977 char * name;
978 int ret = FALSE;
980 /* special root key */
981 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
983 /* parse the one subkey */
984 if (dke->nextsub != 0xffffffff)
986 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
988 /* has no sibling keys */
989 goto error;
992 /* search subblock */
993 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
995 fprintf(stderr, "dke pointing to missing dkh !\n");
996 goto error;
999 if ( level <= 0 )
1001 /* walk sibling keys */
1002 if (dke->next != 0xffffffff )
1004 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1007 /* create subkey and insert values */
1008 name = _strdupnA( dkh->name, dkh->keynamelen);
1009 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1010 free(name);
1011 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1014 /* next sub key */
1015 if (dke->nextsub != 0xffffffff)
1017 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1020 ret = TRUE;
1021 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1022 error: return ret;
1024 /* end windows 95 loader */
1026 /******************************************************************************
1027 * NativeRegLoadKey [Internal]
1029 * Loads a native registry file (win95/nt)
1030 * hkey root key
1031 * fn filename
1032 * level number of levels to cut away (eg. ".Default" in user.dat)
1034 * this function intentionally uses unix file functions to make it possible
1035 * to move it to a seperate registry helper programm
1037 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1039 int fd = 0;
1040 struct stat st;
1041 DOS_FULL_NAME full_name;
1042 int ret = FALSE;
1043 void * base;
1044 char *filetype = "unknown";
1046 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1048 /* map the registry into the memory */
1049 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1050 if ((fstat(fd, &st) == -1)) goto error;
1051 if (!st.st_size) goto error;
1052 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1054 switch (*(LPDWORD)base)
1056 /* windows 95 'CREG' */
1057 case W95_REG_CREG_ID:
1059 _w95creg *creg;
1060 _w95rgkn *rgkn;
1061 _w95dke *dke, *root_dke;
1062 creg = base;
1063 filetype = "win95";
1064 TRACE("Loading %s registry '%s' '%s'\n", filetype, fn, full_name.long_name);
1066 /* load the header (rgkn) */
1067 rgkn = (_w95rgkn*)(creg + 1);
1068 if (rgkn->id != W95_REG_RGKN_ID)
1070 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1071 goto error1;
1073 if (rgkn->root_off != 0x20)
1075 ERR("rgkn->root_off not 0x20, please report !\n");
1076 goto error1;
1078 if (rgkn->last_dke > rgkn->size)
1080 ERR("registry file corrupt! last_dke > size!\n");
1081 goto error1;
1083 /* verify last dke */
1084 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1085 if (dke->x1 != 0x80000000)
1086 { /* wrong magic */
1087 ERR("last dke invalid !\n");
1088 goto error1;
1090 if (rgkn->size > creg->rgdb_off)
1092 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1093 goto error1;
1095 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1096 if ( (root_dke->prevlvl != 0xffffffff)
1097 || (root_dke->next != 0xffffffff) )
1099 ERR("registry file corrupt! invalid root dke !\n");
1100 goto error1;
1103 ret = _w95_parse_dke(hkey, creg, rgkn, root_dke, level);
1105 break;
1106 /* nt 'regf'*/
1107 case NT_REG_HEADER_BLOCK_ID:
1109 nt_regf * regf;
1110 nt_hbin * hbin;
1111 nt_hbin_sub * hbin_sub;
1112 nt_nk* nk;
1114 filetype = "NT";
1115 TRACE("Loading %s registry '%s' '%s'\n", filetype, fn, full_name.long_name);
1117 /* start block */
1118 regf = base;
1120 /* hbin block */
1121 hbin = (nt_hbin*)((char*) base + 0x1000);
1122 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1124 ERR( "hbin block invalid\n");
1125 goto error1;
1128 /* hbin_sub block */
1129 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1130 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1132 ERR( "hbin_sub block invalid\n");
1133 goto error1;
1136 /* nk block */
1137 nk = (nt_nk*)&(hbin_sub->data[0]);
1138 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1140 ERR( "special nk block not found\n");
1141 goto error1;
1144 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1146 break;
1147 default:
1149 ERR("unknown registry signature !\n");
1150 goto error1;
1153 error1: if(!ret)
1155 ERR("error loading %s registry file %s\n",
1156 filetype, full_name.long_name);
1157 if (!strcmp(filetype, "win95"))
1158 ERR("Please report to a.mohr@mailto.de.\n");
1159 ERR("Make a backup of the file, run a good reg cleaner program and try again !\n");
1161 munmap(base, st.st_size);
1162 error: close(fd);
1163 return ret;
1166 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1168 reghack - windows 3.11 registry data format demo program.
1170 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1171 a combined hash table and tree description, and finally a text table.
1173 The header is obvious from the struct header. The taboff1 and taboff2
1174 fields are always 0x20, and their usage is unknown.
1176 The 8-byte entry table has various entry types.
1178 tabent[0] is a root index. The second word has the index of the root of
1179 the directory.
1180 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1181 the index of the key/value that has that hash. Data with the same
1182 hash value are on a circular list. The other three words in the
1183 hash entry are always zero.
1184 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1185 entry: dirent and keyent/valent. They are identified by context.
1186 tabent[freeidx] is the first free entry. The first word in a free entry
1187 is the index of the next free entry. The last has 0 as a link.
1188 The other three words in the free list are probably irrelevant.
1190 Entries in text table are preceeded by a word at offset-2. This word
1191 has the value (2*index)+1, where index is the referring keyent/valent
1192 entry in the table. I have no suggestion for the 2* and the +1.
1193 Following the word, there are N bytes of data, as per the keyent/valent
1194 entry length. The offset of the keyent/valent entry is from the start
1195 of the text table to the first data byte.
1197 This information is not available from Microsoft. The data format is
1198 deduced from the reg.dat file by me. Mistakes may
1199 have been made. I claim no rights and give no guarantees for this program.
1201 Tor Sjøwall, tor@sn.no
1204 /* reg.dat header format */
1205 struct _w31_header {
1206 char cookie[8]; /* 'SHCC3.10' */
1207 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1208 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1209 unsigned long tabcnt; /* number of entries in index table */
1210 unsigned long textoff; /* offset of text part */
1211 unsigned long textsize; /* byte size of text part */
1212 unsigned short hashsize; /* hash size */
1213 unsigned short freeidx; /* free index */
1216 /* generic format of table entries */
1217 struct _w31_tabent {
1218 unsigned short w0, w1, w2, w3;
1221 /* directory tabent: */
1222 struct _w31_dirent {
1223 unsigned short sibling_idx; /* table index of sibling dirent */
1224 unsigned short child_idx; /* table index of child dirent */
1225 unsigned short key_idx; /* table index of key keyent */
1226 unsigned short value_idx; /* table index of value valent */
1229 /* key tabent: */
1230 struct _w31_keyent {
1231 unsigned short hash_idx; /* hash chain index for string */
1232 unsigned short refcnt; /* reference count */
1233 unsigned short length; /* length of string */
1234 unsigned short string_off; /* offset of string in text table */
1237 /* value tabent: */
1238 struct _w31_valent {
1239 unsigned short hash_idx; /* hash chain index for string */
1240 unsigned short refcnt; /* reference count */
1241 unsigned short length; /* length of string */
1242 unsigned short string_off; /* offset of string in text table */
1245 /* recursive helper function to display a directory tree */
1246 void
1247 __w31_dumptree( unsigned short idx,
1248 unsigned char *txt,
1249 struct _w31_tabent *tab,
1250 struct _w31_header *head,
1251 HKEY hkey,
1252 time_t lastmodified,
1253 int level
1255 struct _w31_dirent *dir;
1256 struct _w31_keyent *key;
1257 struct _w31_valent *val;
1258 HKEY subkey = 0;
1259 static char tail[400];
1261 while (idx!=0) {
1262 dir=(struct _w31_dirent*)&tab[idx];
1264 if (dir->key_idx) {
1265 key = (struct _w31_keyent*)&tab[dir->key_idx];
1267 memcpy(tail,&txt[key->string_off],key->length);
1268 tail[key->length]='\0';
1269 /* all toplevel entries AND the entries in the
1270 * toplevel subdirectory belong to \SOFTWARE\Classes
1272 if (!level && !strcmp(tail,".classes")) {
1273 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1274 idx=dir->sibling_idx;
1275 continue;
1277 if (subkey) RegCloseKey( subkey );
1278 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1279 /* only add if leaf node or valued node */
1280 if (dir->value_idx!=0||dir->child_idx==0) {
1281 if (dir->value_idx) {
1282 val=(struct _w31_valent*)&tab[dir->value_idx];
1283 memcpy(tail,&txt[val->string_off],val->length);
1284 tail[val->length]='\0';
1285 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1288 } else {
1289 TRACE("strange: no directory key name, idx=%04x\n", idx);
1291 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1292 idx=dir->sibling_idx;
1294 if (subkey) RegCloseKey( subkey );
1298 /******************************************************************************
1299 * _w31_loadreg [Internal]
1301 void _w31_loadreg(void) {
1302 HFILE hf;
1303 struct _w31_header head;
1304 struct _w31_tabent *tab;
1305 unsigned char *txt;
1306 int len;
1307 OFSTRUCT ofs;
1308 BY_HANDLE_FILE_INFORMATION hfinfo;
1309 time_t lastmodified;
1311 TRACE("(void)\n");
1313 hf = OpenFile("reg.dat",&ofs,OF_READ);
1314 if (hf==HFILE_ERROR)
1315 return;
1317 /* read & dump header */
1318 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1319 ERR("reg.dat is too short.\n");
1320 _lclose(hf);
1321 return;
1323 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1324 ERR("reg.dat has bad signature.\n");
1325 _lclose(hf);
1326 return;
1329 len = head.tabcnt * sizeof(struct _w31_tabent);
1330 /* read and dump index table */
1331 tab = xmalloc(len);
1332 if (len!=_lread(hf,tab,len)) {
1333 ERR("couldn't read %d bytes.\n",len);
1334 free(tab);
1335 _lclose(hf);
1336 return;
1339 /* read text */
1340 txt = xmalloc(head.textsize);
1341 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1342 ERR("couldn't seek to textblock.\n");
1343 free(tab);
1344 free(txt);
1345 _lclose(hf);
1346 return;
1348 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1349 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1350 free(tab);
1351 free(txt);
1352 _lclose(hf);
1353 return;
1356 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1357 ERR("GetFileInformationByHandle failed?.\n");
1358 free(tab);
1359 free(txt);
1360 _lclose(hf);
1361 return;
1363 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1364 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1365 free(tab);
1366 free(txt);
1367 _lclose(hf);
1368 return;
1372 static void save_at_exit( HKEY hkey, const char *path )
1374 const char *confdir = get_config_dir();
1375 size_t len = strlen(confdir) + strlen(path) + 2;
1376 if (len > REQUEST_MAX_VAR_SIZE)
1378 ERR( "config dir '%s' too long\n", confdir );
1379 return;
1381 SERVER_START_REQ
1383 struct save_registry_atexit_request *req = server_alloc_req( sizeof(*req), len );
1384 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1385 req->hkey = hkey;
1386 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1388 SERVER_END_REQ;
1391 /* configure save files and start the periodic saving timer */
1392 static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
1394 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1395 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1397 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1398 SERVER_START_REQ
1400 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1401 req->current = 1;
1402 req->saving = !all;
1403 req->period = period * 1000;
1404 server_call( REQ_SET_REGISTRY_LEVELS );
1406 SERVER_END_REQ;
1408 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1410 save_at_exit( HKEY_CURRENT_USER, SAVE_CURRENT_USER );
1411 save_at_exit( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE );
1412 save_at_exit( hkey_users_default, SAVE_DEFAULT_USER );
1417 /**********************************************************************************
1418 * SetLoadLevel [Internal]
1420 * set level to 0 for loading system files
1421 * set level to 1 for loading user files
1423 static void SetLoadLevel(int level)
1425 SERVER_START_REQ
1427 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1429 req->current = level;
1430 req->saving = 0;
1431 req->period = 0;
1432 server_call( REQ_SET_REGISTRY_LEVELS );
1434 SERVER_END_REQ;
1437 /**********************************************************************************
1438 * SHELL_LoadRegistry [Internal]
1440 #define REG_DONTLOAD -1
1441 #define REG_WIN31 0
1442 #define REG_WIN95 1
1443 #define REG_WINNT 2
1445 void SHELL_LoadRegistry( void )
1447 HKEY hkey;
1448 char windir[MAX_PATHNAME_LEN];
1449 char path[MAX_PATHNAME_LEN];
1450 int systemtype = REG_WIN31;
1451 HKEY hkey_users_default;
1453 TRACE("(void)\n");
1455 if (!CLIENT_IsBootThread()) return; /* already loaded */
1457 REGISTRY_Init();
1458 SetLoadLevel(0);
1460 if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default))
1461 hkey_users_default = 0;
1463 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1465 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1467 /* test %windir%/system32/config/system --> winnt */
1468 strcpy(path, windir);
1469 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1470 if(GetFileAttributesA(path) != -1)
1472 systemtype = REG_WINNT;
1474 else
1476 /* test %windir%/system.dat --> win95 */
1477 strcpy(path, windir);
1478 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1479 if(GetFileAttributesA(path) != -1)
1481 systemtype = REG_WIN95;
1485 if ((systemtype==REG_WINNT)
1486 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1488 MESSAGE("When you are running with a native NT directory specify\n");
1489 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1490 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1491 systemtype = REG_DONTLOAD;
1494 else
1496 /* only wine registry */
1497 systemtype = REG_DONTLOAD;
1500 switch (systemtype)
1502 case REG_WIN31:
1503 _w31_loadreg();
1504 break;
1506 case REG_WIN95:
1507 /* Load windows 95 entries */
1508 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1510 strcpy(path, windir);
1511 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1512 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1514 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1516 /* user specific user.dat */
1517 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1518 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1520 MESSAGE("can't load win95 user-registry %s\n", path);
1521 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1523 /* default user.dat */
1524 if (hkey_users_default)
1526 strcpy(path, windir);
1527 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1528 NativeRegLoadKey(hkey_users_default, path, 1);
1531 else
1533 /* global user.dat */
1534 strcpy(path, windir);
1535 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1536 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1538 break;
1540 case REG_WINNT:
1541 /* default user.dat */
1542 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1544 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1545 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1547 MESSAGE("can't load NT user-registry %s\n", path);
1548 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1552 /* default user.dat */
1553 if (hkey_users_default)
1555 strcpy(path, windir);
1556 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1557 NativeRegLoadKey(hkey_users_default, path, 1);
1561 * FIXME
1562 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1565 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1567 strcpy(path, windir);
1568 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1569 NativeRegLoadKey(hkey, path, 1);
1570 RegCloseKey(hkey);
1573 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1575 strcpy(path, windir);
1576 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1577 NativeRegLoadKey(hkey, path, 1);
1578 RegCloseKey(hkey);
1581 strcpy(path, windir);
1582 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1583 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1585 strcpy(path, windir);
1586 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1587 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1589 /* this key is generated when the nt-core booted successfully */
1590 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1591 RegCloseKey(hkey);
1592 break;
1593 } /* switch */
1595 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1598 * Load the global HKU hive directly from sysconfdir
1600 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1603 * Load the global machine defaults directly from sysconfdir
1605 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1608 SetLoadLevel(1);
1611 * Load the user saved registries
1613 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1615 const char *confdir = get_config_dir();
1616 int len = strlen(confdir) + 20;
1617 char *fn = path;
1619 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1621 * Load user's personal versions of global HKU/.Default keys
1623 if (fn)
1625 char *str;
1626 strcpy( fn, confdir );
1627 str = fn + strlen(fn);
1628 *str++ = '/';
1630 /* try to load HKU\.Default key only */
1631 strcpy( str, SAVE_DEFAULT_USER );
1632 if (_wine_loadreg( hkey_users_default, fn ))
1634 /* if not found load old file containing both HKU\.Default and HKU\user */
1635 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1636 _wine_loadreg( HKEY_USERS, fn );
1639 strcpy( str, SAVE_CURRENT_USER );
1640 _wine_loadreg( HKEY_CURRENT_USER, fn );
1642 strcpy( str, SAVE_LOCAL_MACHINE );
1643 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1645 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1648 SHELL_InitRegistrySaving( hkey_users_default );
1649 RegCloseKey( hkey_users_default );
1652 /********************* API FUNCTIONS ***************************************/
1657 /******************************************************************************
1658 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1659 * Immediately writes key to registry.
1660 * Only returns after data has been written to disk.
1662 * FIXME: does it really wait until data is written ?
1664 * PARAMS
1665 * hkey [I] Handle of key to write
1667 * RETURNS
1668 * Success: ERROR_SUCCESS
1669 * Failure: Error code
1671 DWORD WINAPI RegFlushKey( HKEY hkey )
1673 FIXME( "(%x): stub\n", hkey );
1674 return ERROR_SUCCESS;
1677 /******************************************************************************
1678 * RegConnectRegistryW [ADVAPI32.128]
1680 * PARAMS
1681 * lpMachineName [I] Address of name of remote computer
1682 * hHey [I] Predefined registry handle
1683 * phkResult [I] Address of buffer for remote registry handle
1685 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1686 LPHKEY phkResult )
1688 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1690 if (!lpMachineName || !*lpMachineName) {
1691 /* Use the local machine name */
1692 return RegOpenKey16( hKey, "", phkResult );
1695 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1696 return ERROR_BAD_NETPATH;
1700 /******************************************************************************
1701 * RegConnectRegistryA [ADVAPI32.127]
1703 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1705 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1706 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1707 HeapFree( GetProcessHeap(), 0, machineW );
1708 return ret;
1712 /******************************************************************************
1713 * RegGetKeySecurity [ADVAPI32.144]
1714 * Retrieves a copy of security descriptor protecting the registry key
1716 * PARAMS
1717 * hkey [I] Open handle of key to set
1718 * SecurityInformation [I] Descriptor contents
1719 * pSecurityDescriptor [O] Address of descriptor for key
1720 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1722 * RETURNS
1723 * Success: ERROR_SUCCESS
1724 * Failure: Error code
1726 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1727 SECURITY_INFORMATION SecurityInformation,
1728 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1729 LPDWORD lpcbSecurityDescriptor )
1731 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1732 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1734 /* FIXME: Check for valid SecurityInformation values */
1736 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1737 return ERROR_INSUFFICIENT_BUFFER;
1739 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1740 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1742 return ERROR_SUCCESS;
1746 /******************************************************************************
1747 * RegNotifyChangeKeyValue [ADVAPI32.???]
1749 * PARAMS
1750 * hkey [I] Handle of key to watch
1751 * fWatchSubTree [I] Flag for subkey notification
1752 * fdwNotifyFilter [I] Changes to be reported
1753 * hEvent [I] Handle of signaled event
1754 * fAsync [I] Flag for asynchronous reporting
1756 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1757 DWORD fdwNotifyFilter, HANDLE hEvent,
1758 BOOL fAsync )
1760 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1761 hEvent,fAsync);
1762 return ERROR_SUCCESS;
1766 /******************************************************************************
1767 * RegUnLoadKeyW [ADVAPI32.173]
1769 * PARAMS
1770 * hkey [I] Handle of open key
1771 * lpSubKey [I] Address of name of subkey to unload
1773 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1775 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1776 return ERROR_SUCCESS;
1780 /******************************************************************************
1781 * RegUnLoadKeyA [ADVAPI32.172]
1783 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1785 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1786 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1787 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1788 return ret;
1792 /******************************************************************************
1793 * RegSetKeySecurity [ADVAPI32.167]
1795 * PARAMS
1796 * hkey [I] Open handle of key to set
1797 * SecurityInfo [I] Descriptor contents
1798 * pSecurityDesc [I] Address of descriptor for key
1800 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1801 PSECURITY_DESCRIPTOR pSecurityDesc )
1803 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1805 /* It seems to perform this check before the hkey check */
1806 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1807 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1808 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1809 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1810 /* Param OK */
1811 } else
1812 return ERROR_INVALID_PARAMETER;
1814 if (!pSecurityDesc)
1815 return ERROR_INVALID_PARAMETER;
1817 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1819 return ERROR_SUCCESS;
1823 /******************************************************************************
1824 * RegRestoreKeyW [ADVAPI32.164]
1826 * PARAMS
1827 * hkey [I] Handle of key where restore begins
1828 * lpFile [I] Address of filename containing saved tree
1829 * dwFlags [I] Optional flags
1831 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1833 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1835 /* It seems to do this check before the hkey check */
1836 if (!lpFile || !*lpFile)
1837 return ERROR_INVALID_PARAMETER;
1839 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1841 /* Check for file existence */
1843 return ERROR_SUCCESS;
1847 /******************************************************************************
1848 * RegRestoreKeyA [ADVAPI32.163]
1850 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1852 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1853 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1854 HeapFree( GetProcessHeap(), 0, lpFileW );
1855 return ret;
1859 /******************************************************************************
1860 * RegReplaceKeyW [ADVAPI32.162]
1862 * PARAMS
1863 * hkey [I] Handle of open key
1864 * lpSubKey [I] Address of name of subkey
1865 * lpNewFile [I] Address of filename for file with new data
1866 * lpOldFile [I] Address of filename for backup file
1868 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1869 LPCWSTR lpOldFile )
1871 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1872 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1873 return ERROR_SUCCESS;
1877 /******************************************************************************
1878 * RegReplaceKeyA [ADVAPI32.161]
1880 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1881 LPCSTR lpOldFile )
1883 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1884 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1885 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1886 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1887 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1888 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1889 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1890 return ret;
1898 /* 16-bit functions */
1900 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1901 * some programs. Do not remove those cases. -MM
1903 static inline void fix_win16_hkey( HKEY *hkey )
1905 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1908 /******************************************************************************
1909 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1911 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1913 fix_win16_hkey( &hkey );
1914 return RegEnumKeyA( hkey, index, name, name_len );
1917 /******************************************************************************
1918 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1920 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1922 fix_win16_hkey( &hkey );
1923 return RegOpenKeyA( hkey, name, retkey );
1926 /******************************************************************************
1927 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1929 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1931 fix_win16_hkey( &hkey );
1932 return RegCreateKeyA( hkey, name, retkey );
1935 /******************************************************************************
1936 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1938 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1940 fix_win16_hkey( &hkey );
1941 return RegDeleteKeyA( hkey, name );
1944 /******************************************************************************
1945 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1947 DWORD WINAPI RegCloseKey16( HKEY hkey )
1949 fix_win16_hkey( &hkey );
1950 return RegCloseKey( hkey );
1953 /******************************************************************************
1954 * RegSetValue16 [KERNEL.221] [SHELL.5]
1956 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1958 fix_win16_hkey( &hkey );
1959 return RegSetValueA( hkey, name, type, data, count );
1962 /******************************************************************************
1963 * RegDeleteValue16 [KERNEL.222]
1965 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1967 fix_win16_hkey( &hkey );
1968 return RegDeleteValueA( hkey, name );
1971 /******************************************************************************
1972 * RegEnumValue16 [KERNEL.223]
1974 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1975 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1977 fix_win16_hkey( &hkey );
1978 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1981 /******************************************************************************
1982 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1984 * NOTES
1985 * Is this HACK still applicable?
1987 * HACK
1988 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1989 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1990 * Aldus FH4)
1992 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1994 fix_win16_hkey( &hkey );
1995 if (count) *count &= 0xffff;
1996 return RegQueryValueA( hkey, name, data, count );
1999 /******************************************************************************
2000 * RegQueryValueEx16 [KERNEL.225]
2002 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2003 LPBYTE data, LPDWORD count )
2005 fix_win16_hkey( &hkey );
2006 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2009 /******************************************************************************
2010 * RegSetValueEx16 [KERNEL.226]
2012 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2013 CONST BYTE *data, DWORD count )
2015 fix_win16_hkey( &hkey );
2016 return RegSetValueExA( hkey, name, reserved, type, data, count );