Follow symlinks when saving registry.
[wine/multimedia.git] / misc / registry.c
blob6ec0a0d1e9240b22fbb90d3b375ff6b44e84c9c6
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 <assert.h>
39 #include <time.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wine/winbase16.h"
43 #include "wine/winestring.h"
44 #include "winerror.h"
45 #include "file.h"
46 #include "heap.h"
47 #include "debugtools.h"
48 #include "options.h"
49 #include "winreg.h"
50 #include "server.h"
51 #include "services.h"
53 DEFAULT_DEBUG_CHANNEL(reg);
55 static void REGISTRY_Init(void);
56 /* FIXME: following defines should be configured global ... */
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
70 static void *xmalloc( size_t size )
72 void *res;
74 res = malloc (size ? size : 1);
75 if (res == NULL) {
76 WARN("Virtual memory exhausted.\n");
77 exit (1);
79 return res;
83 * QUESTION
84 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
85 * If so, can we remove them?
86 * ANSWER
87 * No, the memory handling functions are called very often in here,
88 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
89 * loading 100 times slower. -MM
91 static LPWSTR strdupA2W(LPCSTR src)
93 if(src) {
94 LPWSTR dest=xmalloc(2*strlen(src)+2);
95 lstrcpyAtoW(dest,src);
96 return dest;
98 return NULL;
101 LPWSTR strcvtA2W(LPCSTR src, int nchars)
104 LPWSTR dest = xmalloc (2 * nchars + 2);
106 lstrcpynAtoW(dest,src,nchars+1);
107 return dest;
112 /******************************************************************************
113 * REGISTRY_Init [Internal]
114 * Registry initialisation, allocates some default keys.
116 static void REGISTRY_Init(void) {
117 HKEY hkey;
118 char buf[200];
120 TRACE("(void)\n");
122 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
123 RegCloseKey(hkey);
125 /* This was an Open, but since it is called before the real registries
126 are loaded, it was changed to a Create - MTB 980507*/
127 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
128 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
129 RegCloseKey(hkey);
131 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
132 * CurrentVersion
133 * CurrentBuildNumber
134 * CurrentType
135 * string RegisteredOwner
136 * string RegisteredOrganization
139 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
140 * string SysContact
141 * string SysLocation
142 * SysServices
144 if (-1!=gethostname(buf,200)) {
145 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
146 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
147 RegCloseKey(hkey);
152 /************************ SAVE Registry Function ****************************/
154 #define REGISTRY_SAVE_VERSION 0x00000001
156 /* Registry saveformat:
157 * If you change it, increase above number by 1, which will flush
158 * old registry database files.
160 * Global:
161 * "WINE REGISTRY Version %d"
162 * subkeys....
163 * Subkeys:
164 * keyname
165 * valuename=lastmodified,type,data
166 * ...
167 * subkeys
168 * ...
169 * keyname,valuename,stringdata:
170 * the usual ascii characters from 0x00-0xff (well, not 0x00)
171 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
172 * ( "=\\\t" escaped in \uXXXX form.)
173 * type,lastmodified:
174 * int
176 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
178 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
179 * SaveOnlyUpdatedKeys=yes
182 /* Same as RegSaveKey but with Unix pathnames */
183 static void save_key( HKEY hkey, const char *filename )
185 struct save_registry_request *req = get_req_buffer();
186 int count = 0;
187 DWORD ret;
188 HANDLE handle;
189 char *p;
190 char *rname = HeapAlloc( GetProcessHeap(), 0, PATH_MAX );
191 char *name;
193 /* use realpath to resolve any symlinks
194 * I assume that rname is filled in correctly if the error is ENOENT */
195 if ((realpath(filename, rname) == NULL) && (errno != ENOENT))
197 ERR( "Failed to find real path of %s: ", filename );
198 perror( "realpath" );
199 HeapFree( GetProcessHeap(), 0, rname );
200 return;
203 name = HeapAlloc( GetProcessHeap(), 0, strlen(rname) + 20 );
205 if (!name) return;
206 strcpy( name, rname );
207 if ((p = strrchr( name, '/' ))) p++;
208 else p = name;
210 for (;;)
212 sprintf( p, "reg%04x.tmp", count++ );
213 handle = FILE_CreateFile( name, GENERIC_WRITE, 0, NULL,
214 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1, TRUE );
215 if (handle != INVALID_HANDLE_VALUE) break;
216 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) break;
219 if (handle != INVALID_HANDLE_VALUE)
221 req->hkey = hkey;
222 req->file = handle;
223 ret = server_call_noerr( REQ_SAVE_REGISTRY );
224 CloseHandle( handle );
225 if (ret) unlink( name );
226 else if (rename( name, rname ) == -1)
228 ERR( "Failed to move %s to %s: ", name, rname );
229 perror( "rename" );
230 unlink( name );
233 else ERR( "Failed to save registry to %s, err %ld\n", name, GetLastError() );
235 HeapFree( GetProcessHeap(), 0, rname );
236 HeapFree( GetProcessHeap(), 0, name );
240 /******************************************************************************
241 * SHELL_SaveRegistry [Internal]
243 void SHELL_SaveRegistry( void )
245 const char *confdir = get_config_dir();
246 struct set_registry_levels_request *req = get_req_buffer();
247 char *fn;
249 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
250 int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
252 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
253 req->current = 1;
254 req->saving = !all;
255 req->version = version;
256 server_call( REQ_SET_REGISTRY_LEVELS );
258 if (!(fn = HeapAlloc( GetProcessHeap(), 0, MAX_PATHNAME_LEN )))
260 ERR( "Not enough memory to save registry\n" );
261 return;
264 if (PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1))
266 if (PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", fn, MAX_PATHNAME_LEN ))
267 save_key( HKEY_CURRENT_USER, fn );
268 if (PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "", fn, MAX_PATHNAME_LEN ))
269 save_key( HKEY_LOCAL_MACHINE, fn );
270 if (PROFILE_GetWineIniString( "Registry", "AltUserFile", "", fn, MAX_PATHNAME_LEN ))
271 save_key( HKEY_USERS, fn );
275 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
277 char *str;
278 strcpy( fn, confdir );
279 str = fn + strlen(fn);
280 *str++ = '/';
282 strcpy( str, SAVE_CURRENT_USER );
283 save_key( HKEY_CURRENT_USER, fn );
285 strcpy( str, SAVE_LOCAL_MACHINE );
286 save_key( HKEY_LOCAL_MACHINE, fn );
288 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
289 save_key( HKEY_USERS, fn );
292 HeapFree( GetProcessHeap(), 0, fn );
295 /* Periodic save callback */
296 static void CALLBACK periodic_save( ULONG_PTR dummy )
298 SHELL_SaveRegistry();
301 /************************ LOAD Registry Function ****************************/
305 /******************************************************************************
306 * _find_or_add_key [Internal]
308 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
310 HKEY subkey;
311 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
312 if (keyname) free( keyname );
313 return subkey;
316 /******************************************************************************
317 * _find_or_add_value [Internal]
319 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
321 RegSetValueExW( hkey, name, 0, type, data, len );
322 if (name) free( name );
323 if (data) free( data );
327 /******************************************************************************
328 * _wine_read_line [Internal]
330 * reads a line including dynamically enlarging the readbuffer and throwing
331 * away comments
333 static int _wine_read_line( FILE *F, char **buf, int *len )
335 char *s,*curread;
336 int mylen,curoff;
338 curread = *buf;
339 mylen = *len;
340 **buf = '\0';
341 while (1) {
342 while (1) {
343 s=fgets(curread,mylen,F);
344 if (s==NULL)
345 return 0; /* EOF */
346 if (NULL==(s=strchr(curread,'\n'))) {
347 /* buffer wasn't large enough */
348 curoff = strlen(*buf);
349 curread = realloc(*buf,*len*2);
350 if(curread == NULL) {
351 WARN("Out of memory");
352 return 0;
354 *buf = curread;
355 curread+= curoff;
356 mylen = *len; /* we filled up the buffer and
357 * got new '*len' bytes to fill
359 *len = *len * 2;
360 } else {
361 *s='\0';
362 break;
365 /* throw away comments */
366 if (**buf=='#' || **buf==';') {
367 curread = *buf;
368 mylen = *len;
369 continue;
371 if (s) /* got end of line */
372 break;
374 return 1;
378 /******************************************************************************
379 * _wine_read_USTRING [Internal]
381 * converts a char* into a UNICODE string (up to a special char)
382 * and returns the position exactly after that string
384 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
386 char *s;
387 LPWSTR ws;
389 /* read up to "=" or "\0" or "\n" */
390 s = buf;
391 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
392 ws = *str;
393 while (*s && (*s!='\n') && (*s!='=')) {
394 if (*s!='\\')
395 *ws++=*((unsigned char*)s++);
396 else {
397 s++;
398 if (!*s) {
399 /* Dangling \ ... may only happen if a registry
400 * write was short. FIXME: What do to?
402 break;
404 if (*s=='\\') {
405 *ws++='\\';
406 s++;
407 continue;
409 if (*s!='u') {
410 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
411 *ws++='\\';
412 *ws++=*s++;
413 } else {
414 char xbuf[5];
415 int wc;
417 s++;
418 memcpy(xbuf,s,4);xbuf[4]='\0';
419 if (!sscanf(xbuf,"%x",&wc))
420 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
421 s+=4;
422 *ws++ =(unsigned short)wc;
426 *ws = 0;
427 return s;
431 /******************************************************************************
432 * _wine_loadsubkey [Internal]
434 * NOTES
435 * It seems like this is returning a boolean. Should it?
437 * RETURNS
438 * Success: 1
439 * Failure: 0
441 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
443 HKEY subkey;
444 int i;
445 char *s;
446 LPWSTR name;
448 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
450 /* Good. We already got a line here ... so parse it */
451 subkey = 0;
452 while (1) {
453 i=0;s=*buf;
454 while (*s=='\t') {
455 s++;
456 i++;
458 if (i>level) {
459 if (!subkey) {
460 WARN("Got a subhierarchy without resp. key?\n");
461 return 0;
463 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
464 if (!_wine_read_line(F,buf,buflen))
465 goto done;
466 continue;
469 /* let the caller handle this line */
470 if (i<level || **buf=='\0')
471 goto done;
473 /* it can be: a value or a keyname. Parse the name first */
474 s=_wine_read_USTRING(s,&name);
476 /* switch() default: hack to avoid gotos */
477 switch (0) {
478 default:
479 if (*s=='\0') {
480 if (subkey) RegCloseKey( subkey );
481 subkey=_find_or_add_key(hkey,name);
482 } else {
483 LPBYTE data;
484 int len,lastmodified,type;
486 if (*s!='=') {
487 WARN("Unexpected character: %c\n",*s);
488 break;
490 s++;
491 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
492 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
493 break;
495 /* skip the 2 , */
496 s=strchr(s,',');s++;
497 s=strchr(s,',');
498 if (!s++) {
499 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
500 break;
502 if (type == REG_SZ || type == REG_EXPAND_SZ) {
503 s=_wine_read_USTRING(s,(LPWSTR*)&data);
504 len = lstrlenW((LPWSTR)data)*2+2;
505 } else {
506 len=strlen(s)/2;
507 data = (LPBYTE)xmalloc(len+1);
508 for (i=0;i<len;i++) {
509 data[i]=0;
510 if (*s>='0' && *s<='9')
511 data[i]=(*s-'0')<<4;
512 if (*s>='a' && *s<='f')
513 data[i]=(*s-'a'+'\xa')<<4;
514 if (*s>='A' && *s<='F')
515 data[i]=(*s-'A'+'\xa')<<4;
516 s++;
517 if (*s>='0' && *s<='9')
518 data[i]|=*s-'0';
519 if (*s>='a' && *s<='f')
520 data[i]|=*s-'a'+'\xa';
521 if (*s>='A' && *s<='F')
522 data[i]|=*s-'A'+'\xa';
523 s++;
526 _find_or_add_value(hkey,name,type,data,len);
529 /* read the next line */
530 if (!_wine_read_line(F,buf,buflen))
531 goto done;
533 done:
534 if (subkey) RegCloseKey( subkey );
535 return 1;
539 /******************************************************************************
540 * _wine_loadsubreg [Internal]
542 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
544 int ver;
545 char *buf;
546 int buflen;
548 buf=xmalloc(10);buflen=10;
549 if (!_wine_read_line(F,&buf,&buflen)) {
550 free(buf);
551 return 0;
553 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
554 free(buf);
555 return 0;
557 if (ver!=REGISTRY_SAVE_VERSION) {
558 if (ver == 2) /* new version */
560 HANDLE file;
561 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
562 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
564 struct load_registry_request *req = get_req_buffer();
565 req->hkey = hkey;
566 req->file = file;
567 req->name[0] = 0;
568 server_call( REQ_LOAD_REGISTRY );
569 CloseHandle( file );
571 free( buf );
572 return 1;
574 else
576 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
577 free(buf);
578 return 0;
581 if (!_wine_read_line(F,&buf,&buflen)) {
582 free(buf);
583 return 0;
585 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
586 free(buf);
587 return 0;
589 free(buf);
590 return 1;
594 /******************************************************************************
595 * _wine_loadreg [Internal]
597 static void _wine_loadreg( HKEY hkey, char *fn )
599 FILE *F;
601 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
603 F = fopen(fn,"rb");
604 if (F==NULL) {
605 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
606 return;
608 _wine_loadsubreg(F,hkey,fn);
609 fclose(F);
612 /* NT REGISTRY LOADER */
614 #ifdef HAVE_SYS_MMAN_H
615 # include <sys/mman.h>
616 #endif
618 #ifndef MAP_FAILED
619 #define MAP_FAILED ((LPVOID)-1)
620 #endif
622 #define NT_REG_BLOCK_SIZE 0x1000
624 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
625 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
626 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
627 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
629 /* subblocks of nk */
630 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
631 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
632 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
634 #define NT_REG_KEY_BLOCK_TYPE 0x20
635 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
637 typedef struct
639 DWORD id; /* 0x66676572 'regf'*/
640 DWORD uk1; /* 0x04 */
641 DWORD uk2; /* 0x08 */
642 FILETIME DateModified; /* 0x0c */
643 DWORD uk3; /* 0x14 */
644 DWORD uk4; /* 0x18 */
645 DWORD uk5; /* 0x1c */
646 DWORD uk6; /* 0x20 */
647 DWORD RootKeyBlock; /* 0x24 */
648 DWORD BlockSize; /* 0x28 */
649 DWORD uk7[116];
650 DWORD Checksum; /* at offset 0x1FC */
651 } nt_regf;
653 typedef struct
655 DWORD blocksize;
656 BYTE data[1];
657 } nt_hbin_sub;
659 typedef struct
661 DWORD id; /* 0x6E696268 'hbin' */
662 DWORD off_prev;
663 DWORD off_next;
664 DWORD uk1;
665 DWORD uk2; /* 0x10 */
666 DWORD uk3; /* 0x14 */
667 DWORD uk4; /* 0x18 */
668 DWORD size; /* 0x1C */
669 nt_hbin_sub hbin_sub; /* 0x20 */
670 } nt_hbin;
673 * the value_list consists of offsets to the values (vk)
675 typedef struct
677 WORD SubBlockId; /* 0x00 0x6B6E */
678 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
679 FILETIME writetime; /* 0x04 */
680 DWORD uk1; /* 0x0C */
681 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
682 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
683 DWORD uk8; /* 0x18 */
684 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
685 DWORD uk2; /* 0x20 */
686 DWORD nr_values; /* 0x24 number of values */
687 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
688 DWORD off_sk; /* 0x2c Offset of the sk-Record */
689 DWORD off_class; /* 0x30 Offset of the Class-Name */
690 DWORD uk3; /* 0x34 */
691 DWORD uk4; /* 0x38 */
692 DWORD uk5; /* 0x3c */
693 DWORD uk6; /* 0x40 */
694 DWORD uk7; /* 0x44 */
695 WORD name_len; /* 0x48 name-length */
696 WORD class_len; /* 0x4a class-name length */
697 char name[1]; /* 0x4c key-name */
698 } nt_nk;
700 typedef struct
702 DWORD off_nk; /* 0x00 */
703 DWORD name; /* 0x04 */
704 } hash_rec;
706 typedef struct
708 WORD id; /* 0x00 0x666c */
709 WORD nr_keys; /* 0x06 */
710 hash_rec hash_rec[1];
711 } nt_lf;
714 list of subkeys without hash
716 li --+-->nk
718 +-->nk
720 typedef struct
722 WORD id; /* 0x00 0x696c */
723 WORD nr_keys;
724 DWORD off_nk[1];
725 } nt_li;
728 this is a intermediate node
730 ri --+-->li--+-->nk
732 | +-->nk
734 +-->li--+-->nk
736 +-->nk
738 typedef struct
740 WORD id; /* 0x00 0x6972 */
741 WORD nr_li; /* 0x02 number off offsets */
742 DWORD off_li[1]; /* 0x04 points to li */
743 } nt_ri;
745 typedef struct
747 WORD id; /* 0x00 'vk' */
748 WORD nam_len;
749 DWORD data_len;
750 DWORD data_off;
751 DWORD type;
752 WORD flag;
753 WORD uk1;
754 char name[1];
755 } nt_vk;
757 LPSTR _strdupnA( LPCSTR str, int len )
759 LPSTR ret;
761 if (!str) return NULL;
762 ret = malloc( len + 1 );
763 lstrcpynA( ret, str, len );
764 ret[len] = 0x00;
765 return ret;
768 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
769 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
770 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
774 * gets a value
776 * vk->flag:
777 * 0 value is a default value
778 * 1 the value has a name
780 * vk->data_len
781 * len of the whole data block
782 * - reg_sz (unicode)
783 * bytes including the terminating \0 = 2*(number_of_chars+1)
784 * - reg_dword, reg_binary:
785 * if highest bit of data_len is set data_off contains the value
787 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
789 WCHAR name [256];
790 DWORD ret;
791 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
793 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
795 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
797 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
798 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
799 (vk->data_len & 0x7fffffff) );
800 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
801 return TRUE;
802 error:
803 ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
804 return FALSE;
808 * get the subkeys
810 * this structure contains the hash of a keyname and points to all
811 * subkeys
813 * exception: if the id is 'il' there are no hash values and every
814 * dword is a offset
816 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
818 int i;
820 if (lf->id == NT_REG_HASH_BLOCK_ID)
822 if (subkeys != lf->nr_keys) goto error1;
824 for (i=0; i<lf->nr_keys; i++)
826 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
829 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
831 nt_li * li = (nt_li*)lf;
832 if (subkeys != li->nr_keys) goto error1;
834 for (i=0; i<li->nr_keys; i++)
836 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
839 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
841 nt_ri * ri = (nt_ri*)lf;
842 int li_subkeys = 0;
844 /* count all subkeys */
845 for (i=0; i<ri->nr_li; i++)
847 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
848 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
849 li_subkeys += li->nr_keys;
852 /* check number */
853 if (subkeys != li_subkeys) goto error1;
855 /* loop through the keys */
856 for (i=0; i<ri->nr_li; i++)
858 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
859 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
862 else
864 goto error2;
866 return TRUE;
868 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
869 return TRUE;
871 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
872 return FALSE;
874 error: ERR_(reg)("error reading lf block\n");
875 return FALSE;
878 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
880 char * name;
881 int i;
882 DWORD * vl;
883 HKEY subkey = hkey;
885 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
887 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
888 goto error;
891 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
892 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
894 ERR_(reg)("registry file corrupt!\n");
895 goto error;
898 /* create the new key */
899 if(level <= 0)
901 name = _strdupnA( nk->name, nk->name_len+1);
902 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
903 free(name);
906 /* loop through the subkeys */
907 if (nk->nr_subkeys)
909 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
910 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
913 /* loop trough the value list */
914 vl = (DWORD *)(base+nk->valuelist_off+4);
915 for (i=0; i<nk->nr_values; i++)
917 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
918 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
921 RegCloseKey(subkey);
922 return TRUE;
924 error1: RegCloseKey(subkey);
925 error: return FALSE;
928 /* end nt loader */
930 /* windows 95 registry loader */
932 /* SECTION 1: main header
934 * once at offset 0
936 #define W95_REG_CREG_ID 0x47455243
938 typedef struct
940 DWORD id; /* "CREG" = W95_REG_CREG_ID */
941 DWORD version; /* ???? 0x00010000 */
942 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
943 DWORD uk2; /* 0x0c */
944 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
945 WORD uk3;
946 DWORD uk[3];
947 /* rgkn */
948 } _w95creg;
950 /* SECTION 2: Directory information (tree structure)
952 * once on offset 0x20
954 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
956 #define W95_REG_RGKN_ID 0x4e4b4752
958 typedef struct
960 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
961 DWORD size; /* Size of the RGKN-block */
962 DWORD root_off; /* Rel. Offset of the root-record */
963 DWORD uk[5];
964 } _w95rgkn;
966 /* Disk Key Entry Structure
968 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
969 * hive itself. It looks the same like other keys. Even the ID-number can
970 * be any value.
972 * The "hash"-value is a value representing the key's name. Windows will not
973 * search for the name, but for a matching hash-value. if it finds one, it
974 * will compare the actual string info, otherwise continue with the next key.
975 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
976 * of the string which are smaller than 0x80 (128) to this D-Word.
978 * If you want to modify key names, also modify the hash-values, since they
979 * cannot be found again (although they would be displayed in REGEDIT)
980 * End of list-pointers are filled with 0xFFFFFFFF
982 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
983 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
984 * structure) and reading another RGDB_section.
986 * there is a one to one relationship between dke and dkh
988 /* key struct, once per key */
989 typedef struct
991 DWORD x1; /* Free entry indicator(?) */
992 DWORD hash; /* sum of bytes of keyname */
993 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
994 DWORD prevlvl; /* offset of previous key */
995 DWORD nextsub; /* offset of child key */
996 DWORD next; /* offset of sibling key */
997 WORD nrLS; /* id inside the rgdb block */
998 WORD nrMS; /* number of the rgdb block */
999 } _w95dke;
1001 /* SECTION 3: key information, values and data
1003 * structure:
1004 * section: [blocks]* (repeat creg->rgdb_num times)
1005 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
1006 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
1008 * An interesting relationship exists in RGDB_section. The value at offset
1009 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1010 * idea at the moment what this means. (Kevin Cozens)
1013 /* block header, once per block */
1014 #define W95_REG_RGDB_ID 0x42444752
1016 typedef struct
1018 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
1019 DWORD size; /* 0x04 */
1020 DWORD uk1; /* 0x08 */
1021 DWORD uk2; /* 0x0c */
1022 DWORD uk3; /* 0x10 */
1023 DWORD uk4; /* 0x14 */
1024 DWORD uk5; /* 0x18 */
1025 DWORD uk6; /* 0x1c */
1026 /* dkh */
1027 } _w95rgdb;
1029 /* Disk Key Header structure (RGDB part), once per key */
1030 typedef struct
1032 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
1033 WORD nrLS; /* 0x04 id inside the rgdb block */
1034 WORD nrMS; /* 0x06 number of the rgdb block */
1035 DWORD bytesused; /* 0x08 */
1036 WORD keynamelen; /* 0x0c len of name */
1037 WORD values; /* 0x0e number of values */
1038 DWORD xx1; /* 0x10 */
1039 char name[1]; /* 0x14 */
1040 /* dkv */ /* 0x14 + keynamelen */
1041 } _w95dkh;
1043 /* Disk Key Value structure, once per value */
1044 typedef struct
1046 DWORD type; /* 0x00 */
1047 DWORD x1; /* 0x04 */
1048 WORD valnamelen; /* 0x08 length of name, 0 is default key */
1049 WORD valdatalen; /* 0x0A length of data */
1050 char name[1]; /* 0x0c */
1051 /* raw data */ /* 0x0c + valnamelen */
1052 } _w95dkv;
1054 /******************************************************************************
1055 * _w95_lookup_dkh [Internal]
1057 * seeks the dkh belonging to a dke
1059 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1061 _w95rgdb * rgdb;
1062 _w95dkh * dkh;
1063 int i;
1065 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
1066 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
1068 /* find the right block */
1069 for(i=0; i<nrMS ;i++)
1071 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
1072 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
1075 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
1079 if(nrLS==dkh->nrLS ) return dkh;
1080 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
1081 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1083 return NULL;
1086 /******************************************************************************
1087 * _w95_parse_dkv [Internal]
1089 static int _w95_parse_dkv (
1090 HKEY hkey,
1091 _w95dkh * dkh,
1092 int nrLS,
1093 int nrMS )
1095 _w95dkv * dkv;
1096 int i;
1097 DWORD ret;
1098 char * name;
1100 /* first value block */
1101 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1103 /* loop trought the values */
1104 for (i=0; i< dkh->values; i++)
1106 name = _strdupnA(dkv->name, dkv->valnamelen+1);
1107 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
1108 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1109 free (name);
1111 /* next value */
1112 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1114 return TRUE;
1117 /******************************************************************************
1118 * _w95_parse_dke [Internal]
1120 static int _w95_parse_dke(
1121 HKEY hkey,
1122 _w95creg * creg,
1123 _w95rgkn *rgkn,
1124 _w95dke * dke,
1125 int level )
1127 _w95dkh * dkh;
1128 HKEY hsubkey = hkey;
1129 char * name;
1130 int ret = FALSE;
1132 /* get start address of root key block */
1133 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1135 /* special root key */
1136 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
1138 /* parse the one subkey*/
1139 if (dke->nextsub != 0xffffffff)
1141 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1143 /* has no sibling keys */
1144 goto error;
1147 /* search subblock */
1148 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1150 fprintf(stderr, "dke pointing to missing dkh !\n");
1151 goto error;
1154 if ( level <= 0 )
1156 /* walk sibling keys */
1157 if (dke->next != 0xffffffff )
1159 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1162 /* create subkey and insert values */
1163 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1164 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1165 free(name);
1166 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1169 /* next sub key */
1170 if (dke->nextsub != 0xffffffff)
1172 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1175 ret = TRUE;
1176 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1177 error: return ret;
1179 /* end windows 95 loader */
1181 /******************************************************************************
1182 * NativeRegLoadKey [Internal]
1184 * Loads a native registry file (win95/nt)
1185 * hkey root key
1186 * fn filename
1187 * level number of levels to cut away (eg. ".Default" in user.dat)
1189 * this function intentionally uses unix file functions to make it possible
1190 * to move it to a seperate registry helper programm
1192 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1194 int fd = 0;
1195 struct stat st;
1196 DOS_FULL_NAME full_name;
1197 int ret = FALSE;
1198 void * base;
1200 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1202 /* map the registry into the memory */
1203 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1204 if ((fstat(fd, &st) == -1)) goto error;
1205 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1207 switch (*(LPDWORD)base)
1209 /* windows 95 'creg' */
1210 case W95_REG_CREG_ID:
1212 _w95creg * creg;
1213 _w95rgkn * rgkn;
1214 creg = base;
1215 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1217 /* load the header (rgkn) */
1218 rgkn = (_w95rgkn*)(creg + 1);
1219 if (rgkn->id != W95_REG_RGKN_ID)
1221 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1222 goto error1;
1225 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1227 break;
1228 /* nt 'regf'*/
1229 case NT_REG_HEADER_BLOCK_ID:
1231 nt_regf * regf;
1232 nt_hbin * hbin;
1233 nt_hbin_sub * hbin_sub;
1234 nt_nk* nk;
1236 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1238 /* start block */
1239 regf = base;
1241 /* hbin block */
1242 hbin = (nt_hbin *) ((char *) base + 0x1000);
1243 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1245 ERR_(reg)( "%s hbin block invalid\n", fn);
1246 goto error1;
1249 /* hbin_sub block */
1250 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1251 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1253 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1254 goto error1;
1257 /* nk block */
1258 nk = (nt_nk*)&(hbin_sub->data[0]);
1259 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1261 ERR_(reg)( "%s special nk block not found\n", fn);
1262 goto error1;
1265 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1267 break;
1268 default:
1270 ERR("unknown signature in registry file %s.\n",fn);
1271 goto error1;
1274 if(!ret) ERR("error loading registry file %s\n", fn);
1275 error1: munmap(base, st.st_size);
1276 error: close(fd);
1277 return ret;
1280 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1282 reghack - windows 3.11 registry data format demo program.
1284 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1285 a combined hash table and tree description, and finally a text table.
1287 The header is obvious from the struct header. The taboff1 and taboff2
1288 fields are always 0x20, and their usage is unknown.
1290 The 8-byte entry table has various entry types.
1292 tabent[0] is a root index. The second word has the index of the root of
1293 the directory.
1294 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1295 the index of the key/value that has that hash. Data with the same
1296 hash value are on a circular list. The other three words in the
1297 hash entry are always zero.
1298 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1299 entry: dirent and keyent/valent. They are identified by context.
1300 tabent[freeidx] is the first free entry. The first word in a free entry
1301 is the index of the next free entry. The last has 0 as a link.
1302 The other three words in the free list are probably irrelevant.
1304 Entries in text table are preceeded by a word at offset-2. This word
1305 has the value (2*index)+1, where index is the referring keyent/valent
1306 entry in the table. I have no suggestion for the 2* and the +1.
1307 Following the word, there are N bytes of data, as per the keyent/valent
1308 entry length. The offset of the keyent/valent entry is from the start
1309 of the text table to the first data byte.
1311 This information is not available from Microsoft. The data format is
1312 deduced from the reg.dat file by me. Mistakes may
1313 have been made. I claim no rights and give no guarantees for this program.
1315 Tor Sjøwall, tor@sn.no
1318 /* reg.dat header format */
1319 struct _w31_header {
1320 char cookie[8]; /* 'SHCC3.10' */
1321 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1322 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1323 unsigned long tabcnt; /* number of entries in index table */
1324 unsigned long textoff; /* offset of text part */
1325 unsigned long textsize; /* byte size of text part */
1326 unsigned short hashsize; /* hash size */
1327 unsigned short freeidx; /* free index */
1330 /* generic format of table entries */
1331 struct _w31_tabent {
1332 unsigned short w0, w1, w2, w3;
1335 /* directory tabent: */
1336 struct _w31_dirent {
1337 unsigned short sibling_idx; /* table index of sibling dirent */
1338 unsigned short child_idx; /* table index of child dirent */
1339 unsigned short key_idx; /* table index of key keyent */
1340 unsigned short value_idx; /* table index of value valent */
1343 /* key tabent: */
1344 struct _w31_keyent {
1345 unsigned short hash_idx; /* hash chain index for string */
1346 unsigned short refcnt; /* reference count */
1347 unsigned short length; /* length of string */
1348 unsigned short string_off; /* offset of string in text table */
1351 /* value tabent: */
1352 struct _w31_valent {
1353 unsigned short hash_idx; /* hash chain index for string */
1354 unsigned short refcnt; /* reference count */
1355 unsigned short length; /* length of string */
1356 unsigned short string_off; /* offset of string in text table */
1359 /* recursive helper function to display a directory tree */
1360 void
1361 __w31_dumptree( unsigned short idx,
1362 unsigned char *txt,
1363 struct _w31_tabent *tab,
1364 struct _w31_header *head,
1365 HKEY hkey,
1366 time_t lastmodified,
1367 int level
1369 struct _w31_dirent *dir;
1370 struct _w31_keyent *key;
1371 struct _w31_valent *val;
1372 HKEY subkey = 0;
1373 static char tail[400];
1375 while (idx!=0) {
1376 dir=(struct _w31_dirent*)&tab[idx];
1378 if (dir->key_idx) {
1379 key = (struct _w31_keyent*)&tab[dir->key_idx];
1381 memcpy(tail,&txt[key->string_off],key->length);
1382 tail[key->length]='\0';
1383 /* all toplevel entries AND the entries in the
1384 * toplevel subdirectory belong to \SOFTWARE\Classes
1386 if (!level && !lstrcmpA(tail,".classes")) {
1387 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1388 idx=dir->sibling_idx;
1389 continue;
1391 if (subkey) RegCloseKey( subkey );
1392 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1393 /* only add if leaf node or valued node */
1394 if (dir->value_idx!=0||dir->child_idx==0) {
1395 if (dir->value_idx) {
1396 val=(struct _w31_valent*)&tab[dir->value_idx];
1397 memcpy(tail,&txt[val->string_off],val->length);
1398 tail[val->length]='\0';
1399 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1402 } else {
1403 TRACE("strange: no directory key name, idx=%04x\n", idx);
1405 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1406 idx=dir->sibling_idx;
1408 if (subkey) RegCloseKey( subkey );
1412 /******************************************************************************
1413 * _w31_loadreg [Internal]
1415 void _w31_loadreg(void) {
1416 HFILE hf;
1417 struct _w31_header head;
1418 struct _w31_tabent *tab;
1419 unsigned char *txt;
1420 int len;
1421 OFSTRUCT ofs;
1422 BY_HANDLE_FILE_INFORMATION hfinfo;
1423 time_t lastmodified;
1425 TRACE("(void)\n");
1427 hf = OpenFile("reg.dat",&ofs,OF_READ);
1428 if (hf==HFILE_ERROR)
1429 return;
1431 /* read & dump header */
1432 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1433 ERR("reg.dat is too short.\n");
1434 _lclose(hf);
1435 return;
1437 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1438 ERR("reg.dat has bad signature.\n");
1439 _lclose(hf);
1440 return;
1443 len = head.tabcnt * sizeof(struct _w31_tabent);
1444 /* read and dump index table */
1445 tab = xmalloc(len);
1446 if (len!=_lread(hf,tab,len)) {
1447 ERR("couldn't read %d bytes.\n",len);
1448 free(tab);
1449 _lclose(hf);
1450 return;
1453 /* read text */
1454 txt = xmalloc(head.textsize);
1455 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1456 ERR("couldn't seek to textblock.\n");
1457 free(tab);
1458 free(txt);
1459 _lclose(hf);
1460 return;
1462 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1463 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1464 free(tab);
1465 free(txt);
1466 _lclose(hf);
1467 return;
1470 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1471 ERR("GetFileInformationByHandle failed?.\n");
1472 free(tab);
1473 free(txt);
1474 _lclose(hf);
1475 return;
1477 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1478 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1479 free(tab);
1480 free(txt);
1481 _lclose(hf);
1482 return;
1485 /**********************************************************************************
1486 * SetLoadLevel [Internal]
1488 * set level to 0 for loading system files
1489 * set level to 1 for loading user files
1491 static void SetLoadLevel(int level)
1493 struct set_registry_levels_request *req = get_req_buffer();
1495 req->current = level;
1496 req->saving = 0;
1497 req->version = 1;
1498 server_call( REQ_SET_REGISTRY_LEVELS );
1501 /**********************************************************************************
1502 * SHELL_LoadRegistry [Internal]
1504 #define REG_DONTLOAD -1
1505 #define REG_WIN31 0
1506 #define REG_WIN95 1
1507 #define REG_WINNT 2
1509 void SHELL_LoadRegistry( void )
1511 HKEY hkey;
1512 char windir[MAX_PATHNAME_LEN];
1513 char path[MAX_PATHNAME_LEN];
1514 int systemtype = REG_WIN31;
1516 TRACE("(void)\n");
1518 if (!CLIENT_IsBootThread()) return; /* already loaded */
1520 REGISTRY_Init();
1521 SetLoadLevel(0);
1523 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1525 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1527 /* test %windir%/system32/config/system --> winnt */
1528 strcpy(path, windir);
1529 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1530 if(GetFileAttributesA(path) != -1)
1532 systemtype = REG_WINNT;
1534 else
1536 /* test %windir%/system.dat --> win95 */
1537 strcpy(path, windir);
1538 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1539 if(GetFileAttributesA(path) != -1)
1541 systemtype = REG_WIN95;
1545 if ((systemtype==REG_WINNT)
1546 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1548 MESSAGE("When you are running with a native NT directory specify\n");
1549 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1550 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1551 systemtype = REG_DONTLOAD;
1554 else
1556 /* only wine registry */
1557 systemtype = REG_DONTLOAD;
1560 switch (systemtype)
1562 case REG_WIN31:
1563 _w31_loadreg();
1564 break;
1566 case REG_WIN95:
1567 /* Load windows 95 entries */
1568 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1570 strcpy(path, windir);
1571 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1572 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1574 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1576 /* user specific user.dat */
1577 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1578 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1580 MESSAGE("can't load win95 user-registry %s\n", path);
1581 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1583 /* default user.dat */
1584 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1586 strcpy(path, windir);
1587 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1588 NativeRegLoadKey(hkey, path, 1);
1589 RegCloseKey(hkey);
1592 else
1594 /* global user.dat */
1595 strcpy(path, windir);
1596 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1597 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1599 break;
1601 case REG_WINNT:
1602 /* default user.dat */
1603 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1605 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1606 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1608 MESSAGE("can't load NT user-registry %s\n", path);
1609 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1613 /* default user.dat */
1614 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1616 strcpy(path, windir);
1617 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1618 NativeRegLoadKey(hkey, path, 1);
1619 RegCloseKey(hkey);
1623 * FIXME
1624 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1627 strcpy(path, windir);
1628 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1629 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1631 strcpy(path, windir);
1632 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1633 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1635 strcpy(path, windir);
1636 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1637 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1639 strcpy(path, windir);
1640 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1641 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1643 /* this key is generated when the nt-core booted successfully */
1644 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1645 RegCloseKey(hkey);
1646 break;
1647 } /* switch */
1649 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1652 * Load the global HKU hive directly from sysconfdir
1654 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1657 * Load the global machine defaults directly form sysconfdir
1659 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1662 SetLoadLevel(1);
1665 * Load the user saved registries
1667 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1669 const char *confdir = get_config_dir();
1670 int len = strlen(confdir) + 20;
1671 char *fn = path;
1673 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1675 * Load user's personal versions of global HKU/.Default keys
1677 if (fn)
1679 char *str;
1680 strcpy( fn, confdir );
1681 str = fn + strlen(fn);
1682 *str++ = '/';
1684 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1685 _wine_loadreg( HKEY_USERS, fn );
1687 strcpy( str, SAVE_CURRENT_USER );
1688 _wine_loadreg( HKEY_CURRENT_USER, fn );
1690 strcpy( str, SAVE_LOCAL_MACHINE );
1691 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1693 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1698 * Load HKCU, get the registry location from the config
1699 * file, if exist, load and keep going.
1701 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1703 if (PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", path, sizeof(path) ))
1704 _wine_loadreg( HKEY_CURRENT_USER, path );
1707 * Load HKU, get the registry location from the config
1708 * file, if exist, load and keep going.
1710 if (PROFILE_GetWineIniString ( "registry", "AltUserFile", "", path, sizeof(path) ))
1711 _wine_loadreg( HKEY_USERS, path );
1714 * Load HKLM, get the registry location from the config
1715 * file, if exist, load and keep going.
1717 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "", path, sizeof(path) ))
1718 _wine_loadreg( HKEY_LOCAL_MACHINE, path );
1722 /* start the periodic saving timer */
1723 void SHELL_InitRegistrySaving(void)
1725 int save_timeout;
1727 if (!CLIENT_IsBootThread()) return;
1729 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1731 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1736 /********************* API FUNCTIONS ***************************************/
1741 /******************************************************************************
1742 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1743 * Immediately writes key to registry.
1744 * Only returns after data has been written to disk.
1746 * FIXME: does it really wait until data is written ?
1748 * PARAMS
1749 * hkey [I] Handle of key to write
1751 * RETURNS
1752 * Success: ERROR_SUCCESS
1753 * Failure: Error code
1755 DWORD WINAPI RegFlushKey( HKEY hkey )
1757 FIXME( "(%x): stub\n", hkey );
1758 return ERROR_SUCCESS;
1761 /******************************************************************************
1762 * RegConnectRegistryW [ADVAPI32.128]
1764 * PARAMS
1765 * lpMachineName [I] Address of name of remote computer
1766 * hHey [I] Predefined registry handle
1767 * phkResult [I] Address of buffer for remote registry handle
1769 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1770 LPHKEY phkResult )
1772 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1774 if (!lpMachineName || !*lpMachineName) {
1775 /* Use the local machine name */
1776 return RegOpenKey16( hKey, "", phkResult );
1779 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1780 return ERROR_BAD_NETPATH;
1784 /******************************************************************************
1785 * RegConnectRegistryA [ADVAPI32.127]
1787 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1789 DWORD ret;
1790 LPWSTR machineW = strdupA2W(machine);
1791 ret = RegConnectRegistryW( machineW, hkey, reskey );
1792 free(machineW);
1793 return ret;
1797 /******************************************************************************
1798 * RegGetKeySecurity [ADVAPI32.144]
1799 * Retrieves a copy of security descriptor protecting the registry key
1801 * PARAMS
1802 * hkey [I] Open handle of key to set
1803 * SecurityInformation [I] Descriptor contents
1804 * pSecurityDescriptor [O] Address of descriptor for key
1805 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1807 * RETURNS
1808 * Success: ERROR_SUCCESS
1809 * Failure: Error code
1811 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1812 SECURITY_INFORMATION SecurityInformation,
1813 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1814 LPDWORD lpcbSecurityDescriptor )
1816 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1817 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1819 /* FIXME: Check for valid SecurityInformation values */
1821 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1822 return ERROR_INSUFFICIENT_BUFFER;
1824 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1825 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1827 return ERROR_SUCCESS;
1831 /******************************************************************************
1832 * RegNotifyChangeKeyValue [ADVAPI32.???]
1834 * PARAMS
1835 * hkey [I] Handle of key to watch
1836 * fWatchSubTree [I] Flag for subkey notification
1837 * fdwNotifyFilter [I] Changes to be reported
1838 * hEvent [I] Handle of signaled event
1839 * fAsync [I] Flag for asynchronous reporting
1841 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1842 DWORD fdwNotifyFilter, HANDLE hEvent,
1843 BOOL fAsync )
1845 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1846 hEvent,fAsync);
1847 return ERROR_SUCCESS;
1851 /******************************************************************************
1852 * RegUnLoadKeyW [ADVAPI32.173]
1854 * PARAMS
1855 * hkey [I] Handle of open key
1856 * lpSubKey [I] Address of name of subkey to unload
1858 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1860 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1861 return ERROR_SUCCESS;
1865 /******************************************************************************
1866 * RegUnLoadKeyA [ADVAPI32.172]
1868 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1870 LONG ret;
1871 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1872 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1873 if(lpSubKeyW) free(lpSubKeyW);
1874 return ret;
1878 /******************************************************************************
1879 * RegSetKeySecurity [ADVAPI32.167]
1881 * PARAMS
1882 * hkey [I] Open handle of key to set
1883 * SecurityInfo [I] Descriptor contents
1884 * pSecurityDesc [I] Address of descriptor for key
1886 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1887 PSECURITY_DESCRIPTOR pSecurityDesc )
1889 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1891 /* It seems to perform this check before the hkey check */
1892 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1893 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1894 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1895 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1896 /* Param OK */
1897 } else
1898 return ERROR_INVALID_PARAMETER;
1900 if (!pSecurityDesc)
1901 return ERROR_INVALID_PARAMETER;
1903 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1905 return ERROR_SUCCESS;
1909 /******************************************************************************
1910 * RegRestoreKeyW [ADVAPI32.164]
1912 * PARAMS
1913 * hkey [I] Handle of key where restore begins
1914 * lpFile [I] Address of filename containing saved tree
1915 * dwFlags [I] Optional flags
1917 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1919 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1921 /* It seems to do this check before the hkey check */
1922 if (!lpFile || !*lpFile)
1923 return ERROR_INVALID_PARAMETER;
1925 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1927 /* Check for file existence */
1929 return ERROR_SUCCESS;
1933 /******************************************************************************
1934 * RegRestoreKeyA [ADVAPI32.163]
1936 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1938 LONG ret;
1939 LPWSTR lpFileW = strdupA2W(lpFile);
1940 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1941 if(lpFileW) free(lpFileW);
1942 return ret;
1946 /******************************************************************************
1947 * RegReplaceKeyW [ADVAPI32.162]
1949 * PARAMS
1950 * hkey [I] Handle of open key
1951 * lpSubKey [I] Address of name of subkey
1952 * lpNewFile [I] Address of filename for file with new data
1953 * lpOldFile [I] Address of filename for backup file
1955 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1956 LPCWSTR lpOldFile )
1958 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1959 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1960 return ERROR_SUCCESS;
1964 /******************************************************************************
1965 * RegReplaceKeyA [ADVAPI32.161]
1967 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1968 LPCSTR lpOldFile )
1970 LONG ret;
1971 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1972 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1973 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1974 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1975 free(lpOldFileW);
1976 free(lpNewFileW);
1977 free(lpSubKeyW);
1978 return ret;
1986 /* 16-bit functions */
1988 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1989 * some programs. Do not remove those cases. -MM
1991 static inline void fix_win16_hkey( HKEY *hkey )
1993 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1996 /******************************************************************************
1997 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1999 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2001 fix_win16_hkey( &hkey );
2002 return RegEnumKeyA( hkey, index, name, name_len );
2005 /******************************************************************************
2006 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2008 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2010 fix_win16_hkey( &hkey );
2011 return RegOpenKeyA( hkey, name, retkey );
2014 /******************************************************************************
2015 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2017 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2019 fix_win16_hkey( &hkey );
2020 return RegCreateKeyA( hkey, name, retkey );
2023 /******************************************************************************
2024 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2026 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2028 fix_win16_hkey( &hkey );
2029 return RegDeleteKeyA( hkey, name );
2032 /******************************************************************************
2033 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2035 DWORD WINAPI RegCloseKey16( HKEY hkey )
2037 fix_win16_hkey( &hkey );
2038 return RegCloseKey( hkey );
2041 /******************************************************************************
2042 * RegSetValue16 [KERNEL.221] [SHELL.5]
2044 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2046 fix_win16_hkey( &hkey );
2047 return RegSetValueA( hkey, name, type, data, count );
2050 /******************************************************************************
2051 * RegDeleteValue16 [KERNEL.222]
2053 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2055 fix_win16_hkey( &hkey );
2056 return RegDeleteValueA( hkey, name );
2059 /******************************************************************************
2060 * RegEnumValue16 [KERNEL.223]
2062 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2063 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2065 fix_win16_hkey( &hkey );
2066 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2069 /******************************************************************************
2070 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2072 * NOTES
2073 * Is this HACK still applicable?
2075 * HACK
2076 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2077 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2078 * Aldus FH4)
2080 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2082 fix_win16_hkey( &hkey );
2083 if (count) *count &= 0xffff;
2084 return RegQueryValueA( hkey, name, data, count );
2087 /******************************************************************************
2088 * RegQueryValueEx16 [KERNEL.225]
2090 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2091 LPBYTE data, LPDWORD count )
2093 fix_win16_hkey( &hkey );
2094 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2097 /******************************************************************************
2098 * RegSetValueEx16 [KERNEL.226]
2100 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2101 CONST BYTE *data, DWORD count )
2103 fix_win16_hkey( &hkey );
2104 return RegSetValueExA( hkey, name, reserved, type, data, count );