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>
34 #include <sys/fcntl.h>
40 #include "wine/winbase16.h"
41 #include "wine/winestring.h"
45 #include "debugtools.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))
78 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
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)
88 LPWSTR dest=xmalloc(2*strlen(src)+2);
89 lstrcpyAtoW(dest,src);
95 LPWSTR strcvtA2W(LPCSTR src, int nchars)
98 LPWSTR dest = xmalloc (2 * nchars + 2);
100 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 */
736 #ifdef HAVE_SYS_MMAN_H
737 # include <sys/mman.h>
741 #define MAP_FAILED ((LPVOID)-1)
746 #define REG_BLOCK_SIZE 0x1000
748 #define REG_HEADER_BLOCK_ID 0x66676572 /* regf */
749 #define REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
750 #define REG_KEY_BLOCK_ID 0x6b6e
751 #define REG_VALUE_BLOCK_ID 0x6b76
752 #define REG_HASH_BLOCK_ID 0x666c
753 #define REG_NOHASH_BLOCK_ID 0x696c
754 #define REG_KEY_BLOCK_TYPE 0x20
755 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
759 DWORD id; /* 0x66676572 'regf'*/
760 DWORD uk1; /* 0x04 */
761 DWORD uk2; /* 0x08 */
762 FILETIME DateModified; /* 0x0c */
763 DWORD uk3; /* 0x14 */
764 DWORD uk4; /* 0x18 */
765 DWORD uk5; /* 0x1c */
766 DWORD uk6; /* 0x20 */
767 DWORD RootKeyBlock; /* 0x24 */
768 DWORD BlockSize; /* 0x28 */
770 DWORD Checksum; /* at offset 0x1FC */
781 DWORD id; /* 0x6E696268 'hbin' */
785 DWORD uk2; /* 0x10 */
786 DWORD uk3; /* 0x14 */
787 DWORD uk4; /* 0x18 */
788 DWORD size; /* 0x1C */
789 nt_hbin_sub hbin_sub; /* 0x20 */
793 * the value_list consists of offsets to the values (vk)
797 WORD SubBlockId; /* 0x00 0x6B6E */
798 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
799 FILETIME writetime; /* 0x04 */
800 DWORD uk1; /* 0x0C */
801 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
802 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
803 DWORD uk8; /* 0x18 */
804 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
805 DWORD uk2; /* 0x20 */
806 DWORD nr_values; /* 0x24 number of values */
807 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
808 DWORD off_sk; /* 0x2c Offset of the sk-Record */
809 DWORD off_class; /* 0x30 Offset of the Class-Name */
810 DWORD uk3; /* 0x34 */
811 DWORD uk4; /* 0x38 */
812 DWORD uk5; /* 0x3c */
813 DWORD uk6; /* 0x40 */
814 DWORD uk7; /* 0x44 */
815 WORD name_len; /* 0x48 name-length */
816 WORD class_len; /* 0x4a class-name length */
817 char name[1]; /* 0x4c key-name */
822 DWORD off_nk; /* 0x00 */
823 DWORD name; /* 0x04 */
828 WORD id; /* 0x00 0x666c */
829 WORD nr_keys; /* 0x06 */
830 hash_rec hash_rec[1];
835 WORD id; /* 0x00 0x696c */
842 WORD id; /* 0x00 'vk' */
853 #define vk_expsz 0x0002
854 #define vk_bin 0x0003
855 #define vk_dword 0x0004
856 #define vk_multisz 0x0007
860 LPSTR _strdupnA( LPCSTR str, int len )
864 if (!str) return NULL;
865 ret = malloc( len + 1 );
866 lstrcpynA( ret, str, len );
871 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
872 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level);
873 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
880 * 0 value is a default value
881 * 1 the value has a name
884 * len of the whole data block
886 * bytes including the terminating \0 = 2*(number_of_chars+1)
887 * - reg_dword, reg_binary:
888 * if highest bit of data_len is set data_off contains the value
890 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level)
894 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
896 if(vk->id != REG_VALUE_BLOCK_ID) goto error;
898 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
900 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
901 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
902 (vk->data_len & 0x7fffffff) );
903 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
906 ERR_(reg)("vk block invalid\n");
913 * this structure contains the hash of a keyname and points to all
916 * exception: if the id is 'il' there are no hash values and every
919 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
923 if (lf->id == REG_HASH_BLOCK_ID)
925 for (i=0; i<lf->nr_keys; i++)
927 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
931 else if (lf->id == REG_NOHASH_BLOCK_ID)
933 for (i=0; i<lf->nr_keys; i++)
935 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
940 error: ERR_(reg)("error reading lf block\n");
944 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
951 if(nk->SubBlockId != REG_KEY_BLOCK_ID) goto error;
952 if((nk->Type!=REG_ROOT_KEY_BLOCK_TYPE) &&
953 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != REG_KEY_BLOCK_ID)) goto error;
955 /* create the new key */
956 name = _strdupnA( nk->name, nk->name_len+1);
957 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
960 /* loop through the subkeys */
963 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
964 if (nk->nr_subkeys != lf->nr_keys) goto error1;
965 if (!_nt_parse_lf(subkey, base, lf, level+1)) goto error1;
968 /* loop trough the value list */
969 vl = (DWORD *)(base+nk->valuelist_off+4);
970 for (i=0; i<nk->nr_values; i++)
972 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
973 if (!_nt_parse_vk(subkey, base, vk, level+1 )) goto error1;
979 error1: RegCloseKey(subkey);
980 error: ERR_(reg)("error reading nk block\n");
985 * this function intentionally uses unix file functions to make it possible
986 * to move it to a seperate registry helper programm
988 static int _nt_loadreg( HKEY hkey, char* fn )
995 nt_hbin_sub * hbin_sub;
997 DOS_FULL_NAME full_name;
999 if (!DOSFS_GetFullName( fn, 0, &full_name ));
1001 TRACE_(reg)("Loading NT registry database '%s' '%s'\n",fn, full_name.long_name);
1003 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1004 if (fstat(fd, &st ) == -1) goto error1;
1006 if ((base=mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1010 if(regf->id != REG_HEADER_BLOCK_ID) /* 'regf' */
1012 ERR( "%s is not a nt-registry\n", fn);
1015 TRACE_(reg)( "%p [regf] offset=%lx size=%lx\n", regf, regf->RootKeyBlock, regf->BlockSize);
1018 hbin = base + 0x1000;
1019 if (hbin->id != REG_POOL_BLOCK_ID)
1021 ERR_(reg)( "%s hbin block invalid\n", fn);
1024 TRACE_(reg)( "%p [hbin] prev=%lx next=%lx size=%lx\n", hbin, hbin->off_prev, hbin->off_next, hbin->size);
1026 /* hbin_sub block */
1027 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1028 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1030 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1033 TRACE_(reg)( "%p [hbin sub] size=%lx\n", hbin_sub, hbin_sub->blocksize);
1036 nk = (nt_nk*)&(hbin_sub->data[0]);
1037 if (nk->Type != REG_ROOT_KEY_BLOCK_TYPE)
1039 ERR_(reg)( "%s special nk block not found\n", fn);
1043 _nt_parse_nk (hkey, base+0x1000, nk, 0);
1049 error: munmap(base, len);
1051 ERR_(reg)("error reading registry file\n");
1056 /* WINDOWS 95 REGISTRY LOADER */
1058 * Structure of a win95 registry database.
1060 * 0 : "CREG" - magic
1062 * 8 : DWORD offset_of_RGDB_part
1063 * 0C..0F: ? (someone fill in please)
1064 * 10: WORD number of RGDB blocks
1066 * 14: WORD always 0000?
1067 * 16: WORD always 0001?
1068 * 18..1F: ? (someone fill in please)
1072 * 0 : "RGKN" - magic
1073 * 4 : DWORD offset to first RGDB section
1074 * 8 : DWORD offset to the root record
1075 * C..0x1B: ? (fill in)
1076 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1078 * Disk Key Entry Structure:
1079 * 00: DWORD - Free entry indicator(?)
1080 * 04: DWORD - Hash = sum of bytes of keyname
1081 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1082 * 0C: DWORD - disk address of PreviousLevel Key.
1083 * 10: DWORD - disk address of Next Sublevel Key.
1084 * 14: DWORD - disk address of Next Key (on same level).
1085 * DKEP>18: WORD - Nr, Low Significant part.
1086 * 1A: WORD - Nr, High Significant part.
1088 * The disk address always points to the nr part of the previous key entry
1089 * of the referenced key. Don't ask me why, or even if I got this correct
1090 * from staring at 1kg of hexdumps. (DKEP)
1092 * The High significant part of the structure seems to equal the number
1093 * of the RGDB section. The low significant part is a unique ID within
1096 * There are two minor corrections to the position of that structure.
1097 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1098 * the DKE reread from there.
1099 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1100 * CPS - I have not experienced the above phenomenon in my registry files
1103 * 00: "RGDB" - magic
1104 * 04: DWORD offset to next RGDB section
1106 * 0C: WORD always 000d?
1107 * 0E: WORD RGDB block number
1108 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1110 * 20.....: disk keys
1113 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1114 * 08: WORD nrLS - low significant part of NR
1115 * 0A: WORD nrHS - high significant part of NR
1116 * 0C: DWORD bytesused - bytes used in this structure.
1117 * 10: WORD name_len - length of name in bytes. without \0
1118 * 12: WORD nr_of_values - number of values.
1119 * 14: char name[name_len] - name string. No \0.
1120 * 14+name_len: disk values
1121 * nextkeyoffset: ... next disk key
1124 * 00: DWORD type - value type (hmm, could be WORD too)
1125 * 04: DWORD - unknown, usually 0
1126 * 08: WORD namelen - length of Name. 0 means name=NULL
1127 * 0C: WORD datalen - length of Data.
1128 * 10: char name[namelen] - name, no \0
1129 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1130 * 10+namelen+datalen: next values or disk key
1132 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1133 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1134 * structure) and reading another RGDB_section.
1135 * repeat until end of file.
1137 * An interesting relationship exists in RGDB_section. The value at offset
1138 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1139 * idea at the moment what this means. (Kevin Cozens)
1141 * FIXME: this description needs some serious help, yes.
1144 struct _w95keyvalue {
1146 unsigned short datalen;
1148 unsigned char *data;
1156 struct _w95keyvalue *values;
1157 struct _w95key *prevlvl;
1158 struct _w95key *nextsub;
1159 struct _w95key *next;
1173 /******************************************************************************
1174 * _w95_processKey [Internal]
1176 static HKEY _w95_processKey ( HKEY hkey, int nrLS, int nrMS, struct _w95_info *info )
1179 /* Disk Key Header structure (RGDB part) */
1181 unsigned long nextkeyoff;
1182 unsigned short nrLS;
1183 unsigned short nrMS;
1184 unsigned long bytesused;
1185 unsigned short keynamelen;
1186 unsigned short values;
1189 /* disk key values or nothing */
1191 /* Disk Key Value structure */
1195 unsigned short valnamelen;
1196 unsigned short valdatalen;
1197 /* valname, valdata */
1203 char *rgdbdata = info->rgdbbuffer;
1204 int nbytes = info->rgdbsize;
1205 char *curdata = rgdbdata;
1206 char *end = rgdbdata + nbytes;
1208 char *next = rgdbdata;
1214 if (strncmp(curdata, "RGDB", 4)) return 0;
1216 memcpy(&off_next_rgdb,curdata+4,4);
1217 next = curdata + off_next_rgdb;
1218 nrgdb = (int) *((short *)curdata + 7);
1220 } while (nrgdb != nrMS && (next < end));
1222 /* curdata now points to the start of the right RGDB section */
1225 #define XREAD(whereto,len) \
1226 if ((curdata + len) <= end) {\
1227 memcpy(whereto,curdata,len);\
1232 while (curdata < next) {
1233 struct dkh *xdkh = (struct dkh*)curdata;
1235 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1236 if (xdkh->nrLS == nrLS) {
1237 memcpy(&dkh,xdkh,sizeof(dkh));
1238 curdata += sizeof(dkh);
1241 curdata += xdkh->nextkeyoff;
1244 if (dkh.nrLS != nrLS) return 0;
1246 if (nrgdb != dkh.nrMS)
1249 assert((dkh.keynamelen<2) || curdata[0]);
1250 subkey=_find_or_add_key(hkey,strcvtA2W(curdata, dkh.keynamelen));
1251 curdata += dkh.keynamelen;
1253 for (i=0;i< dkh.values; i++) {
1259 XREAD(&dkv,sizeof(dkv));
1261 name = strcvtA2W(curdata, dkv.valnamelen);
1262 curdata += dkv.valnamelen;
1264 if ((1 << dkv.type) & UNICONVMASK) {
1265 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1266 len = 2*(dkv.valdatalen + 1);
1268 /* I don't think we want to NULL terminate all data */
1269 data = xmalloc(dkv.valdatalen);
1270 memcpy (data, curdata, dkv.valdatalen);
1271 len = dkv.valdatalen;
1274 curdata += dkv.valdatalen;
1276 _find_or_add_value( subkey, name, dkv.type, data, len );
1281 /******************************************************************************
1282 * _w95_walkrgkn [Internal]
1284 static void _w95_walkrgkn( HKEY prevkey, char *off,
1285 struct _w95_info *info )
1288 /* Disk Key Entry structure (RGKN part) */
1292 unsigned long x3;/*usually 0xFFFFFFFF */
1293 unsigned long prevlvl;
1294 unsigned long nextsub;
1296 unsigned short nrLS;
1297 unsigned short nrMS;
1298 } *dke = (struct dke *)off;
1302 dke = (struct dke *) ((char *)info->rgknbuffer);
1305 subkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1307 if (dke->nextsub != -1 &&
1308 ((dke->nextsub - 0x20) < info->rgknsize)
1309 && (dke->nextsub > 0x20)) {
1311 _w95_walkrgkn(subkey ? subkey : prevkey, /* XXX <-- This is a hack*/
1312 info->rgknbuffer + dke->nextsub - 0x20,
1315 if (subkey) RegCloseKey( subkey );
1317 if (dke->next != -1 &&
1318 ((dke->next - 0x20) < info->rgknsize) &&
1319 (dke->next > 0x20)) {
1320 _w95_walkrgkn(prevkey,
1321 info->rgknbuffer + dke->next - 0x20,
1327 /******************************************************************************
1328 * _w95_loadreg [Internal]
1330 static void _w95_loadreg( char* fn, HKEY hkey )
1334 unsigned long where,version,rgdbsection,end;
1335 struct _w95_info info;
1337 BY_HANDLE_FILE_INFORMATION hfdinfo;
1339 TRACE("Loading Win95 registry database '%s'\n",fn);
1340 hfd=OpenFile(fn,&ofs,OF_READ);
1341 if (hfd==HFILE_ERROR)
1344 if (4!=_lread(hfd,magic,4))
1346 if (strcmp(magic,"CREG")) {
1347 WARN("%s is not a w95 registry.\n",fn);
1350 if (4!=_lread(hfd,&version,4))
1352 if (4!=_lread(hfd,&rgdbsection,4))
1354 if (-1==_llseek(hfd,0x20,SEEK_SET))
1356 if (4!=_lread(hfd,magic,4))
1358 if (strcmp(magic,"RGKN")) {
1359 WARN("second IFF header not RGKN, but %s\n", magic);
1363 /* STEP 1: Keylink structures */
1364 if (-1==_llseek(hfd,0x40,SEEK_SET))
1369 info.rgknsize = end - where;
1370 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1371 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1374 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1377 end = hfdinfo.nFileSizeLow;
1378 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1380 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1383 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1384 info.rgdbsize = end - rgdbsection;
1386 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1390 _w95_walkrgkn(hkey, NULL, &info);
1392 free (info.rgdbbuffer);
1393 free (info.rgknbuffer);
1397 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1400 reghack - windows 3.11 registry data format demo program.
1402 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1403 a combined hash table and tree description, and finally a text table.
1405 The header is obvious from the struct header. The taboff1 and taboff2
1406 fields are always 0x20, and their usage is unknown.
1408 The 8-byte entry table has various entry types.
1410 tabent[0] is a root index. The second word has the index of the root of
1412 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1413 the index of the key/value that has that hash. Data with the same
1414 hash value are on a circular list. The other three words in the
1415 hash entry are always zero.
1416 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1417 entry: dirent and keyent/valent. They are identified by context.
1418 tabent[freeidx] is the first free entry. The first word in a free entry
1419 is the index of the next free entry. The last has 0 as a link.
1420 The other three words in the free list are probably irrelevant.
1422 Entries in text table are preceeded by a word at offset-2. This word
1423 has the value (2*index)+1, where index is the referring keyent/valent
1424 entry in the table. I have no suggestion for the 2* and the +1.
1425 Following the word, there are N bytes of data, as per the keyent/valent
1426 entry length. The offset of the keyent/valent entry is from the start
1427 of the text table to the first data byte.
1429 This information is not available from Microsoft. The data format is
1430 deduced from the reg.dat file by me. Mistakes may
1431 have been made. I claim no rights and give no guarantees for this program.
1433 Tor Sjøwall, tor@sn.no
1436 /* reg.dat header format */
1437 struct _w31_header {
1438 char cookie[8]; /* 'SHCC3.10' */
1439 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1440 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1441 unsigned long tabcnt; /* number of entries in index table */
1442 unsigned long textoff; /* offset of text part */
1443 unsigned long textsize; /* byte size of text part */
1444 unsigned short hashsize; /* hash size */
1445 unsigned short freeidx; /* free index */
1448 /* generic format of table entries */
1449 struct _w31_tabent {
1450 unsigned short w0, w1, w2, w3;
1453 /* directory tabent: */
1454 struct _w31_dirent {
1455 unsigned short sibling_idx; /* table index of sibling dirent */
1456 unsigned short child_idx; /* table index of child dirent */
1457 unsigned short key_idx; /* table index of key keyent */
1458 unsigned short value_idx; /* table index of value valent */
1462 struct _w31_keyent {
1463 unsigned short hash_idx; /* hash chain index for string */
1464 unsigned short refcnt; /* reference count */
1465 unsigned short length; /* length of string */
1466 unsigned short string_off; /* offset of string in text table */
1470 struct _w31_valent {
1471 unsigned short hash_idx; /* hash chain index for string */
1472 unsigned short refcnt; /* reference count */
1473 unsigned short length; /* length of string */
1474 unsigned short string_off; /* offset of string in text table */
1477 /* recursive helper function to display a directory tree */
1479 __w31_dumptree( unsigned short idx,
1481 struct _w31_tabent *tab,
1482 struct _w31_header *head,
1484 time_t lastmodified,
1487 struct _w31_dirent *dir;
1488 struct _w31_keyent *key;
1489 struct _w31_valent *val;
1491 static char tail[400];
1494 dir=(struct _w31_dirent*)&tab[idx];
1497 key = (struct _w31_keyent*)&tab[dir->key_idx];
1499 memcpy(tail,&txt[key->string_off],key->length);
1500 tail[key->length]='\0';
1501 /* all toplevel entries AND the entries in the
1502 * toplevel subdirectory belong to \SOFTWARE\Classes
1504 if (!level && !lstrcmpA(tail,".classes")) {
1505 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1506 idx=dir->sibling_idx;
1509 if (subkey) RegCloseKey( subkey );
1510 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1511 /* only add if leaf node or valued node */
1512 if (dir->value_idx!=0||dir->child_idx==0) {
1513 if (dir->value_idx) {
1514 val=(struct _w31_valent*)&tab[dir->value_idx];
1515 memcpy(tail,&txt[val->string_off],val->length);
1516 tail[val->length]='\0';
1517 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1521 TRACE("strange: no directory key name, idx=%04x\n", idx);
1523 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1524 idx=dir->sibling_idx;
1526 if (subkey) RegCloseKey( subkey );
1530 /******************************************************************************
1531 * _w31_loadreg [Internal]
1533 void _w31_loadreg(void) {
1535 struct _w31_header head;
1536 struct _w31_tabent *tab;
1540 BY_HANDLE_FILE_INFORMATION hfinfo;
1541 time_t lastmodified;
1545 hf = OpenFile("reg.dat",&ofs,OF_READ);
1546 if (hf==HFILE_ERROR)
1549 /* read & dump header */
1550 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1551 ERR("reg.dat is too short.\n");
1555 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1556 ERR("reg.dat has bad signature.\n");
1561 len = head.tabcnt * sizeof(struct _w31_tabent);
1562 /* read and dump index table */
1564 if (len!=_lread(hf,tab,len)) {
1565 ERR("couldn't read %d bytes.\n",len);
1572 txt = xmalloc(head.textsize);
1573 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1574 ERR("couldn't seek to textblock.\n");
1580 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1581 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1588 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1589 ERR("GetFileInformationByHandle failed?.\n");
1595 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1596 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1604 /**********************************************************************************
1605 * SHELL_LoadRegistry [Internal]
1607 void SHELL_LoadRegistry( void )
1609 struct set_registry_levels_request *req = get_req_buffer();
1618 /* set level to 0 for loading system files */
1622 server_call( REQ_SET_REGISTRY_LEVELS );
1624 if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1))
1626 /* Load windows 3.1 entries */
1629 if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1))
1631 /* Load windows 95 entries */
1632 _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE);
1633 _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE);
1634 _w95_loadreg("user.dat", HKEY_USERS);
1636 if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1))
1638 fn = xmalloc( MAX_PATHNAME_LEN );
1639 home = xmalloc ( MAX_PATHNAME_LEN );
1640 if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1))
1642 GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1643 strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1644 strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1645 strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
1646 _nt_loadreg( HKEY_USERS, fn );
1650 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1652 GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1655 strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
1656 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1659 strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
1660 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1663 strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
1664 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1667 strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
1668 _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1672 /* this key is generated when the nt-core booted successfully */
1673 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1677 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1680 * Load the global HKU hive directly from sysconfdir
1682 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1685 * Load the global machine defaults directly form sysconfdir
1687 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1690 /* set level to 1 for loading user files */
1694 server_call( REQ_SET_REGISTRY_LEVELS );
1697 * Load the user saved registries
1699 if (!(home = getenv( "HOME" )))
1700 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1701 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1704 * Load user's personal versions of global HKU/.Default keys
1706 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1707 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1709 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1710 _wine_loadreg( HKEY_USERS, fn );
1713 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1715 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1716 _wine_loadreg( HKEY_CURRENT_USER, fn );
1720 * Load HKLM, attempt to get the registry location from the config
1721 * file first, if exist, load and keep going.
1723 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1725 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1726 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1731 * Load HKCU, get the registry location from the config
1732 * file, if exist, load and keep going.
1734 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1736 fn = xmalloc( MAX_PATHNAME_LEN );
1737 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1738 fn, MAX_PATHNAME_LEN - 1))
1740 _wine_loadreg( HKEY_CURRENT_USER, fn );
1744 * Load HKU, get the registry location from the config
1745 * file, if exist, load and keep going.
1747 fn = xmalloc ( MAX_PATHNAME_LEN );
1748 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1749 fn, MAX_PATHNAME_LEN - 1))
1751 _wine_loadreg( HKEY_USERS, fn );
1755 * Load HKLM, get the registry location from the config
1756 * file, if exist, load and keep going.
1758 fn = xmalloc ( MAX_PATHNAME_LEN );
1759 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1760 fn, MAX_PATHNAME_LEN - 1))
1762 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1768 * Obtain the handle of the HKU\.Default key.
1769 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1771 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey) != ERROR_SUCCESS)
1772 WARN("Could not create global user default key\n");
1774 _copy_registry( hkey, HKEY_CURRENT_USER );
1778 * Since HKU is built from the global HKU and the local user HKU file we must
1779 * flush the HKU tree we have built at this point otherwise the part brought
1780 * in from the global HKU is saved into the local HKU. To avoid this
1781 * useless dupplication of HKU keys we reread the local HKU key.
1784 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1785 _flush_registry( HKEY_USERS );
1787 /* Reload user's local HKU hive */
1788 if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
1790 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1791 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
1794 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1796 _wine_loadreg( HKEY_USERS, fn );
1802 * Make sure the update mode is there
1804 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1806 DWORD junk,type,len;
1810 if (( RegQueryValueExA(
1816 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1818 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1824 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1826 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1831 /********************* API FUNCTIONS ***************************************/
1836 /******************************************************************************
1837 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1838 * Immediately writes key to registry.
1839 * Only returns after data has been written to disk.
1841 * FIXME: does it really wait until data is written ?
1844 * hkey [I] Handle of key to write
1847 * Success: ERROR_SUCCESS
1848 * Failure: Error code
1850 DWORD WINAPI RegFlushKey( HKEY hkey )
1852 FIXME( "(%x): stub\n", hkey );
1853 return ERROR_SUCCESS;
1856 /******************************************************************************
1857 * RegConnectRegistry32W [ADVAPI32.128]
1860 * lpMachineName [I] Address of name of remote computer
1861 * hHey [I] Predefined registry handle
1862 * phkResult [I] Address of buffer for remote registry handle
1864 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1867 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1869 if (!lpMachineName || !*lpMachineName) {
1870 /* Use the local machine name */
1871 return RegOpenKey16( hKey, "", phkResult );
1874 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1875 return ERROR_BAD_NETPATH;
1879 /******************************************************************************
1880 * RegConnectRegistry32A [ADVAPI32.127]
1882 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1885 LPWSTR machineW = strdupA2W(machine);
1886 ret = RegConnectRegistryW( machineW, hkey, reskey );
1892 /******************************************************************************
1893 * RegGetKeySecurity [ADVAPI32.144]
1894 * Retrieves a copy of security descriptor protecting the registry key
1897 * hkey [I] Open handle of key to set
1898 * SecurityInformation [I] Descriptor contents
1899 * pSecurityDescriptor [O] Address of descriptor for key
1900 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1903 * Success: ERROR_SUCCESS
1904 * Failure: Error code
1906 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1907 SECURITY_INFORMATION SecurityInformation,
1908 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1909 LPDWORD lpcbSecurityDescriptor )
1911 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1912 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1914 /* FIXME: Check for valid SecurityInformation values */
1916 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1917 return ERROR_INSUFFICIENT_BUFFER;
1919 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1920 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1922 return ERROR_SUCCESS;
1926 /******************************************************************************
1927 * RegNotifyChangeKeyValue [ADVAPI32.???]
1930 * hkey [I] Handle of key to watch
1931 * fWatchSubTree [I] Flag for subkey notification
1932 * fdwNotifyFilter [I] Changes to be reported
1933 * hEvent [I] Handle of signaled event
1934 * fAsync [I] Flag for asynchronous reporting
1936 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1937 DWORD fdwNotifyFilter, HANDLE hEvent,
1940 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1942 return ERROR_SUCCESS;
1946 /******************************************************************************
1947 * RegUnLoadKey32W [ADVAPI32.173]
1950 * hkey [I] Handle of open key
1951 * lpSubKey [I] Address of name of subkey to unload
1953 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1955 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1956 return ERROR_SUCCESS;
1960 /******************************************************************************
1961 * RegUnLoadKey32A [ADVAPI32.172]
1963 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1966 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1967 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1968 if(lpSubKeyW) free(lpSubKeyW);
1973 /******************************************************************************
1974 * RegSetKeySecurity [ADVAPI32.167]
1977 * hkey [I] Open handle of key to set
1978 * SecurityInfo [I] Descriptor contents
1979 * pSecurityDesc [I] Address of descriptor for key
1981 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1982 PSECURITY_DESCRIPTOR pSecurityDesc )
1984 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1986 /* It seems to perform this check before the hkey check */
1987 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1988 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1989 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1990 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1993 return ERROR_INVALID_PARAMETER;
1996 return ERROR_INVALID_PARAMETER;
1998 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2000 return ERROR_SUCCESS;
2004 /******************************************************************************
2005 * RegRestoreKey32W [ADVAPI32.164]
2008 * hkey [I] Handle of key where restore begins
2009 * lpFile [I] Address of filename containing saved tree
2010 * dwFlags [I] Optional flags
2012 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2014 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2016 /* It seems to do this check before the hkey check */
2017 if (!lpFile || !*lpFile)
2018 return ERROR_INVALID_PARAMETER;
2020 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2022 /* Check for file existence */
2024 return ERROR_SUCCESS;
2028 /******************************************************************************
2029 * RegRestoreKey32A [ADVAPI32.163]
2031 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2034 LPWSTR lpFileW = strdupA2W(lpFile);
2035 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
2036 if(lpFileW) free(lpFileW);
2041 /******************************************************************************
2042 * RegReplaceKey32W [ADVAPI32.162]
2045 * hkey [I] Handle of open key
2046 * lpSubKey [I] Address of name of subkey
2047 * lpNewFile [I] Address of filename for file with new data
2048 * lpOldFile [I] Address of filename for backup file
2050 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2053 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2054 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2055 return ERROR_SUCCESS;
2059 /******************************************************************************
2060 * RegReplaceKey32A [ADVAPI32.161]
2062 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2066 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
2067 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
2068 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
2069 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
2081 /* 16-bit functions */
2083 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
2084 * some programs. Do not remove those cases. -MM
2086 static inline void fix_win16_hkey( HKEY *hkey )
2088 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
2091 /******************************************************************************
2092 * RegEnumKey16 [KERNEL.216] [SHELL.7]
2094 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2096 fix_win16_hkey( &hkey );
2097 return RegEnumKeyA( hkey, index, name, name_len );
2100 /******************************************************************************
2101 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2103 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2105 fix_win16_hkey( &hkey );
2106 return RegOpenKeyA( hkey, name, retkey );
2109 /******************************************************************************
2110 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2112 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2114 fix_win16_hkey( &hkey );
2115 return RegCreateKeyA( hkey, name, retkey );
2118 /******************************************************************************
2119 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2121 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2123 fix_win16_hkey( &hkey );
2124 return RegDeleteKeyA( hkey, name );
2127 /******************************************************************************
2128 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2130 DWORD WINAPI RegCloseKey16( HKEY hkey )
2132 fix_win16_hkey( &hkey );
2133 return RegCloseKey( hkey );
2136 /******************************************************************************
2137 * RegSetValue16 [KERNEL.221] [SHELL.5]
2139 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2141 fix_win16_hkey( &hkey );
2142 return RegSetValueA( hkey, name, type, data, count );
2145 /******************************************************************************
2146 * RegDeleteValue16 [KERNEL.222]
2148 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2150 fix_win16_hkey( &hkey );
2151 return RegDeleteValueA( hkey, name );
2154 /******************************************************************************
2155 * RegEnumValue16 [KERNEL.223]
2157 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2158 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2160 fix_win16_hkey( &hkey );
2161 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2164 /******************************************************************************
2165 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2168 * Is this HACK still applicable?
2171 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2172 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2175 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2177 fix_win16_hkey( &hkey );
2178 if (count) *count &= 0xffff;
2179 return RegQueryValueA( hkey, name, data, count );
2182 /******************************************************************************
2183 * RegQueryValueEx16 [KERNEL.225]
2185 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2186 LPBYTE data, LPDWORD count )
2188 fix_win16_hkey( &hkey );
2189 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2192 /******************************************************************************
2193 * RegSetValueEx16 [KERNEL.226]
2195 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2196 CONST BYTE *data, DWORD count )
2198 fix_win16_hkey( &hkey );
2199 return RegSetValueExA( hkey, name, reserved, type, data, count );