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.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/fcntl.h>
39 #include "wine/winbase16.h"
40 #include "wine/winestring.h"
44 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(reg)
53 static void REGISTRY_Init(void);
54 /* FIXME: following defines should be configured global ... */
56 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
57 #define WINE_PREFIX "/.wine"
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 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
67 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
70 /* what valuetypes do we need to convert? */
71 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
77 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
78 * If so, can we remove them?
80 * No, the memory handling functions are called very often in here,
81 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
82 * loading 100 times slower. -MM
84 static LPWSTR strdupA2W(LPCSTR src)
87 LPWSTR dest=xmalloc(2*strlen(src)+2);
88 lstrcpyAtoW(dest,src);
94 LPWSTR strcvtA2W(LPCSTR src, int nchars)
97 LPWSTR dest = xmalloc (2 * nchars + 2);
99 lstrcpynAtoW(dest,src,nchars+1);
106 /******************************************************************************
107 * REGISTRY_Init [Internal]
108 * Registry initialisation, allocates some default keys.
110 static void REGISTRY_Init(void) {
116 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&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"));
125 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
129 * string RegisteredOwner
130 * string RegisteredOrganization
133 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
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);
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.
155 * "WINE REGISTRY Version %d"
159 * valuename=lastmodified,type,data
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.)
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();
184 char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
187 strcpy( name, filename );
188 if ((p = strrchr( name, '/' ))) p++;
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)
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 );
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)
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;
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 );
247 if (home && writeToHome)
249 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
250 strlen(SAVE_CURRENT_USER) + 2 );
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 );
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 );
269 if (home && writeToHome)
271 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
272 strlen(SAVE_LOCAL_MACHINE) + 2);
274 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
275 save_key( HKEY_LOCAL_MACHINE, fn );
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 );
286 if (home && writeToHome)
288 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
289 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
291 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
292 save_key( HKEY_USERS, fn );
297 ERR("unknown/invalid key handle !\n");
303 /******************************************************************************
304 * SHELL_SaveRegistry [Internal]
306 void SHELL_SaveRegistry( void )
308 struct set_registry_levels_request *req = get_req_buffer();
316 if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
325 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
330 &len)) || (type!=REG_SZ))
337 if (lstrcmpiA(buf,"yes")) all = 1;
339 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
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 )
366 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
367 if (keyname) free( keyname );
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
388 static int _wine_read_line( FILE *F, char **buf, int *len )
398 s=fgets(curread,mylen,F);
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
415 /* throw away comments */
416 if (**buf=='#' || **buf==';') {
421 if (s) /* got end of line */
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 )
439 /* read up to "=" or "\0" or "\n" */
441 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
443 while (*s && (*s!='\n') && (*s!='=')) {
445 *ws++=*((unsigned char*)s++);
449 /* Dangling \ ... may only happen if a registry
450 * write was short. FIXME: What do to?
460 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
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);
472 *ws++ =(unsigned short)wc;
481 /******************************************************************************
482 * _wine_loadsubkey [Internal]
485 * It seems like this is returning a boolean. Should it?
491 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
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 */
510 WARN("Got a subhierarchy without resp. key?\n");
513 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
514 if (!_wine_read_line(F,buf,buflen))
519 /* let the caller handle this line */
520 if (i<level || **buf=='\0')
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 */
530 if (subkey) RegCloseKey( subkey );
531 subkey=_find_or_add_key(hkey,name);
534 int len,lastmodified,type;
537 WARN("Unexpected character: %c\n",*s);
541 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
542 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
549 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
552 if (type == REG_SZ || type == REG_EXPAND_SZ) {
553 s=_wine_read_USTRING(s,(LPWSTR*)&data);
554 len = lstrlenW((LPWSTR)data)*2+2;
557 data = (LPBYTE)xmalloc(len+1);
558 for (i=0;i<len;i++) {
560 if (*s>='0' && *s<='9')
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;
567 if (*s>='0' && *s<='9')
569 if (*s>='a' && *s<='f')
570 data[i]|=*s-'a'+'\xa';
571 if (*s>='A' && *s<='F')
572 data[i]|=*s-'A'+'\xa';
576 _find_or_add_value(hkey,name,type,data,len);
579 /* read the next line */
580 if (!_wine_read_line(F,buf,buflen))
584 if (subkey) RegCloseKey( subkey );
589 /******************************************************************************
590 * _wine_loadsubreg [Internal]
592 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
598 buf=xmalloc(10);buflen=10;
599 if (!_wine_read_line(F,&buf,&buflen)) {
603 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
607 if (ver!=REGISTRY_SAVE_VERSION) {
608 if (ver == 2) /* new version */
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();
618 server_call( REQ_LOAD_REGISTRY );
626 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
631 if (!_wine_read_line(F,&buf,&buflen)) {
635 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
644 /******************************************************************************
645 * _wine_loadreg [Internal]
647 static void _wine_loadreg( HKEY hkey, char *fn )
651 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
655 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
658 _wine_loadsubreg(F,hkey,fn);
662 /******************************************************************************
663 * _flush_registry [Internal]
665 * This function allow to flush section of the internal registry. It is mainly
666 * implements to fix a problem with the global HKU and the local HKU.
667 * Those two files are read to build the HKU\.Default branch to finaly copy
668 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
669 * all the global HKU are saved onto the user's personal version of HKU hive.
673 static void _flush_registry( HKEY hkey )
675 WCHAR name[MAX_PATH];
680 /* FIXME: we assume that deleting a key will move the other ones up, */
681 /* so that we can always use index 0 until there are no more keys */
682 if (RegEnumKeyW( hkey, 0, name, sizeof(name) ) != ERROR_SUCCESS) break;
683 if (RegOpenKeyW( hkey, name, &subkey ) != ERROR_SUCCESS) break;
684 _flush_registry( subkey );
685 if (RegDeleteKeyW( subkey, NULL ) != ERROR_SUCCESS) break;
686 RegCloseKey( subkey );
691 /******************************************************************************
692 * _copy_registry [Internal]
694 static void _copy_registry( HKEY from, HKEY to )
699 DWORD type, name_len, len;
700 static WCHAR name[MAX_PATH];
701 static BYTE data[2048];
708 name_len = sizeof(name);
709 if (RegEnumValueW( from, index++, name, &name_len,
710 NULL, &type, data, &len ) != ERROR_SUCCESS) break;
711 RegSetValueExW( to, name, 0, type, data, len );
718 name_len = sizeof(name);
719 if (RegEnumKeyExW( from, index++, name, &name_len,
720 NULL, NULL, 0, &ft ) != ERROR_SUCCESS)
722 if (RegOpenKeyW( from, name, &subkey ) == ERROR_SUCCESS)
725 if (RegCreateKeyW( to, name, &newsub ) == ERROR_SUCCESS)
727 _copy_registry( subkey, newsub );
728 RegCloseKey( newsub );
730 RegCloseKey( subkey );
734 /* NT REGISTRY LOADER */
735 #include <sys/mman.h>
738 #define MAP_FAILED ((LPVOID)-1)
743 #define REG_BLOCK_SIZE 0x1000
745 #define REG_HEADER_BLOCK_ID 0x66676572 /* regf */
746 #define REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
747 #define REG_KEY_BLOCK_ID 0x6b6e
748 #define REG_VALUE_BLOCK_ID 0x6b76
749 #define REG_HASH_BLOCK_ID 0x666c
750 #define REG_NOHASH_BLOCK_ID 0x696c
751 #define REG_KEY_BLOCK_TYPE 0x20
752 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
756 DWORD id; /* 0x66676572 'regf'*/
757 DWORD uk1; /* 0x04 */
758 DWORD uk2; /* 0x08 */
759 FILETIME DateModified; /* 0x0c */
760 DWORD uk3; /* 0x14 */
761 DWORD uk4; /* 0x18 */
762 DWORD uk5; /* 0x1c */
763 DWORD uk6; /* 0x20 */
764 DWORD RootKeyBlock; /* 0x24 */
765 DWORD BlockSize; /* 0x28 */
767 DWORD Checksum; /* at offset 0x1FC */
778 DWORD id; /* 0x6E696268 'hbin' */
782 DWORD uk2; /* 0x10 */
783 DWORD uk3; /* 0x14 */
784 DWORD uk4; /* 0x18 */
785 DWORD size; /* 0x1C */
786 nt_hbin_sub hbin_sub; /* 0x20 */
790 * the value_list consists of offsets to the values (vk)
794 WORD SubBlockId; /* 0x00 0x6B6E */
795 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
796 FILETIME writetime; /* 0x04 */
797 DWORD uk1; /* 0x0C */
798 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
799 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
800 DWORD uk8; /* 0x18 */
801 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
802 DWORD uk2; /* 0x20 */
803 DWORD nr_values; /* 0x24 number of values */
804 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
805 DWORD off_sk; /* 0x2c Offset of the sk-Record */
806 DWORD off_class; /* 0x30 Offset of the Class-Name */
807 DWORD uk3; /* 0x34 */
808 DWORD uk4; /* 0x38 */
809 DWORD uk5; /* 0x3c */
810 DWORD uk6; /* 0x40 */
811 DWORD uk7; /* 0x44 */
812 WORD name_len; /* 0x48 name-length */
813 WORD class_len; /* 0x4a class-name length */
814 char name[1]; /* 0x4c key-name */
819 DWORD off_nk; /* 0x00 */
820 DWORD name; /* 0x04 */
825 WORD id; /* 0x00 0x666c */
826 WORD nr_keys; /* 0x06 */
827 hash_rec hash_rec[1];
832 WORD id; /* 0x00 0x696c */
839 WORD id; /* 0x00 'vk' */
850 #define vk_expsz 0x0002
851 #define vk_bin 0x0003
852 #define vk_dword 0x0004
853 #define vk_multisz 0x0007
857 LPSTR _strdupnA( LPCSTR str, int len )
861 if (!str) return NULL;
862 ret = malloc( len + 1 );
863 lstrcpynA( ret, str, len );
868 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
869 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level);
870 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
877 * 0 value is a default value
878 * 1 the value has a name
881 * len of the whole data block
883 * bytes including the terminating \0 = 2*(number_of_chars+1)
884 * - reg_dword, reg_binary:
885 * if highest bit of data_len is set data_off contains the value
887 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level)
891 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
893 if(vk->id != REG_VALUE_BLOCK_ID) goto error;
895 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
897 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
898 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
899 (vk->data_len & 0x7fffffff) );
900 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
903 ERR_(reg)("vk block invalid\n");
910 * this structure contains the hash of a keyname and points to all
913 * exception: if the id is 'il' there are no hash values and every
916 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
920 if (lf->id == REG_HASH_BLOCK_ID)
922 for (i=0; i<lf->nr_keys; i++)
924 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
928 else if (lf->id == REG_NOHASH_BLOCK_ID)
930 for (i=0; i<lf->nr_keys; i++)
932 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
937 error: ERR_(reg)("error reading lf block\n");
941 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
948 if(nk->SubBlockId != REG_KEY_BLOCK_ID) goto error;
949 if((nk->Type!=REG_ROOT_KEY_BLOCK_TYPE) &&
950 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != REG_KEY_BLOCK_ID)) goto error;
952 /* create the new key */
953 name = _strdupnA( nk->name, nk->name_len+1);
954 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
957 /* loop through the subkeys */
960 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
961 if (nk->nr_subkeys != lf->nr_keys) goto error1;
962 if (!_nt_parse_lf(subkey, base, lf, level+1)) goto error1;
965 /* loop trough the value list */
966 vl = (DWORD *)(base+nk->valuelist_off+4);
967 for (i=0; i<nk->nr_values; i++)
969 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
970 if (!_nt_parse_vk(subkey, base, vk, level+1 )) goto error1;
976 error1: RegCloseKey(subkey);
977 error: ERR_(reg)("error reading nk block\n");
982 * this function intentionally uses unix file functions to make it possible
983 * to move it to a seperate registry helper programm
985 static int _nt_loadreg( HKEY hkey, char* fn )
992 nt_hbin_sub * hbin_sub;
994 DOS_FULL_NAME full_name;
996 if (!DOSFS_GetFullName( fn, 0, &full_name ));
998 TRACE_(reg)("Loading NT registry database '%s' '%s'\n",fn, full_name.long_name);
1000 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1001 if (fstat(fd, &st ) == -1) goto error1;
1003 if ((base=mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1007 if(regf->id != REG_HEADER_BLOCK_ID) /* 'regf' */
1009 ERR( "%s is not a nt-registry\n", fn);
1012 TRACE_(reg)( "%p [regf] offset=%lx size=%lx\n", regf, regf->RootKeyBlock, regf->BlockSize);
1015 hbin = base + 0x1000;
1016 if (hbin->id != REG_POOL_BLOCK_ID)
1018 ERR_(reg)( "%s hbin block invalid\n", fn);
1021 TRACE_(reg)( "%p [hbin] prev=%lx next=%lx size=%lx\n", hbin, hbin->off_prev, hbin->off_next, hbin->size);
1023 /* hbin_sub block */
1024 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1025 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1027 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1030 TRACE_(reg)( "%p [hbin sub] size=%lx\n", hbin_sub, hbin_sub->blocksize);
1033 nk = (nt_nk*)&(hbin_sub->data[0]);
1034 if (nk->Type != REG_ROOT_KEY_BLOCK_TYPE)
1036 ERR_(reg)( "%s special nk block not found\n", fn);
1040 _nt_parse_nk (hkey, base+0x1000, nk, 0);
1046 error: munmap(base, len);
1048 ERR_(reg)("error reading registry file\n");
1053 /* WINDOWS 95 REGISTRY LOADER */
1055 * Structure of a win95 registry database.
1057 * 0 : "CREG" - magic
1059 * 8 : DWORD offset_of_RGDB_part
1060 * 0C..0F: ? (someone fill in please)
1061 * 10: WORD number of RGDB blocks
1063 * 14: WORD always 0000?
1064 * 16: WORD always 0001?
1065 * 18..1F: ? (someone fill in please)
1069 * 0 : "RGKN" - magic
1070 * 4 : DWORD offset to first RGDB section
1071 * 8 : DWORD offset to the root record
1072 * C..0x1B: ? (fill in)
1073 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1075 * Disk Key Entry Structure:
1076 * 00: DWORD - Free entry indicator(?)
1077 * 04: DWORD - Hash = sum of bytes of keyname
1078 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1079 * 0C: DWORD - disk address of PreviousLevel Key.
1080 * 10: DWORD - disk address of Next Sublevel Key.
1081 * 14: DWORD - disk address of Next Key (on same level).
1082 * DKEP>18: WORD - Nr, Low Significant part.
1083 * 1A: WORD - Nr, High Significant part.
1085 * The disk address always points to the nr part of the previous key entry
1086 * of the referenced key. Don't ask me why, or even if I got this correct
1087 * from staring at 1kg of hexdumps. (DKEP)
1089 * The High significant part of the structure seems to equal the number
1090 * of the RGDB section. The low significant part is a unique ID within
1093 * There are two minor corrections to the position of that structure.
1094 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1095 * the DKE reread from there.
1096 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1097 * CPS - I have not experienced the above phenomenon in my registry files
1100 * 00: "RGDB" - magic
1101 * 04: DWORD offset to next RGDB section
1103 * 0C: WORD always 000d?
1104 * 0E: WORD RGDB block number
1105 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1107 * 20.....: disk keys
1110 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1111 * 08: WORD nrLS - low significant part of NR
1112 * 0A: WORD nrHS - high significant part of NR
1113 * 0C: DWORD bytesused - bytes used in this structure.
1114 * 10: WORD name_len - length of name in bytes. without \0
1115 * 12: WORD nr_of_values - number of values.
1116 * 14: char name[name_len] - name string. No \0.
1117 * 14+name_len: disk values
1118 * nextkeyoffset: ... next disk key
1121 * 00: DWORD type - value type (hmm, could be WORD too)
1122 * 04: DWORD - unknown, usually 0
1123 * 08: WORD namelen - length of Name. 0 means name=NULL
1124 * 0C: WORD datalen - length of Data.
1125 * 10: char name[namelen] - name, no \0
1126 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1127 * 10+namelen+datalen: next values or disk key
1129 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1130 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1131 * structure) and reading another RGDB_section.
1132 * repeat until end of file.
1134 * An interesting relationship exists in RGDB_section. The value at offset
1135 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1136 * idea at the moment what this means. (Kevin Cozens)
1138 * FIXME: this description needs some serious help, yes.
1141 struct _w95keyvalue {
1143 unsigned short datalen;
1145 unsigned char *data;
1153 struct _w95keyvalue *values;
1154 struct _w95key *prevlvl;
1155 struct _w95key *nextsub;
1156 struct _w95key *next;
1170 /******************************************************************************
1171 * _w95_processKey [Internal]
1173 static HKEY _w95_processKey ( HKEY hkey, int nrLS, int nrMS, struct _w95_info *info )
1176 /* Disk Key Header structure (RGDB part) */
1178 unsigned long nextkeyoff;
1179 unsigned short nrLS;
1180 unsigned short nrMS;
1181 unsigned long bytesused;
1182 unsigned short keynamelen;
1183 unsigned short values;
1186 /* disk key values or nothing */
1188 /* Disk Key Value structure */
1192 unsigned short valnamelen;
1193 unsigned short valdatalen;
1194 /* valname, valdata */
1200 char *rgdbdata = info->rgdbbuffer;
1201 int nbytes = info->rgdbsize;
1202 char *curdata = rgdbdata;
1203 char *end = rgdbdata + nbytes;
1205 char *next = rgdbdata;
1211 if (strncmp(curdata, "RGDB", 4)) return 0;
1213 memcpy(&off_next_rgdb,curdata+4,4);
1214 next = curdata + off_next_rgdb;
1215 nrgdb = (int) *((short *)curdata + 7);
1217 } while (nrgdb != nrMS && (next < end));
1219 /* curdata now points to the start of the right RGDB section */
1222 #define XREAD(whereto,len) \
1223 if ((curdata + len) <= end) {\
1224 memcpy(whereto,curdata,len);\
1229 while (curdata < next) {
1230 struct dkh *xdkh = (struct dkh*)curdata;
1232 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1233 if (xdkh->nrLS == nrLS) {
1234 memcpy(&dkh,xdkh,sizeof(dkh));
1235 curdata += sizeof(dkh);
1238 curdata += xdkh->nextkeyoff;
1241 if (dkh.nrLS != nrLS) return 0;
1243 if (nrgdb != dkh.nrMS)
1246 assert((dkh.keynamelen<2) || curdata[0]);
1247 subkey=_find_or_add_key(hkey,strcvtA2W(curdata, dkh.keynamelen));
1248 curdata += dkh.keynamelen;
1250 for (i=0;i< dkh.values; i++) {
1256 XREAD(&dkv,sizeof(dkv));
1258 name = strcvtA2W(curdata, dkv.valnamelen);
1259 curdata += dkv.valnamelen;
1261 if ((1 << dkv.type) & UNICONVMASK) {
1262 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1263 len = 2*(dkv.valdatalen + 1);
1265 /* I don't think we want to NULL terminate all data */
1266 data = xmalloc(dkv.valdatalen);
1267 memcpy (data, curdata, dkv.valdatalen);
1268 len = dkv.valdatalen;
1271 curdata += dkv.valdatalen;
1273 _find_or_add_value( subkey, name, dkv.type, data, len );
1278 /******************************************************************************
1279 * _w95_walkrgkn [Internal]
1281 static void _w95_walkrgkn( HKEY prevkey, char *off,
1282 struct _w95_info *info )
1285 /* Disk Key Entry structure (RGKN part) */
1289 unsigned long x3;/*usually 0xFFFFFFFF */
1290 unsigned long prevlvl;
1291 unsigned long nextsub;
1293 unsigned short nrLS;
1294 unsigned short nrMS;
1295 } *dke = (struct dke *)off;
1299 dke = (struct dke *) ((char *)info->rgknbuffer);
1302 subkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1304 if (dke->nextsub != -1 &&
1305 ((dke->nextsub - 0x20) < info->rgknsize)
1306 && (dke->nextsub > 0x20)) {
1308 _w95_walkrgkn(subkey ? subkey : prevkey, /* XXX <-- This is a hack*/
1309 info->rgknbuffer + dke->nextsub - 0x20,
1312 if (subkey) RegCloseKey( subkey );
1314 if (dke->next != -1 &&
1315 ((dke->next - 0x20) < info->rgknsize) &&
1316 (dke->next > 0x20)) {
1317 _w95_walkrgkn(prevkey,
1318 info->rgknbuffer + dke->next - 0x20,
1324 /******************************************************************************
1325 * _w95_loadreg [Internal]
1327 static void _w95_loadreg( char* fn, HKEY hkey )
1331 unsigned long where,version,rgdbsection,end;
1332 struct _w95_info info;
1334 BY_HANDLE_FILE_INFORMATION hfdinfo;
1336 TRACE("Loading Win95 registry database '%s'\n",fn);
1337 hfd=OpenFile(fn,&ofs,OF_READ);
1338 if (hfd==HFILE_ERROR)
1341 if (4!=_lread(hfd,magic,4))
1343 if (strcmp(magic,"CREG")) {
1344 WARN("%s is not a w95 registry.\n",fn);
1347 if (4!=_lread(hfd,&version,4))
1349 if (4!=_lread(hfd,&rgdbsection,4))
1351 if (-1==_llseek(hfd,0x20,SEEK_SET))
1353 if (4!=_lread(hfd,magic,4))
1355 if (strcmp(magic,"RGKN")) {
1356 WARN("second IFF header not RGKN, but %s\n", magic);
1360 /* STEP 1: Keylink structures */
1361 if (-1==_llseek(hfd,0x40,SEEK_SET))
1366 info.rgknsize = end - where;
1367 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1368 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1371 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1374 end = hfdinfo.nFileSizeLow;
1375 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1377 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1380 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1381 info.rgdbsize = end - rgdbsection;
1383 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1387 _w95_walkrgkn(hkey, NULL, &info);
1389 free (info.rgdbbuffer);
1390 free (info.rgknbuffer);
1394 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1397 reghack - windows 3.11 registry data format demo program.
1399 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1400 a combined hash table and tree description, and finally a text table.
1402 The header is obvious from the struct header. The taboff1 and taboff2
1403 fields are always 0x20, and their usage is unknown.
1405 The 8-byte entry table has various entry types.
1407 tabent[0] is a root index. The second word has the index of the root of
1409 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1410 the index of the key/value that has that hash. Data with the same
1411 hash value are on a circular list. The other three words in the
1412 hash entry are always zero.
1413 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1414 entry: dirent and keyent/valent. They are identified by context.
1415 tabent[freeidx] is the first free entry. The first word in a free entry
1416 is the index of the next free entry. The last has 0 as a link.
1417 The other three words in the free list are probably irrelevant.
1419 Entries in text table are preceeded by a word at offset-2. This word
1420 has the value (2*index)+1, where index is the referring keyent/valent
1421 entry in the table. I have no suggestion for the 2* and the +1.
1422 Following the word, there are N bytes of data, as per the keyent/valent
1423 entry length. The offset of the keyent/valent entry is from the start
1424 of the text table to the first data byte.
1426 This information is not available from Microsoft. The data format is
1427 deduced from the reg.dat file by me. Mistakes may
1428 have been made. I claim no rights and give no guarantees for this program.
1430 Tor Sjøwall, tor@sn.no
1433 /* reg.dat header format */
1434 struct _w31_header {
1435 char cookie[8]; /* 'SHCC3.10' */
1436 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1437 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1438 unsigned long tabcnt; /* number of entries in index table */
1439 unsigned long textoff; /* offset of text part */
1440 unsigned long textsize; /* byte size of text part */
1441 unsigned short hashsize; /* hash size */
1442 unsigned short freeidx; /* free index */
1445 /* generic format of table entries */
1446 struct _w31_tabent {
1447 unsigned short w0, w1, w2, w3;
1450 /* directory tabent: */
1451 struct _w31_dirent {
1452 unsigned short sibling_idx; /* table index of sibling dirent */
1453 unsigned short child_idx; /* table index of child dirent */
1454 unsigned short key_idx; /* table index of key keyent */
1455 unsigned short value_idx; /* table index of value valent */
1459 struct _w31_keyent {
1460 unsigned short hash_idx; /* hash chain index for string */
1461 unsigned short refcnt; /* reference count */
1462 unsigned short length; /* length of string */
1463 unsigned short string_off; /* offset of string in text table */
1467 struct _w31_valent {
1468 unsigned short hash_idx; /* hash chain index for string */
1469 unsigned short refcnt; /* reference count */
1470 unsigned short length; /* length of string */
1471 unsigned short string_off; /* offset of string in text table */
1474 /* recursive helper function to display a directory tree */
1476 __w31_dumptree( unsigned short idx,
1478 struct _w31_tabent *tab,
1479 struct _w31_header *head,
1481 time_t lastmodified,
1484 struct _w31_dirent *dir;
1485 struct _w31_keyent *key;
1486 struct _w31_valent *val;
1488 static char tail[400];
1491 dir=(struct _w31_dirent*)&tab[idx];
1494 key = (struct _w31_keyent*)&tab[dir->key_idx];
1496 memcpy(tail,&txt[key->string_off],key->length);
1497 tail[key->length]='\0';
1498 /* all toplevel entries AND the entries in the
1499 * toplevel subdirectory belong to \SOFTWARE\Classes
1501 if (!level && !lstrcmpA(tail,".classes")) {
1502 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1503 idx=dir->sibling_idx;
1506 if (subkey) RegCloseKey( subkey );
1507 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1508 /* only add if leaf node or valued node */
1509 if (dir->value_idx!=0||dir->child_idx==0) {
1510 if (dir->value_idx) {
1511 val=(struct _w31_valent*)&tab[dir->value_idx];
1512 memcpy(tail,&txt[val->string_off],val->length);
1513 tail[val->length]='\0';
1514 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1518 TRACE("strange: no directory key name, idx=%04x\n", idx);
1520 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1521 idx=dir->sibling_idx;
1523 if (subkey) RegCloseKey( subkey );
1527 /******************************************************************************
1528 * _w31_loadreg [Internal]
1530 void _w31_loadreg(void) {
1532 struct _w31_header head;
1533 struct _w31_tabent *tab;
1537 BY_HANDLE_FILE_INFORMATION hfinfo;
1538 time_t lastmodified;
1542 hf = OpenFile("reg.dat",&ofs,OF_READ);
1543 if (hf==HFILE_ERROR)
1546 /* read & dump header */
1547 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1548 ERR("reg.dat is too short.\n");
1552 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1553 ERR("reg.dat has bad signature.\n");
1558 len = head.tabcnt * sizeof(struct _w31_tabent);
1559 /* read and dump index table */
1561 if (len!=_lread(hf,tab,len)) {
1562 ERR("couldn't read %d bytes.\n",len);
1569 txt = xmalloc(head.textsize);
1570 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1571 ERR("couldn't seek to textblock.\n");
1577 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1578 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1585 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1586 ERR("GetFileInformationByHandle failed?.\n");
1592 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1593 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1601 /**********************************************************************************
1602 * SHELL_LoadRegistry [Internal]
1604 void SHELL_LoadRegistry( void )
1606 struct set_registry_levels_request *req = get_req_buffer();
1615 /* set level to 0 for loading system files */
1619 server_call( REQ_SET_REGISTRY_LEVELS );
1621 if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1))
1623 /* Load windows 3.1 entries */
1626 if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1))
1628 /* Load windows 95 entries */
1629 _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE);
1630 _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE);
1631 _w95_loadreg("user.dat", HKEY_USERS);
1633 if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1))
1635 fn = xmalloc( MAX_PATHNAME_LEN );
1636 home = xmalloc ( MAX_PATHNAME_LEN );
1637 if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1))
1639 GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1640 strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1641 strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1642 strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
1643 _nt_loadreg( HKEY_USERS, fn );
1647 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1649 GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1652 strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
1653 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1656 strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
1657 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1660 strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
1661 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1664 strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
1665 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1669 /* this key is generated when the nt-core booted successfully */
1670 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1674 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1677 * Load the global HKU hive directly from sysconfdir
1679 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1682 * Load the global machine defaults directly form sysconfdir
1684 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1687 /* set level to 1 for loading user files */
1691 server_call( REQ_SET_REGISTRY_LEVELS );
1694 * Load the user saved registries
1696 if (!(home = getenv( "HOME" )))
1697 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1698 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1701 * Load user's personal versions of global HKU/.Default keys
1703 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1704 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1706 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1707 _wine_loadreg( HKEY_USERS, fn );
1710 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1712 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1713 _wine_loadreg( HKEY_CURRENT_USER, fn );
1717 * Load HKLM, attempt to get the registry location from the config
1718 * file first, if exist, load and keep going.
1720 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1722 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1723 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1728 * Load HKCU, get the registry location from the config
1729 * file, if exist, load and keep going.
1731 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1733 fn = xmalloc( MAX_PATHNAME_LEN );
1734 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1735 fn, MAX_PATHNAME_LEN - 1))
1737 _wine_loadreg( HKEY_CURRENT_USER, fn );
1741 * Load HKU, get the registry location from the config
1742 * file, if exist, load and keep going.
1744 fn = xmalloc ( MAX_PATHNAME_LEN );
1745 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1746 fn, MAX_PATHNAME_LEN - 1))
1748 _wine_loadreg( HKEY_USERS, fn );
1752 * Load HKLM, get the registry location from the config
1753 * file, if exist, load and keep going.
1755 fn = xmalloc ( MAX_PATHNAME_LEN );
1756 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1757 fn, MAX_PATHNAME_LEN - 1))
1759 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1765 * Obtain the handle of the HKU\.Default key.
1766 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1768 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey) != ERROR_SUCCESS)
1769 WARN("Could not create global user default key\n");
1771 _copy_registry( hkey, HKEY_CURRENT_USER );
1775 * Since HKU is built from the global HKU and the local user HKU file we must
1776 * flush the HKU tree we have built at this point otherwise the part brought
1777 * in from the global HKU is saved into the local HKU. To avoid this
1778 * useless dupplication of HKU keys we reread the local HKU key.
1781 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1782 _flush_registry( HKEY_USERS );
1784 /* Reload user's local HKU hive */
1785 if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
1787 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1788 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
1791 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1793 _wine_loadreg( HKEY_USERS, fn );
1799 * Make sure the update mode is there
1801 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1803 DWORD junk,type,len;
1807 if (( RegQueryValueExA(
1813 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1815 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1821 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1823 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1828 /********************* API FUNCTIONS ***************************************/
1833 /******************************************************************************
1834 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1835 * Immediately writes key to registry.
1836 * Only returns after data has been written to disk.
1838 * FIXME: does it really wait until data is written ?
1841 * hkey [I] Handle of key to write
1844 * Success: ERROR_SUCCESS
1845 * Failure: Error code
1847 DWORD WINAPI RegFlushKey( HKEY hkey )
1849 FIXME( "(%x): stub\n", hkey );
1850 return ERROR_SUCCESS;
1853 /******************************************************************************
1854 * RegConnectRegistry32W [ADVAPI32.128]
1857 * lpMachineName [I] Address of name of remote computer
1858 * hHey [I] Predefined registry handle
1859 * phkResult [I] Address of buffer for remote registry handle
1861 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1864 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1866 if (!lpMachineName || !*lpMachineName) {
1867 /* Use the local machine name */
1868 return RegOpenKey16( hKey, "", phkResult );
1871 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1872 return ERROR_BAD_NETPATH;
1876 /******************************************************************************
1877 * RegConnectRegistry32A [ADVAPI32.127]
1879 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1882 LPWSTR machineW = strdupA2W(machine);
1883 ret = RegConnectRegistryW( machineW, hkey, reskey );
1889 /******************************************************************************
1890 * RegGetKeySecurity [ADVAPI32.144]
1891 * Retrieves a copy of security descriptor protecting the registry key
1894 * hkey [I] Open handle of key to set
1895 * SecurityInformation [I] Descriptor contents
1896 * pSecurityDescriptor [O] Address of descriptor for key
1897 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1900 * Success: ERROR_SUCCESS
1901 * Failure: Error code
1903 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1904 SECURITY_INFORMATION SecurityInformation,
1905 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1906 LPDWORD lpcbSecurityDescriptor )
1908 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1909 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1911 /* FIXME: Check for valid SecurityInformation values */
1913 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1914 return ERROR_INSUFFICIENT_BUFFER;
1916 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1917 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1919 return ERROR_SUCCESS;
1923 /******************************************************************************
1924 * RegNotifyChangeKeyValue [ADVAPI32.???]
1927 * hkey [I] Handle of key to watch
1928 * fWatchSubTree [I] Flag for subkey notification
1929 * fdwNotifyFilter [I] Changes to be reported
1930 * hEvent [I] Handle of signaled event
1931 * fAsync [I] Flag for asynchronous reporting
1933 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1934 DWORD fdwNotifyFilter, HANDLE hEvent,
1937 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1939 return ERROR_SUCCESS;
1943 /******************************************************************************
1944 * RegUnLoadKey32W [ADVAPI32.173]
1947 * hkey [I] Handle of open key
1948 * lpSubKey [I] Address of name of subkey to unload
1950 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1952 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1953 return ERROR_SUCCESS;
1957 /******************************************************************************
1958 * RegUnLoadKey32A [ADVAPI32.172]
1960 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1963 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1964 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1965 if(lpSubKeyW) free(lpSubKeyW);
1970 /******************************************************************************
1971 * RegSetKeySecurity [ADVAPI32.167]
1974 * hkey [I] Open handle of key to set
1975 * SecurityInfo [I] Descriptor contents
1976 * pSecurityDesc [I] Address of descriptor for key
1978 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1979 PSECURITY_DESCRIPTOR pSecurityDesc )
1981 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1983 /* It seems to perform this check before the hkey check */
1984 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1985 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1986 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1987 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1990 return ERROR_INVALID_PARAMETER;
1993 return ERROR_INVALID_PARAMETER;
1995 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1997 return ERROR_SUCCESS;
2001 /******************************************************************************
2002 * RegRestoreKey32W [ADVAPI32.164]
2005 * hkey [I] Handle of key where restore begins
2006 * lpFile [I] Address of filename containing saved tree
2007 * dwFlags [I] Optional flags
2009 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2011 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2013 /* It seems to do this check before the hkey check */
2014 if (!lpFile || !*lpFile)
2015 return ERROR_INVALID_PARAMETER;
2017 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2019 /* Check for file existence */
2021 return ERROR_SUCCESS;
2025 /******************************************************************************
2026 * RegRestoreKey32A [ADVAPI32.163]
2028 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2031 LPWSTR lpFileW = strdupA2W(lpFile);
2032 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
2033 if(lpFileW) free(lpFileW);
2038 /******************************************************************************
2039 * RegReplaceKey32W [ADVAPI32.162]
2042 * hkey [I] Handle of open key
2043 * lpSubKey [I] Address of name of subkey
2044 * lpNewFile [I] Address of filename for file with new data
2045 * lpOldFile [I] Address of filename for backup file
2047 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2050 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2051 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2052 return ERROR_SUCCESS;
2056 /******************************************************************************
2057 * RegReplaceKey32A [ADVAPI32.161]
2059 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2063 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
2064 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
2065 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
2066 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
2078 /* 16-bit functions */
2080 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
2081 * some programs. Do not remove those cases. -MM
2083 static inline void fix_win16_hkey( HKEY *hkey )
2085 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
2088 /******************************************************************************
2089 * RegEnumKey16 [KERNEL.216] [SHELL.7]
2091 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2093 fix_win16_hkey( &hkey );
2094 return RegEnumKeyA( hkey, index, name, name_len );
2097 /******************************************************************************
2098 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2100 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2102 fix_win16_hkey( &hkey );
2103 return RegOpenKeyA( hkey, name, retkey );
2106 /******************************************************************************
2107 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2109 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2111 fix_win16_hkey( &hkey );
2112 return RegCreateKeyA( hkey, name, retkey );
2115 /******************************************************************************
2116 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2118 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2120 fix_win16_hkey( &hkey );
2121 return RegDeleteKeyA( hkey, name );
2124 /******************************************************************************
2125 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2127 DWORD WINAPI RegCloseKey16( HKEY hkey )
2129 fix_win16_hkey( &hkey );
2130 return RegCloseKey( hkey );
2133 /******************************************************************************
2134 * RegSetValue16 [KERNEL.221] [SHELL.5]
2136 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2138 fix_win16_hkey( &hkey );
2139 return RegSetValueA( hkey, name, type, data, count );
2142 /******************************************************************************
2143 * RegDeleteValue16 [KERNEL.222]
2145 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2147 fix_win16_hkey( &hkey );
2148 return RegDeleteValueA( hkey, name );
2151 /******************************************************************************
2152 * RegEnumValue16 [KERNEL.223]
2154 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2155 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2157 fix_win16_hkey( &hkey );
2158 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2161 /******************************************************************************
2162 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2165 * Is this HACK still applicable?
2168 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2169 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2172 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2174 fix_win16_hkey( &hkey );
2175 if (count) *count &= 0xffff;
2176 return RegQueryValueA( hkey, name, data, count );
2179 /******************************************************************************
2180 * RegQueryValueEx16 [KERNEL.225]
2182 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2183 LPBYTE data, LPDWORD count )
2185 fix_win16_hkey( &hkey );
2186 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2189 /******************************************************************************
2190 * RegSetValueEx16 [KERNEL.226]
2192 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2193 CONST BYTE *data, DWORD count )
2195 fix_win16_hkey( &hkey );
2196 return RegSetValueExA( hkey, name, reserved, type, data, count );