Release 20000130.
[wine.git] / misc / registry.c
blobd66cd5bf6999ca717521ca482964b7b6d3a1ac1f
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 <unistd.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
31 #endif
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <sys/fcntl.h>
35 #include <sys/stat.h>
36 #include <assert.h>
37 #include <time.h>
38 #include "windef.h"
39 #include "winbase.h"
40 #include "wine/winbase16.h"
41 #include "wine/winestring.h"
42 #include "winerror.h"
43 #include "file.h"
44 #include "heap.h"
45 #include "debugtools.h"
46 #include "xmalloc.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 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
58 #define WINE_PREFIX "/.wine"
59 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
60 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
62 /* relative in ~user/.wine/ : */
63 #define SAVE_CURRENT_USER "user.reg"
64 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
65 #define SAVE_LOCAL_MACHINE "system.reg"
67 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
68 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
71 /* what valuetypes do we need to convert? */
72 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
77 * QUESTION
78 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
80 * ANSWER
81 * No, the memory handling functions are called very often in here,
82 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
83 * loading 100 times slower. -MM
85 static LPWSTR strdupA2W(LPCSTR src)
87 if(src) {
88 LPWSTR dest=xmalloc(2*strlen(src)+2);
89 lstrcpyAtoW(dest,src);
90 return dest;
92 return NULL;
95 LPWSTR strcvtA2W(LPCSTR src, int nchars)
98 LPWSTR dest = xmalloc (2 * nchars + 2);
100 lstrcpynAtoW(dest,src,nchars+1);
101 return dest;
106 /******************************************************************************
107 * REGISTRY_Init [Internal]
108 * Registry initialisation, allocates some default keys.
110 static void REGISTRY_Init(void) {
111 HKEY hkey;
112 char buf[200];
114 TRACE("(void)\n");
116 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
117 RegCloseKey(hkey);
119 /* This was an Open, but since it is called before the real registries
120 are loaded, it was changed to a Create - MTB 980507*/
121 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
122 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
123 RegCloseKey(hkey);
125 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
126 * CurrentVersion
127 * CurrentBuildNumber
128 * CurrentType
129 * string RegisteredOwner
130 * string RegisteredOrganization
133 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
134 * string SysContact
135 * string SysLocation
136 * SysServices
138 if (-1!=gethostname(buf,200)) {
139 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
140 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
141 RegCloseKey(hkey);
146 /************************ SAVE Registry Function ****************************/
148 #define REGISTRY_SAVE_VERSION 0x00000001
150 /* Registry saveformat:
151 * If you change it, increase above number by 1, which will flush
152 * old registry database files.
154 * Global:
155 * "WINE REGISTRY Version %d"
156 * subkeys....
157 * Subkeys:
158 * keyname
159 * valuename=lastmodified,type,data
160 * ...
161 * subkeys
162 * ...
163 * keyname,valuename,stringdata:
164 * the usual ascii characters from 0x00-0xff (well, not 0x00)
165 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
166 * ( "=\\\t" escaped in \uXXXX form.)
167 * type,lastmodified:
168 * int
170 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
172 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
173 * SaveOnlyUpdatedKeys=yes
176 /* Same as RegSaveKey but with Unix pathnames */
177 static void save_key( HKEY hkey, const char *filename )
179 struct save_registry_request *req = get_req_buffer();
180 int count = 0;
181 DWORD ret;
182 HANDLE handle;
183 char *p;
184 char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
186 if (!name) return;
187 strcpy( name, filename );
188 if ((p = strrchr( name, '/' ))) p++;
189 else p = name;
191 for (;;)
193 sprintf( p, "reg%04x.tmp", count++ );
194 handle = FILE_CreateFile( name, GENERIC_WRITE, 0, NULL,
195 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
196 if (handle != INVALID_HANDLE_VALUE) break;
197 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) break;
200 if (handle != INVALID_HANDLE_VALUE)
202 req->hkey = hkey;
203 req->file = handle;
204 ret = server_call_noerr( REQ_SAVE_REGISTRY );
205 CloseHandle( handle );
206 if (ret) unlink( name );
207 else if (rename( name, filename ) == -1)
209 ERR( "Failed to move %s to %s: ", name, filename );
210 perror( "rename" );
211 unlink( name );
214 HeapFree( GetProcessHeap(), 0, name );
218 /******************************************************************************
219 * SHELL_SaveRegistryBranch [Internal]
221 * Saves main registry branch specified by hkey.
223 static void SHELL_SaveRegistryBranch(HKEY hkey)
225 char *fn, *home;
227 /* Find out what to save to, get from config file */
228 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
229 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
231 /* FIXME: does this check apply to all keys written below ? */
232 if (!(home = getenv( "HOME" )))
233 ERR("Failed to get homedirectory of UID %ld.\n",(long) getuid());
235 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
236 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
238 switch (hkey)
240 case HKEY_CURRENT_USER:
241 fn = xmalloc( MAX_PATHNAME_LEN );
242 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
243 fn, MAX_PATHNAME_LEN - 1))
244 save_key( HKEY_CURRENT_USER, fn );
245 free (fn);
247 if (home && writeToHome)
249 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
250 strlen(SAVE_CURRENT_USER) + 2 );
251 strcpy(fn,home);
252 strcat(fn,WINE_PREFIX);
254 /* create the directory. don't care about errorcodes. */
255 mkdir(fn,0755); /* drwxr-xr-x */
256 strcat(fn,"/"SAVE_CURRENT_USER);
257 save_key( HKEY_CURRENT_USER, fn );
258 free(fn);
260 break;
261 case HKEY_LOCAL_MACHINE:
262 /* Try first saving according to the defined location in .winerc */
263 fn = xmalloc ( MAX_PATHNAME_LEN);
264 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
265 fn, MAX_PATHNAME_LEN - 1))
266 save_key( HKEY_LOCAL_MACHINE, fn );
267 free (fn);
269 if (home && writeToHome)
271 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
272 strlen(SAVE_LOCAL_MACHINE) + 2);
273 strcpy(fn,home);
274 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
275 save_key( HKEY_LOCAL_MACHINE, fn );
276 free(fn);
278 break;
279 case HKEY_USERS:
280 fn = xmalloc( MAX_PATHNAME_LEN );
281 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
282 fn, MAX_PATHNAME_LEN - 1))
283 save_key( HKEY_USERS, fn );
284 free (fn);
286 if (home && writeToHome)
288 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
289 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
290 strcpy(fn,home);
291 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
292 save_key( HKEY_USERS, fn );
293 free(fn);
295 break;
296 default:
297 ERR("unknown/invalid key handle !\n");
298 break;
303 /******************************************************************************
304 * SHELL_SaveRegistry [Internal]
306 void SHELL_SaveRegistry( void )
308 struct set_registry_levels_request *req = get_req_buffer();
309 char buf[4];
310 HKEY hkey;
311 int all;
313 TRACE("(void)\n");
315 all=0;
316 if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
318 strcpy(buf,"yes");
320 else
322 DWORD len,junk,type;
324 len=4;
325 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
326 VAL_SAVEUPDATED,
327 &junk,
328 &type,
329 buf,
330 &len)) || (type!=REG_SZ))
332 strcpy(buf,"yes");
334 RegCloseKey(hkey);
337 if (lstrcmpiA(buf,"yes")) all = 1;
339 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
340 req->current = 1;
341 req->saving = !all;
342 req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
343 server_call( REQ_SET_REGISTRY_LEVELS );
345 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
346 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
347 SHELL_SaveRegistryBranch(HKEY_USERS);
350 /* Periodic save callback */
351 static void CALLBACK periodic_save( ULONG_PTR dummy )
353 SHELL_SaveRegistry();
356 /************************ LOAD Registry Function ****************************/
360 /******************************************************************************
361 * _find_or_add_key [Internal]
363 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
365 HKEY subkey;
366 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
367 if (keyname) free( keyname );
368 return subkey;
371 /******************************************************************************
372 * _find_or_add_value [Internal]
374 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
376 RegSetValueExW( hkey, name, 0, type, data, len );
377 if (name) free( name );
378 if (data) free( data );
382 /******************************************************************************
383 * _wine_read_line [Internal]
385 * reads a line including dynamically enlarging the readbuffer and throwing
386 * away comments
388 static int _wine_read_line( FILE *F, char **buf, int *len )
390 char *s,*curread;
391 int mylen,curoff;
393 curread = *buf;
394 mylen = *len;
395 **buf = '\0';
396 while (1) {
397 while (1) {
398 s=fgets(curread,mylen,F);
399 if (s==NULL)
400 return 0; /* EOF */
401 if (NULL==(s=strchr(curread,'\n'))) {
402 /* buffer wasn't large enough */
403 curoff = strlen(*buf);
404 *buf = xrealloc(*buf,*len*2);
405 curread = *buf + curoff;
406 mylen = *len; /* we filled up the buffer and
407 * got new '*len' bytes to fill
409 *len = *len * 2;
410 } else {
411 *s='\0';
412 break;
415 /* throw away comments */
416 if (**buf=='#' || **buf==';') {
417 curread = *buf;
418 mylen = *len;
419 continue;
421 if (s) /* got end of line */
422 break;
424 return 1;
428 /******************************************************************************
429 * _wine_read_USTRING [Internal]
431 * converts a char* into a UNICODE string (up to a special char)
432 * and returns the position exactly after that string
434 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
436 char *s;
437 LPWSTR ws;
439 /* read up to "=" or "\0" or "\n" */
440 s = buf;
441 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
442 ws = *str;
443 while (*s && (*s!='\n') && (*s!='=')) {
444 if (*s!='\\')
445 *ws++=*((unsigned char*)s++);
446 else {
447 s++;
448 if (!*s) {
449 /* Dangling \ ... may only happen if a registry
450 * write was short. FIXME: What do to?
452 break;
454 if (*s=='\\') {
455 *ws++='\\';
456 s++;
457 continue;
459 if (*s!='u') {
460 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
461 *ws++='\\';
462 *ws++=*s++;
463 } else {
464 char xbuf[5];
465 int wc;
467 s++;
468 memcpy(xbuf,s,4);xbuf[4]='\0';
469 if (!sscanf(xbuf,"%x",&wc))
470 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
471 s+=4;
472 *ws++ =(unsigned short)wc;
476 *ws = 0;
477 return s;
481 /******************************************************************************
482 * _wine_loadsubkey [Internal]
484 * NOTES
485 * It seems like this is returning a boolean. Should it?
487 * RETURNS
488 * Success: 1
489 * Failure: 0
491 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
493 HKEY subkey;
494 int i;
495 char *s;
496 LPWSTR name;
498 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
500 /* Good. We already got a line here ... so parse it */
501 subkey = 0;
502 while (1) {
503 i=0;s=*buf;
504 while (*s=='\t') {
505 s++;
506 i++;
508 if (i>level) {
509 if (!subkey) {
510 WARN("Got a subhierarchy without resp. key?\n");
511 return 0;
513 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
514 if (!_wine_read_line(F,buf,buflen))
515 goto done;
516 continue;
519 /* let the caller handle this line */
520 if (i<level || **buf=='\0')
521 goto done;
523 /* it can be: a value or a keyname. Parse the name first */
524 s=_wine_read_USTRING(s,&name);
526 /* switch() default: hack to avoid gotos */
527 switch (0) {
528 default:
529 if (*s=='\0') {
530 if (subkey) RegCloseKey( subkey );
531 subkey=_find_or_add_key(hkey,name);
532 } else {
533 LPBYTE data;
534 int len,lastmodified,type;
536 if (*s!='=') {
537 WARN("Unexpected character: %c\n",*s);
538 break;
540 s++;
541 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
542 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
543 break;
545 /* skip the 2 , */
546 s=strchr(s,',');s++;
547 s=strchr(s,',');
548 if (!s++) {
549 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
550 break;
552 if (type == REG_SZ || type == REG_EXPAND_SZ) {
553 s=_wine_read_USTRING(s,(LPWSTR*)&data);
554 len = lstrlenW((LPWSTR)data)*2+2;
555 } else {
556 len=strlen(s)/2;
557 data = (LPBYTE)xmalloc(len+1);
558 for (i=0;i<len;i++) {
559 data[i]=0;
560 if (*s>='0' && *s<='9')
561 data[i]=(*s-'0')<<4;
562 if (*s>='a' && *s<='f')
563 data[i]=(*s-'a'+'\xa')<<4;
564 if (*s>='A' && *s<='F')
565 data[i]=(*s-'A'+'\xa')<<4;
566 s++;
567 if (*s>='0' && *s<='9')
568 data[i]|=*s-'0';
569 if (*s>='a' && *s<='f')
570 data[i]|=*s-'a'+'\xa';
571 if (*s>='A' && *s<='F')
572 data[i]|=*s-'A'+'\xa';
573 s++;
576 _find_or_add_value(hkey,name,type,data,len);
579 /* read the next line */
580 if (!_wine_read_line(F,buf,buflen))
581 goto done;
583 done:
584 if (subkey) RegCloseKey( subkey );
585 return 1;
589 /******************************************************************************
590 * _wine_loadsubreg [Internal]
592 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
594 int ver;
595 char *buf;
596 int buflen;
598 buf=xmalloc(10);buflen=10;
599 if (!_wine_read_line(F,&buf,&buflen)) {
600 free(buf);
601 return 0;
603 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
604 free(buf);
605 return 0;
607 if (ver!=REGISTRY_SAVE_VERSION) {
608 if (ver == 2) /* new version */
610 HANDLE file;
611 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
612 FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
614 struct load_registry_request *req = get_req_buffer();
615 req->hkey = hkey;
616 req->file = file;
617 req->name[0] = 0;
618 server_call( REQ_LOAD_REGISTRY );
619 CloseHandle( file );
621 free( buf );
622 return 1;
624 else
626 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
627 free(buf);
628 return 0;
631 if (!_wine_read_line(F,&buf,&buflen)) {
632 free(buf);
633 return 0;
635 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
636 free(buf);
637 return 0;
639 free(buf);
640 return 1;
644 /******************************************************************************
645 * _wine_loadreg [Internal]
647 static void _wine_loadreg( HKEY hkey, char *fn )
649 FILE *F;
651 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
653 F = fopen(fn,"rb");
654 if (F==NULL) {
655 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
656 return;
658 _wine_loadsubreg(F,hkey,fn);
659 fclose(F);
662 /* NT REGISTRY LOADER */
664 #ifdef HAVE_SYS_MMAN_H
665 # include <sys/mman.h>
666 #endif
668 #ifndef MAP_FAILED
669 #define MAP_FAILED ((LPVOID)-1)
670 #endif
672 #define NT_REG_BLOCK_SIZE 0x1000
674 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
675 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
676 #define NT_REG_KEY_BLOCK_ID 0x6b6e
677 #define NT_REG_VALUE_BLOCK_ID 0x6b76
678 #define NT_REG_HASH_BLOCK_ID 0x666c
679 #define NT_REG_NOHASH_BLOCK_ID 0x696c
680 #define NT_REG_KEY_BLOCK_TYPE 0x20
681 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
683 typedef struct
685 DWORD id; /* 0x66676572 'regf'*/
686 DWORD uk1; /* 0x04 */
687 DWORD uk2; /* 0x08 */
688 FILETIME DateModified; /* 0x0c */
689 DWORD uk3; /* 0x14 */
690 DWORD uk4; /* 0x18 */
691 DWORD uk5; /* 0x1c */
692 DWORD uk6; /* 0x20 */
693 DWORD RootKeyBlock; /* 0x24 */
694 DWORD BlockSize; /* 0x28 */
695 DWORD uk7[116];
696 DWORD Checksum; /* at offset 0x1FC */
697 } nt_regf;
699 typedef struct
701 DWORD blocksize;
702 BYTE data[1];
703 } nt_hbin_sub;
705 typedef struct
707 DWORD id; /* 0x6E696268 'hbin' */
708 DWORD off_prev;
709 DWORD off_next;
710 DWORD uk1;
711 DWORD uk2; /* 0x10 */
712 DWORD uk3; /* 0x14 */
713 DWORD uk4; /* 0x18 */
714 DWORD size; /* 0x1C */
715 nt_hbin_sub hbin_sub; /* 0x20 */
716 } nt_hbin;
719 * the value_list consists of offsets to the values (vk)
721 typedef struct
723 WORD SubBlockId; /* 0x00 0x6B6E */
724 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
725 FILETIME writetime; /* 0x04 */
726 DWORD uk1; /* 0x0C */
727 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
728 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
729 DWORD uk8; /* 0x18 */
730 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
731 DWORD uk2; /* 0x20 */
732 DWORD nr_values; /* 0x24 number of values */
733 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
734 DWORD off_sk; /* 0x2c Offset of the sk-Record */
735 DWORD off_class; /* 0x30 Offset of the Class-Name */
736 DWORD uk3; /* 0x34 */
737 DWORD uk4; /* 0x38 */
738 DWORD uk5; /* 0x3c */
739 DWORD uk6; /* 0x40 */
740 DWORD uk7; /* 0x44 */
741 WORD name_len; /* 0x48 name-length */
742 WORD class_len; /* 0x4a class-name length */
743 char name[1]; /* 0x4c key-name */
744 } nt_nk;
746 typedef struct
748 DWORD off_nk; /* 0x00 */
749 DWORD name; /* 0x04 */
750 } hash_rec;
752 typedef struct
754 WORD id; /* 0x00 0x666c */
755 WORD nr_keys; /* 0x06 */
756 hash_rec hash_rec[1];
757 } nt_lf;
759 typedef struct
761 WORD id; /* 0x00 0x696c */
762 WORD nr_keys;
763 DWORD off_nk[1];
764 } nt_il;
766 typedef struct
768 WORD id; /* 0x00 'vk' */
769 WORD nam_len;
770 DWORD data_len;
771 DWORD data_off;
772 DWORD type;
773 WORD flag;
774 WORD uk1;
775 char name[1];
776 } nt_vk;
778 LPSTR _strdupnA( LPCSTR str, int len )
780 LPSTR ret;
782 if (!str) return NULL;
783 ret = malloc( len + 1 );
784 lstrcpynA( ret, str, len );
785 ret[len] = 0x00;
786 return ret;
789 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
790 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
791 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
795 * gets a value
797 * vk->flag:
798 * 0 value is a default value
799 * 1 the value has a name
801 * vk->data_len
802 * len of the whole data block
803 * - reg_sz (unicode)
804 * bytes including the terminating \0 = 2*(number_of_chars+1)
805 * - reg_dword, reg_binary:
806 * if highest bit of data_len is set data_off contains the value
808 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
810 WCHAR name [256];
811 DWORD ret;
812 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
814 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
816 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
818 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
819 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
820 (vk->data_len & 0x7fffffff) );
821 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
822 return TRUE;
823 error:
824 ERR_(reg)("vk block invalid\n");
825 return FALSE;
829 * get the subkeys
831 * this structure contains the hash of a keyname and points to all
832 * subkeys
834 * exception: if the id is 'il' there are no hash values and every
835 * dword is a offset
837 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
839 int i;
841 if (lf->id == NT_REG_HASH_BLOCK_ID)
843 for (i=0; i<lf->nr_keys; i++)
845 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
849 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
851 for (i=0; i<lf->nr_keys; i++)
853 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
856 return TRUE;
858 error: ERR_(reg)("error reading lf block\n");
859 return FALSE;
862 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
864 char * name;
865 int i;
866 DWORD * vl;
867 HKEY subkey = hkey;
869 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID) goto error;
870 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
871 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) goto error;
873 /* create the new key */
874 if(level <= 0)
876 name = _strdupnA( nk->name, nk->name_len+1);
877 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
878 free(name);
881 /* loop through the subkeys */
882 if (nk->nr_subkeys)
884 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
885 if (nk->nr_subkeys != lf->nr_keys) goto error1;
886 if (!_nt_parse_lf(subkey, base, lf, level-1)) goto error1;
889 /* loop trough the value list */
890 vl = (DWORD *)(base+nk->valuelist_off+4);
891 for (i=0; i<nk->nr_values; i++)
893 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
894 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
897 RegCloseKey(subkey);
898 return TRUE;
900 error1: RegCloseKey(subkey);
901 error: ERR_(reg)("error reading nk block\n");
902 return FALSE;
905 /* end nt loader */
907 /* windows 95 registry loader */
909 /* SECTION 1: main header
911 * once at offset 0
913 #define W95_REG_CREG_ID 0x47455243
915 typedef struct
917 DWORD id; /* "CREG" = W95_REG_CREG_ID */
918 DWORD version; /* ???? 0x00010000 */
919 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
920 DWORD uk2; /* 0x0c */
921 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
922 WORD uk3;
923 DWORD uk[3];
924 /* rgkn */
925 } _w95creg;
927 /* SECTION 2: Directory information (tree structure)
929 * once on offset 0x20
931 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
933 #define W95_REG_RGKN_ID 0x4e4b4752
935 typedef struct
937 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
938 DWORD size; /* Size of the RGKN-block */
939 DWORD root_off; /* Rel. Offset of the root-record */
940 DWORD uk[5];
941 } _w95rgkn;
943 /* Disk Key Entry Structure
945 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
946 * hive itself. It looks the same like other keys. Even the ID-number can
947 * be any value.
949 * The "hash"-value is a value representing the key's name. Windows will not
950 * search for the name, but for a matching hash-value. if it finds one, it
951 * will compare the actual string info, otherwise continue with the next key.
952 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
953 * of the string which are smaller than 0x80 (128) to this D-Word.
955 * If you want to modify key names, also modify the hash-values, since they
956 * cannot be found again (although they would be displayed in REGEDIT)
957 * End of list-pointers are filled with 0xFFFFFFFF
959 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
960 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
961 * structure) and reading another RGDB_section.
963 * there is a one to one relationship between dke and dkh
965 /* key struct, once per key */
966 typedef struct
968 DWORD x1; /* Free entry indicator(?) */
969 DWORD hash; /* sum of bytes of keyname */
970 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
971 DWORD prevlvl; /* offset of previous key */
972 DWORD nextsub; /* offset of child key */
973 DWORD next; /* offset of sibling key */
974 WORD nrLS; /* id inside the rgdb block */
975 WORD nrMS; /* number of the rgdb block */
976 } _w95dke;
978 /* SECTION 3: key information, values and data
980 * structure:
981 * section: [blocks]* (repeat creg->rgdb_num times)
982 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
983 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
985 * An interesting relationship exists in RGDB_section. The value at offset
986 * 10 equals the value at offset 4 minus the value at offset 8. I have no
987 * idea at the moment what this means. (Kevin Cozens)
990 /* block header, once per block */
991 #define W95_REG_RGDB_ID 0x42444752
993 typedef struct
995 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
996 DWORD size; /* 0x04 */
997 DWORD uk1; /* 0x08 */
998 DWORD uk2; /* 0x0c */
999 DWORD uk3; /* 0x10 */
1000 DWORD uk4; /* 0x14 */
1001 DWORD uk5; /* 0x18 */
1002 DWORD uk6; /* 0x1c */
1003 /* dkh */
1004 } _w95rgdb;
1006 /* Disk Key Header structure (RGDB part), once per key */
1007 typedef struct
1009 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
1010 WORD nrLS; /* 0x04 id inside the rgdb block */
1011 WORD nrMS; /* 0x06 number of the rgdb block */
1012 DWORD bytesused; /* 0x08 */
1013 WORD keynamelen; /* 0x0c len of name */
1014 WORD values; /* 0x0e number of values */
1015 DWORD xx1; /* 0x10 */
1016 char name[1]; /* 0x14 */
1017 /* dkv */ /* 0x14 + keynamelen */
1018 } _w95dkh;
1020 /* Disk Key Value structure, once per value */
1021 typedef struct
1023 DWORD type; /* 0x00 */
1024 DWORD x1; /* 0x04 */
1025 WORD valnamelen; /* 0x08 length of name, 0 is default key */
1026 WORD valdatalen; /* 0x0A length of data */
1027 char name[1]; /* 0x0c */
1028 /* raw data */ /* 0x0c + valnamelen */
1029 } _w95dkv;
1031 /******************************************************************************
1032 * _w95_lookup_dkh [Internal]
1034 * seeks the dkh belonging to a dke
1036 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1038 _w95rgdb * rgdb;
1039 _w95dkh * dkh;
1040 int i;
1042 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
1043 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
1045 /* find the right block */
1046 for(i=0; i<nrMS ;i++)
1048 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
1049 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
1052 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
1056 if(nrLS==dkh->nrLS ) return dkh;
1057 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
1058 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1060 return NULL;
1063 /******************************************************************************
1064 * _w95_parse_dkv [Internal]
1066 static int _w95_parse_dkv (
1067 HKEY hkey,
1068 _w95dkh * dkh,
1069 int nrLS,
1070 int nrMS )
1072 _w95dkv * dkv;
1073 int i;
1074 DWORD ret;
1075 char * name;
1077 /* first value block */
1078 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1080 /* loop trought the values */
1081 for (i=0; i< dkh->values; i++)
1083 name = _strdupnA(dkv->name, dkv->valnamelen+1);
1084 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
1085 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1086 free (name);
1088 /* next value */
1089 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1091 return TRUE;
1094 /******************************************************************************
1095 * _w95_parse_dke [Internal]
1097 static int _w95_parse_dke(
1098 HKEY hkey,
1099 _w95creg * creg,
1100 _w95rgkn *rgkn,
1101 _w95dke * dke,
1102 int level )
1104 _w95dkh * dkh;
1105 HKEY hsubkey = hkey;
1106 char * name;
1107 int ret = FALSE;
1109 /* get start address of root key block */
1110 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1112 /* special root key */
1113 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
1115 /* parse the one subkey*/
1116 if (dke->nextsub != 0xffffffff)
1118 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1120 /* has no sibling keys */
1121 goto error;
1124 /* search subblock */
1125 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1127 fprintf(stderr, "dke pointing to missing dkh !\n");
1128 goto error;
1131 if ( level <= 0 )
1133 /* walk sibling keys */
1134 if (dke->next != 0xffffffff )
1136 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1139 /* create subkey and insert values */
1140 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1141 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1142 free(name);
1143 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1146 /* next sub key */
1147 if (dke->nextsub != 0xffffffff)
1149 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1152 ret = TRUE;
1153 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1154 error: return ret;
1156 /* end windows 95 loader */
1158 /******************************************************************************
1159 * NativeRegLoadKey [Internal]
1161 * Loads a native registry file (win95/nt)
1162 * hkey root key
1163 * fn filename
1164 * level number of levels to cut away (eg. ".Default" in user.dat)
1166 * this function intentionally uses unix file functions to make it possible
1167 * to move it to a seperate registry helper programm
1169 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1171 int fd = 0;
1172 struct stat st;
1173 DOS_FULL_NAME full_name;
1174 int ret = FALSE;
1175 void * base;
1177 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1179 /* map the registry into the memory */
1180 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1181 if ((fstat(fd, &st) == -1)) goto error;
1182 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1184 switch (*(LPDWORD)base)
1186 /* windows 95 'creg' */
1187 case W95_REG_CREG_ID:
1189 _w95creg * creg;
1190 _w95rgkn * rgkn;
1191 creg = base;
1192 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1194 /* load the header (rgkn) */
1195 rgkn = (_w95rgkn*)(creg + 1);
1196 if (rgkn->id != W95_REG_RGKN_ID)
1198 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1199 goto error1;
1202 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1204 break;
1205 /* nt 'regf'*/
1206 case NT_REG_HEADER_BLOCK_ID:
1208 nt_regf * regf;
1209 nt_hbin * hbin;
1210 nt_hbin_sub * hbin_sub;
1211 nt_nk* nk;
1213 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1215 /* start block */
1216 regf = base;
1218 /* hbin block */
1219 hbin = base + 0x1000;
1220 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1222 ERR_(reg)( "%s hbin block invalid\n", fn);
1223 goto error1;
1226 /* hbin_sub block */
1227 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1228 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1230 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1231 goto error1;
1234 /* nk block */
1235 nk = (nt_nk*)&(hbin_sub->data[0]);
1236 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1238 ERR_(reg)( "%s special nk block not found\n", fn);
1239 goto error1;
1242 ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
1244 break;
1245 default:
1247 ERR("unknown signature in registry file %s.\n",fn);
1248 goto error1;
1251 if(!ret) ERR("error loading registry file %s\n", fn);
1252 error1: munmap(base, st.st_size);
1253 error: close(fd);
1254 return ret;
1257 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1259 reghack - windows 3.11 registry data format demo program.
1261 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1262 a combined hash table and tree description, and finally a text table.
1264 The header is obvious from the struct header. The taboff1 and taboff2
1265 fields are always 0x20, and their usage is unknown.
1267 The 8-byte entry table has various entry types.
1269 tabent[0] is a root index. The second word has the index of the root of
1270 the directory.
1271 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1272 the index of the key/value that has that hash. Data with the same
1273 hash value are on a circular list. The other three words in the
1274 hash entry are always zero.
1275 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1276 entry: dirent and keyent/valent. They are identified by context.
1277 tabent[freeidx] is the first free entry. The first word in a free entry
1278 is the index of the next free entry. The last has 0 as a link.
1279 The other three words in the free list are probably irrelevant.
1281 Entries in text table are preceeded by a word at offset-2. This word
1282 has the value (2*index)+1, where index is the referring keyent/valent
1283 entry in the table. I have no suggestion for the 2* and the +1.
1284 Following the word, there are N bytes of data, as per the keyent/valent
1285 entry length. The offset of the keyent/valent entry is from the start
1286 of the text table to the first data byte.
1288 This information is not available from Microsoft. The data format is
1289 deduced from the reg.dat file by me. Mistakes may
1290 have been made. I claim no rights and give no guarantees for this program.
1292 Tor Sjøwall, tor@sn.no
1295 /* reg.dat header format */
1296 struct _w31_header {
1297 char cookie[8]; /* 'SHCC3.10' */
1298 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1299 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1300 unsigned long tabcnt; /* number of entries in index table */
1301 unsigned long textoff; /* offset of text part */
1302 unsigned long textsize; /* byte size of text part */
1303 unsigned short hashsize; /* hash size */
1304 unsigned short freeidx; /* free index */
1307 /* generic format of table entries */
1308 struct _w31_tabent {
1309 unsigned short w0, w1, w2, w3;
1312 /* directory tabent: */
1313 struct _w31_dirent {
1314 unsigned short sibling_idx; /* table index of sibling dirent */
1315 unsigned short child_idx; /* table index of child dirent */
1316 unsigned short key_idx; /* table index of key keyent */
1317 unsigned short value_idx; /* table index of value valent */
1320 /* key tabent: */
1321 struct _w31_keyent {
1322 unsigned short hash_idx; /* hash chain index for string */
1323 unsigned short refcnt; /* reference count */
1324 unsigned short length; /* length of string */
1325 unsigned short string_off; /* offset of string in text table */
1328 /* value tabent: */
1329 struct _w31_valent {
1330 unsigned short hash_idx; /* hash chain index for string */
1331 unsigned short refcnt; /* reference count */
1332 unsigned short length; /* length of string */
1333 unsigned short string_off; /* offset of string in text table */
1336 /* recursive helper function to display a directory tree */
1337 void
1338 __w31_dumptree( unsigned short idx,
1339 unsigned char *txt,
1340 struct _w31_tabent *tab,
1341 struct _w31_header *head,
1342 HKEY hkey,
1343 time_t lastmodified,
1344 int level
1346 struct _w31_dirent *dir;
1347 struct _w31_keyent *key;
1348 struct _w31_valent *val;
1349 HKEY subkey = 0;
1350 static char tail[400];
1352 while (idx!=0) {
1353 dir=(struct _w31_dirent*)&tab[idx];
1355 if (dir->key_idx) {
1356 key = (struct _w31_keyent*)&tab[dir->key_idx];
1358 memcpy(tail,&txt[key->string_off],key->length);
1359 tail[key->length]='\0';
1360 /* all toplevel entries AND the entries in the
1361 * toplevel subdirectory belong to \SOFTWARE\Classes
1363 if (!level && !lstrcmpA(tail,".classes")) {
1364 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1365 idx=dir->sibling_idx;
1366 continue;
1368 if (subkey) RegCloseKey( subkey );
1369 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1370 /* only add if leaf node or valued node */
1371 if (dir->value_idx!=0||dir->child_idx==0) {
1372 if (dir->value_idx) {
1373 val=(struct _w31_valent*)&tab[dir->value_idx];
1374 memcpy(tail,&txt[val->string_off],val->length);
1375 tail[val->length]='\0';
1376 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1379 } else {
1380 TRACE("strange: no directory key name, idx=%04x\n", idx);
1382 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1383 idx=dir->sibling_idx;
1385 if (subkey) RegCloseKey( subkey );
1389 /******************************************************************************
1390 * _w31_loadreg [Internal]
1392 void _w31_loadreg(void) {
1393 HFILE hf;
1394 struct _w31_header head;
1395 struct _w31_tabent *tab;
1396 unsigned char *txt;
1397 int len;
1398 OFSTRUCT ofs;
1399 BY_HANDLE_FILE_INFORMATION hfinfo;
1400 time_t lastmodified;
1402 TRACE("(void)\n");
1404 hf = OpenFile("reg.dat",&ofs,OF_READ);
1405 if (hf==HFILE_ERROR)
1406 return;
1408 /* read & dump header */
1409 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1410 ERR("reg.dat is too short.\n");
1411 _lclose(hf);
1412 return;
1414 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1415 ERR("reg.dat has bad signature.\n");
1416 _lclose(hf);
1417 return;
1420 len = head.tabcnt * sizeof(struct _w31_tabent);
1421 /* read and dump index table */
1422 tab = xmalloc(len);
1423 if (len!=_lread(hf,tab,len)) {
1424 ERR("couldn't read %d bytes.\n",len);
1425 free(tab);
1426 _lclose(hf);
1427 return;
1430 /* read text */
1431 txt = xmalloc(head.textsize);
1432 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1433 ERR("couldn't seek to textblock.\n");
1434 free(tab);
1435 free(txt);
1436 _lclose(hf);
1437 return;
1439 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1440 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1441 free(tab);
1442 free(txt);
1443 _lclose(hf);
1444 return;
1447 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1448 ERR("GetFileInformationByHandle failed?.\n");
1449 free(tab);
1450 free(txt);
1451 _lclose(hf);
1452 return;
1454 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1455 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1456 free(tab);
1457 free(txt);
1458 _lclose(hf);
1459 return;
1462 /**********************************************************************************
1463 * SetLoadLevel [Internal]
1465 * set level to 0 for loading system files
1466 * set level to 1 for loading user files
1468 static void SetLoadLevel(int level)
1470 struct set_registry_levels_request *req = get_req_buffer();
1472 req->current = level;
1473 req->saving = 0;
1474 req->version = 1;
1475 server_call( REQ_SET_REGISTRY_LEVELS );
1478 /**********************************************************************************
1479 * SHELL_LoadRegistry [Internal]
1481 #define REG_DONTLOAD -1
1482 #define REG_WIN31 0
1483 #define REG_WIN95 1
1484 #define REG_WINNT 2
1486 void SHELL_LoadRegistry( void )
1488 int save_timeout;
1489 char *fn, *home;
1490 HKEY hkey;
1491 char windir[MAX_PATHNAME_LEN];
1492 char path[MAX_PATHNAME_LEN];
1493 int systemtype = REG_WIN31;
1495 TRACE("(void)\n");
1497 if (!CLIENT_IsBootThread()) return; /* already loaded */
1499 REGISTRY_Init();
1500 SetLoadLevel(0);
1502 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1504 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1506 /* test %windir%/system32/config/system --> winnt */
1507 strcpy(path, windir);
1508 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1509 if(GetFileAttributesA(path) != -1)
1511 systemtype = REG_WINNT;
1513 else
1515 /* test %windir%/system.dat --> win95 */
1516 strcpy(path, windir);
1517 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1518 if(GetFileAttributesA(path) != -1)
1520 systemtype = REG_WIN95;
1524 if ((systemtype==REG_WINNT)
1525 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1527 MESSAGE("When you are running with a native NT directory specify\n");
1528 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1529 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1530 systemtype = REG_DONTLOAD;
1533 else
1535 /* only wine registry */
1536 systemtype = REG_DONTLOAD;
1539 switch (systemtype)
1541 case REG_WIN31:
1542 _w31_loadreg();
1543 break;
1545 case REG_WIN95:
1546 /* Load windows 95 entries */
1547 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1549 strcpy(path, windir);
1550 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1551 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1553 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1555 /* user specific user.dat */
1556 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1557 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1559 MESSAGE("can't load win95 user-registry %s\n", path);
1560 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1562 /* default user.dat */
1563 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1565 strcpy(path, windir);
1566 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1567 NativeRegLoadKey(hkey, path, 1);
1568 RegCloseKey(hkey);
1571 else
1573 /* global user.dat */
1574 strcpy(path, windir);
1575 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1576 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1578 break;
1580 case REG_WINNT:
1581 /* default user.dat */
1582 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1584 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1585 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1587 MESSAGE("can't load NT user-registry %s\n", path);
1588 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1592 /* default user.dat */
1593 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1595 strcpy(path, windir);
1596 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1597 NativeRegLoadKey(hkey, path, 1);
1598 RegCloseKey(hkey);
1602 * FIXME
1603 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1606 strcpy(path, windir);
1607 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1608 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1610 strcpy(path, windir);
1611 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1612 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1614 strcpy(path, windir);
1615 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1616 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1618 strcpy(path, windir);
1619 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1620 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1622 /* this key is generated when the nt-core booted successfully */
1623 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1624 RegCloseKey(hkey);
1625 break;
1626 } /* switch */
1628 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1631 * Load the global HKU hive directly from sysconfdir
1633 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1636 * Load the global machine defaults directly form sysconfdir
1638 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1641 SetLoadLevel(1);
1644 * Load the user saved registries
1646 if (!(home = getenv( "HOME" )))
1647 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1648 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1651 * Load user's personal versions of global HKU/.Default keys
1653 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1654 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1655 strcpy(fn, home);
1656 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1657 _wine_loadreg( HKEY_USERS, fn );
1658 free(fn);
1660 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1661 strcpy(fn, home);
1662 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1663 _wine_loadreg( HKEY_CURRENT_USER, fn );
1664 free(fn);
1667 * Load HKLM, attempt to get the registry location from the config
1668 * file first, if exist, load and keep going.
1670 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1671 strcpy(fn,home);
1672 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1673 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1674 free(fn);
1678 * Load HKCU, get the registry location from the config
1679 * file, if exist, load and keep going.
1681 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1683 fn = xmalloc( MAX_PATHNAME_LEN );
1684 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1685 fn, MAX_PATHNAME_LEN - 1))
1687 _wine_loadreg( HKEY_CURRENT_USER, fn );
1689 free (fn);
1691 * Load HKU, get the registry location from the config
1692 * file, if exist, load and keep going.
1694 fn = xmalloc ( MAX_PATHNAME_LEN );
1695 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1696 fn, MAX_PATHNAME_LEN - 1))
1698 _wine_loadreg( HKEY_USERS, fn );
1700 free (fn);
1702 * Load HKLM, get the registry location from the config
1703 * file, if exist, load and keep going.
1705 fn = xmalloc ( MAX_PATHNAME_LEN );
1706 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1707 fn, MAX_PATHNAME_LEN - 1))
1709 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1711 free (fn);
1715 * Make sure the update mode is there
1717 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1719 DWORD junk,type,len;
1720 char data[5];
1722 len=4;
1723 if (( RegQueryValueExA(
1724 hkey,
1725 VAL_SAVEUPDATED,
1726 &junk,
1727 &type,
1728 data,
1729 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1731 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1734 RegCloseKey(hkey);
1737 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1739 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1744 /********************* API FUNCTIONS ***************************************/
1749 /******************************************************************************
1750 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1751 * Immediately writes key to registry.
1752 * Only returns after data has been written to disk.
1754 * FIXME: does it really wait until data is written ?
1756 * PARAMS
1757 * hkey [I] Handle of key to write
1759 * RETURNS
1760 * Success: ERROR_SUCCESS
1761 * Failure: Error code
1763 DWORD WINAPI RegFlushKey( HKEY hkey )
1765 FIXME( "(%x): stub\n", hkey );
1766 return ERROR_SUCCESS;
1769 /******************************************************************************
1770 * RegConnectRegistry32W [ADVAPI32.128]
1772 * PARAMS
1773 * lpMachineName [I] Address of name of remote computer
1774 * hHey [I] Predefined registry handle
1775 * phkResult [I] Address of buffer for remote registry handle
1777 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1778 LPHKEY phkResult )
1780 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1782 if (!lpMachineName || !*lpMachineName) {
1783 /* Use the local machine name */
1784 return RegOpenKey16( hKey, "", phkResult );
1787 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1788 return ERROR_BAD_NETPATH;
1792 /******************************************************************************
1793 * RegConnectRegistry32A [ADVAPI32.127]
1795 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1797 DWORD ret;
1798 LPWSTR machineW = strdupA2W(machine);
1799 ret = RegConnectRegistryW( machineW, hkey, reskey );
1800 free(machineW);
1801 return ret;
1805 /******************************************************************************
1806 * RegGetKeySecurity [ADVAPI32.144]
1807 * Retrieves a copy of security descriptor protecting the registry key
1809 * PARAMS
1810 * hkey [I] Open handle of key to set
1811 * SecurityInformation [I] Descriptor contents
1812 * pSecurityDescriptor [O] Address of descriptor for key
1813 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1815 * RETURNS
1816 * Success: ERROR_SUCCESS
1817 * Failure: Error code
1819 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1820 SECURITY_INFORMATION SecurityInformation,
1821 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1822 LPDWORD lpcbSecurityDescriptor )
1824 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1825 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1827 /* FIXME: Check for valid SecurityInformation values */
1829 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1830 return ERROR_INSUFFICIENT_BUFFER;
1832 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1833 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1835 return ERROR_SUCCESS;
1839 /******************************************************************************
1840 * RegNotifyChangeKeyValue [ADVAPI32.???]
1842 * PARAMS
1843 * hkey [I] Handle of key to watch
1844 * fWatchSubTree [I] Flag for subkey notification
1845 * fdwNotifyFilter [I] Changes to be reported
1846 * hEvent [I] Handle of signaled event
1847 * fAsync [I] Flag for asynchronous reporting
1849 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1850 DWORD fdwNotifyFilter, HANDLE hEvent,
1851 BOOL fAsync )
1853 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1854 hEvent,fAsync);
1855 return ERROR_SUCCESS;
1859 /******************************************************************************
1860 * RegUnLoadKey32W [ADVAPI32.173]
1862 * PARAMS
1863 * hkey [I] Handle of open key
1864 * lpSubKey [I] Address of name of subkey to unload
1866 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1868 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1869 return ERROR_SUCCESS;
1873 /******************************************************************************
1874 * RegUnLoadKey32A [ADVAPI32.172]
1876 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1878 LONG ret;
1879 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1880 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1881 if(lpSubKeyW) free(lpSubKeyW);
1882 return ret;
1886 /******************************************************************************
1887 * RegSetKeySecurity [ADVAPI32.167]
1889 * PARAMS
1890 * hkey [I] Open handle of key to set
1891 * SecurityInfo [I] Descriptor contents
1892 * pSecurityDesc [I] Address of descriptor for key
1894 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1895 PSECURITY_DESCRIPTOR pSecurityDesc )
1897 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1899 /* It seems to perform this check before the hkey check */
1900 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1901 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1902 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1903 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1904 /* Param OK */
1905 } else
1906 return ERROR_INVALID_PARAMETER;
1908 if (!pSecurityDesc)
1909 return ERROR_INVALID_PARAMETER;
1911 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1913 return ERROR_SUCCESS;
1917 /******************************************************************************
1918 * RegRestoreKey32W [ADVAPI32.164]
1920 * PARAMS
1921 * hkey [I] Handle of key where restore begins
1922 * lpFile [I] Address of filename containing saved tree
1923 * dwFlags [I] Optional flags
1925 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1927 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1929 /* It seems to do this check before the hkey check */
1930 if (!lpFile || !*lpFile)
1931 return ERROR_INVALID_PARAMETER;
1933 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1935 /* Check for file existence */
1937 return ERROR_SUCCESS;
1941 /******************************************************************************
1942 * RegRestoreKey32A [ADVAPI32.163]
1944 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1946 LONG ret;
1947 LPWSTR lpFileW = strdupA2W(lpFile);
1948 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1949 if(lpFileW) free(lpFileW);
1950 return ret;
1954 /******************************************************************************
1955 * RegReplaceKey32W [ADVAPI32.162]
1957 * PARAMS
1958 * hkey [I] Handle of open key
1959 * lpSubKey [I] Address of name of subkey
1960 * lpNewFile [I] Address of filename for file with new data
1961 * lpOldFile [I] Address of filename for backup file
1963 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1964 LPCWSTR lpOldFile )
1966 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1967 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1968 return ERROR_SUCCESS;
1972 /******************************************************************************
1973 * RegReplaceKey32A [ADVAPI32.161]
1975 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1976 LPCSTR lpOldFile )
1978 LONG ret;
1979 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1980 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1981 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1982 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1983 free(lpOldFileW);
1984 free(lpNewFileW);
1985 free(lpSubKeyW);
1986 return ret;
1994 /* 16-bit functions */
1996 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1997 * some programs. Do not remove those cases. -MM
1999 static inline void fix_win16_hkey( HKEY *hkey )
2001 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
2004 /******************************************************************************
2005 * RegEnumKey16 [KERNEL.216] [SHELL.7]
2007 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2009 fix_win16_hkey( &hkey );
2010 return RegEnumKeyA( hkey, index, name, name_len );
2013 /******************************************************************************
2014 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2016 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2018 fix_win16_hkey( &hkey );
2019 return RegOpenKeyA( hkey, name, retkey );
2022 /******************************************************************************
2023 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2025 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2027 fix_win16_hkey( &hkey );
2028 return RegCreateKeyA( hkey, name, retkey );
2031 /******************************************************************************
2032 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2034 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2036 fix_win16_hkey( &hkey );
2037 return RegDeleteKeyA( hkey, name );
2040 /******************************************************************************
2041 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2043 DWORD WINAPI RegCloseKey16( HKEY hkey )
2045 fix_win16_hkey( &hkey );
2046 return RegCloseKey( hkey );
2049 /******************************************************************************
2050 * RegSetValue16 [KERNEL.221] [SHELL.5]
2052 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2054 fix_win16_hkey( &hkey );
2055 return RegSetValueA( hkey, name, type, data, count );
2058 /******************************************************************************
2059 * RegDeleteValue16 [KERNEL.222]
2061 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2063 fix_win16_hkey( &hkey );
2064 return RegDeleteValueA( hkey, name );
2067 /******************************************************************************
2068 * RegEnumValue16 [KERNEL.223]
2070 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2071 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2073 fix_win16_hkey( &hkey );
2074 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2077 /******************************************************************************
2078 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2080 * NOTES
2081 * Is this HACK still applicable?
2083 * HACK
2084 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2085 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2086 * Aldus FH4)
2088 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2090 fix_win16_hkey( &hkey );
2091 if (count) *count &= 0xffff;
2092 return RegQueryValueA( hkey, name, data, count );
2095 /******************************************************************************
2096 * RegQueryValueEx16 [KERNEL.225]
2098 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2099 LPBYTE data, LPDWORD count )
2101 fix_win16_hkey( &hkey );
2102 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2105 /******************************************************************************
2106 * RegSetValueEx16 [KERNEL.226]
2108 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2109 CONST BYTE *data, DWORD count )
2111 fix_win16_hkey( &hkey );
2112 return RegSetValueExA( hkey, name, reserved, type, data, count );