Made the server listen for new clients on a Unix socket in
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  * Copyright 1998 Matthew Becker
6  * Copyright 1999 Sylvain St-Germain
7  *
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.
11  *
12  * NOTES
13  *    When changing this file, please re-run the regtest program to ensure
14  *    the conditions are handled properly.
15  *
16  * TODO
17  *    Security access
18  *    Option handling
19  *    Time for RegEnumKey*, RegQueryInfoKey*
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
31 #endif
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <sys/fcntl.h>
35 #include <sys/stat.h>
36 #include <assert.h>
37 #include <time.h>
38 #include "windef.h"
39 #include "winbase.h"
40 #include "wine/winbase16.h"
41 #include "wine/winestring.h"
42 #include "winerror.h"
43 #include "file.h"
44 #include "heap.h"
45 #include "debugtools.h"
46 #include "xmalloc.h"
47 #include "options.h"
48 #include "winreg.h"
49 #include "server.h"
50 #include "services.h"
51
52 DEFAULT_DEBUG_CHANNEL(reg)
53
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
56
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"
61
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"
66
67 #define KEY_REGISTRY                "Software\\The WINE team\\WINE\\Registry"
68 #define VAL_SAVEUPDATED             "SaveOnlyUpdatedKeys"
69
70
71 /* what valuetypes do we need to convert? */
72 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
73
74
75
76 /*
77  * QUESTION
78  *   Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79  *   If so, can we remove them?
80  * ANSWER
81  *   No, the memory handling functions are called very often in here, 
82  *   just replacing them by HeapAlloc(SystemHeap,...) makes registry
83  *   loading 100 times slower. -MM
84  */
85 static LPWSTR strdupA2W(LPCSTR src)
86 {
87     if(src) {
88         LPWSTR dest=xmalloc(2*strlen(src)+2);
89         lstrcpyAtoW(dest,src);
90         return dest;
91     }
92     return NULL;
93 }
94
95 LPWSTR strcvtA2W(LPCSTR src, int nchars)
96
97 {
98    LPWSTR dest = xmalloc (2 * nchars + 2);
99
100    lstrcpynAtoW(dest,src,nchars+1);
101    return dest;
102 }
103
104
105
106 /******************************************************************************
107  * REGISTRY_Init [Internal]
108  * Registry initialisation, allocates some default keys. 
109  */
110 static void REGISTRY_Init(void) {
111         HKEY    hkey;
112         char    buf[200];
113
114         TRACE("(void)\n");
115
116         RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
117         RegCloseKey(hkey);
118
119         /* This was an Open, but since it is called before the real registries
120            are loaded, it was changed to a Create - MTB 980507*/
121         RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
122         RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
123         RegCloseKey(hkey);
124
125         /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
126          *                                              CurrentVersion
127          *                                              CurrentBuildNumber
128          *                                              CurrentType
129          *                                      string  RegisteredOwner
130          *                                      string  RegisteredOrganization
131          *
132          */
133         /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
134          *                                      string  SysContact
135          *                                      string  SysLocation
136          *                                              SysServices
137          */
138         if (-1!=gethostname(buf,200)) {
139                 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
140                 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
141                 RegCloseKey(hkey);
142         }
143 }
144
145
146 /************************ SAVE Registry Function ****************************/
147
148 #define REGISTRY_SAVE_VERSION   0x00000001
149
150 /* Registry saveformat:
151  * If you change it, increase above number by 1, which will flush
152  * old registry database files.
153  * 
154  * Global:
155  *      "WINE REGISTRY Version %d"
156  *      subkeys....
157  * Subkeys:
158  *      keyname
159  *              valuename=lastmodified,type,data
160  *              ...
161  *              subkeys
162  *      ...
163  * keyname,valuename,stringdata:
164  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
165  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
166  *      ( "=\\\t" escaped in \uXXXX form.)
167  * type,lastmodified: 
168  *      int
169  * 
170  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
171  *
172  * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
173  * SaveOnlyUpdatedKeys=yes
174  */
175
176 /* Same as RegSaveKey but with Unix pathnames */
177 static void save_key( HKEY hkey, const char *filename )
178 {
179     struct save_registry_request *req = get_req_buffer();
180     int count = 0;
181     DWORD ret;
182     HANDLE handle;
183     char *p;
184     char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
185
186     if (!name) return;
187     strcpy( name, filename );
188     if ((p = strrchr( name, '/' ))) p++;
189     else p = name;
190
191     for (;;)
192     {
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;
198     }
199
200     if (handle != INVALID_HANDLE_VALUE)
201     {
202         req->hkey = hkey;
203         req->file = handle;
204         ret = server_call_noerr( REQ_SAVE_REGISTRY );
205         CloseHandle( handle );
206         if (ret) unlink( name );
207         else if (rename( name, filename ) == -1)
208         {
209             ERR( "Failed to move %s to %s: ", name, filename );
210             perror( "rename" );
211             unlink( name );
212         }
213     }
214     HeapFree( GetProcessHeap(), 0, name );
215 }
216
217
218 /******************************************************************************
219  * SHELL_SaveRegistryBranch [Internal]
220  *
221  * Saves main registry branch specified by hkey.
222  */
223 static void SHELL_SaveRegistryBranch(HKEY hkey)
224 {
225     char   *fn, *home;
226
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);
230
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());
234
235     /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
236     if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
237
238     switch (hkey)
239     {
240     case HKEY_CURRENT_USER:
241         fn = xmalloc( MAX_PATHNAME_LEN ); 
242         if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
243                                                     fn, MAX_PATHNAME_LEN - 1))
244             save_key( HKEY_CURRENT_USER, fn );
245         free (fn);
246
247         if (home && writeToHome)
248         {
249             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
250                                strlen(SAVE_CURRENT_USER) + 2 );
251             strcpy(fn,home);
252             strcat(fn,WINE_PREFIX);
253   
254             /* create the directory. don't care about errorcodes. */
255             mkdir(fn,0755); /* drwxr-xr-x */
256             strcat(fn,"/"SAVE_CURRENT_USER);
257             save_key( HKEY_CURRENT_USER, fn );
258             free(fn);
259         }
260         break;
261     case HKEY_LOCAL_MACHINE:
262         /* Try first saving according to the defined location in .winerc */
263         fn = xmalloc ( MAX_PATHNAME_LEN);
264         if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "", 
265                                                     fn, MAX_PATHNAME_LEN - 1))
266             save_key( HKEY_LOCAL_MACHINE, fn );
267         free (fn);
268
269         if (home && writeToHome)
270         {
271             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
272                                strlen(SAVE_LOCAL_MACHINE) + 2);
273             strcpy(fn,home);
274             strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
275             save_key( HKEY_LOCAL_MACHINE, fn );
276             free(fn);
277         }
278         break;
279     case HKEY_USERS:
280         fn = xmalloc( MAX_PATHNAME_LEN );
281         if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "", 
282                                                     fn, MAX_PATHNAME_LEN - 1))
283             save_key( HKEY_USERS, fn );
284         free (fn);
285
286         if (home && writeToHome)
287         {
288             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
289                                strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
290             strcpy(fn,home);
291             strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
292             save_key( HKEY_USERS, fn );
293             free(fn);
294         }
295         break;
296     default:
297         ERR("unknown/invalid key handle !\n");
298         break;
299     }
300 }
301
302
303 /******************************************************************************
304  * SHELL_SaveRegistry [Internal]
305  */
306 void SHELL_SaveRegistry( void )
307 {
308     struct set_registry_levels_request *req = get_req_buffer();
309     char   buf[4];
310     HKEY   hkey;
311     int    all;
312
313     TRACE("(void)\n");
314
315     all=0;
316     if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) 
317     {
318         strcpy(buf,"yes");
319     } 
320     else 
321     {
322         DWORD len,junk,type;
323
324         len=4;
325         if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
326                                               VAL_SAVEUPDATED,
327                                               &junk,
328                                               &type,
329                                               buf,
330                                               &len)) || (type!=REG_SZ))
331         {
332             strcpy(buf,"yes");
333         }
334         RegCloseKey(hkey);
335     }
336
337     if (lstrcmpiA(buf,"yes")) all = 1;
338
339     /* set saving level (0 for saving everything, 1 for saving only modified keys) */
340     req->current = 1;
341     req->saving  = !all;
342     req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
343     server_call( REQ_SET_REGISTRY_LEVELS );
344
345     SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
346     SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
347     SHELL_SaveRegistryBranch(HKEY_USERS);
348 }
349
350 /* Periodic save callback */
351 static void CALLBACK periodic_save( ULONG_PTR dummy )
352 {
353     SHELL_SaveRegistry();
354 }
355
356 /************************ LOAD Registry Function ****************************/
357
358
359
360 /******************************************************************************
361  * _find_or_add_key [Internal]
362  */
363 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
364 {
365     HKEY subkey;
366     if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
367     if (keyname) free( keyname );
368     return subkey;
369 }
370
371 /******************************************************************************
372  * _find_or_add_value [Internal]
373  */
374 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
375 {
376     RegSetValueExW( hkey, name, 0, type, data, len );
377     if (name) free( name );
378     if (data) free( data );
379 }
380
381
382 /******************************************************************************
383  * _wine_read_line [Internal]
384  *
385  * reads a line including dynamically enlarging the readbuffer and throwing
386  * away comments
387  */
388 static int _wine_read_line( FILE *F, char **buf, int *len )
389 {
390         char    *s,*curread;
391         int     mylen,curoff;
392
393         curread = *buf;
394         mylen   = *len;
395         **buf   = '\0';
396         while (1) {
397                 while (1) {
398                         s=fgets(curread,mylen,F);
399                         if (s==NULL)
400                                 return 0; /* EOF */
401                         if (NULL==(s=strchr(curread,'\n'))) {
402                                 /* buffer wasn't large enough */
403                                 curoff  = strlen(*buf);
404                                 *buf    = xrealloc(*buf,*len*2);
405                                 curread = *buf + curoff;
406                                 mylen   = *len; /* we filled up the buffer and 
407                                                  * got new '*len' bytes to fill
408                                                  */
409                                 *len    = *len * 2;
410                         } else {
411                                 *s='\0';
412                                 break;
413                         }
414                 }
415                 /* throw away comments */
416                 if (**buf=='#' || **buf==';') {
417                         curread = *buf;
418                         mylen   = *len;
419                         continue;
420                 }
421                 if (s)  /* got end of line */
422                         break;
423         }
424         return 1;
425 }
426
427
428 /******************************************************************************
429  * _wine_read_USTRING [Internal]
430  *
431  * converts a char* into a UNICODE string (up to a special char)
432  * and returns the position exactly after that string
433  */
434 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
435 {
436         char    *s;
437         LPWSTR  ws;
438
439         /* read up to "=" or "\0" or "\n" */
440         s       = buf;
441         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
442         ws      = *str;
443         while (*s && (*s!='\n') && (*s!='=')) {
444                 if (*s!='\\')
445                         *ws++=*((unsigned char*)s++);
446                 else {
447                         s++;
448                         if (!*s) {
449                                 /* Dangling \ ... may only happen if a registry
450                                  * write was short. FIXME: What do to?
451                                  */
452                                  break;
453                         }
454                         if (*s=='\\') {
455                                 *ws++='\\';
456                                 s++;
457                                 continue;
458                         }
459                         if (*s!='u') {
460                                 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
461                                 *ws++='\\';
462                                 *ws++=*s++;
463                         } else {
464                                 char    xbuf[5];
465                                 int     wc;
466
467                                 s++;
468                                 memcpy(xbuf,s,4);xbuf[4]='\0';
469                                 if (!sscanf(xbuf,"%x",&wc))
470                                         WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
471                                 s+=4;
472                                 *ws++   =(unsigned short)wc;
473                         }
474                 }
475         }
476         *ws     = 0;
477         return s;
478 }
479
480
481 /******************************************************************************
482  * _wine_loadsubkey [Internal]
483  *
484  * NOTES
485  *    It seems like this is returning a boolean.  Should it?
486  *
487  * RETURNS
488  *    Success: 1
489  *    Failure: 0
490  */
491 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
492 {
493         HKEY subkey;
494         int             i;
495         char            *s;
496         LPWSTR          name;
497
498     TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
499
500     /* Good.  We already got a line here ... so parse it */
501     subkey = 0;
502     while (1) {
503         i=0;s=*buf;
504         while (*s=='\t') {
505             s++;
506             i++;
507         }
508         if (i>level) {
509             if (!subkey) {
510                 WARN("Got a subhierarchy without resp. key?\n");
511                 return 0;
512             }
513             if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
514                if (!_wine_read_line(F,buf,buflen))
515                   goto done;
516             continue;
517         }
518
519                 /* let the caller handle this line */
520                 if (i<level || **buf=='\0')
521                         goto done;
522
523                 /* it can be: a value or a keyname. Parse the name first */
524                 s=_wine_read_USTRING(s,&name);
525
526                 /* switch() default: hack to avoid gotos */
527                 switch (0) {
528                 default:
529                         if (*s=='\0') {
530                                 if (subkey) RegCloseKey( subkey );
531                                 subkey=_find_or_add_key(hkey,name);
532                         } else {
533                                 LPBYTE          data;
534                                 int             len,lastmodified,type;
535
536                                 if (*s!='=') {
537                                         WARN("Unexpected character: %c\n",*s);
538                                         break;
539                                 }
540                                 s++;
541                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
542                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
543                                         break;
544                                 }
545                                 /* skip the 2 , */
546                                 s=strchr(s,',');s++;
547                                 s=strchr(s,',');
548                                 if (!s++) {
549                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
550                                         break;
551                                 }
552                                 if (type == REG_SZ || type == REG_EXPAND_SZ) {
553                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
554                                         len = lstrlenW((LPWSTR)data)*2+2;
555                                 } else {
556                                         len=strlen(s)/2;
557                                         data = (LPBYTE)xmalloc(len+1);
558                                         for (i=0;i<len;i++) {
559                                                 data[i]=0;
560                                                 if (*s>='0' && *s<='9')
561                                                         data[i]=(*s-'0')<<4;
562                                                 if (*s>='a' && *s<='f')
563                                                         data[i]=(*s-'a'+'\xa')<<4;
564                                                 if (*s>='A' && *s<='F')
565                                                         data[i]=(*s-'A'+'\xa')<<4;
566                                                 s++;
567                                                 if (*s>='0' && *s<='9')
568                                                         data[i]|=*s-'0';
569                                                 if (*s>='a' && *s<='f')
570                                                         data[i]|=*s-'a'+'\xa';
571                                                 if (*s>='A' && *s<='F')
572                                                         data[i]|=*s-'A'+'\xa';
573                                                 s++;
574                                         }
575                                 }
576                                 _find_or_add_value(hkey,name,type,data,len);
577                         }
578                 }
579                 /* read the next line */
580                 if (!_wine_read_line(F,buf,buflen))
581                         goto done;
582     }
583  done:
584     if (subkey) RegCloseKey( subkey );
585     return 1;
586 }
587
588
589 /******************************************************************************
590  * _wine_loadsubreg [Internal]
591  */
592 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
593 {
594         int     ver;
595         char    *buf;
596         int     buflen;
597
598         buf=xmalloc(10);buflen=10;
599         if (!_wine_read_line(F,&buf,&buflen)) {
600                 free(buf);
601                 return 0;
602         }
603         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
604                 free(buf);
605                 return 0;
606         }
607         if (ver!=REGISTRY_SAVE_VERSION) {
608             if (ver == 2)  /* new version */
609             {
610                 HANDLE file;
611                 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
612                                              FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
613                 {
614                     struct load_registry_request *req = get_req_buffer();
615                     req->hkey    = hkey;
616                     req->file    = file;
617                     req->name[0] = 0;
618                     server_call( REQ_LOAD_REGISTRY );
619                     CloseHandle( file );
620                 }
621                 free( buf );
622                 return 1;
623             }
624             else
625             {
626                 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
627                 free(buf);
628                 return 0;
629             }
630         }
631         if (!_wine_read_line(F,&buf,&buflen)) {
632                 free(buf);
633                 return 0;
634         }
635         if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
636                 free(buf);
637                 return 0;
638         }
639         free(buf);
640         return 1;
641 }
642
643
644 /******************************************************************************
645  * _wine_loadreg [Internal]
646  */
647 static void _wine_loadreg( HKEY hkey, char *fn )
648 {
649     FILE *F;
650
651     TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
652
653     F = fopen(fn,"rb");
654     if (F==NULL) {
655         WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
656         return;
657     }
658     _wine_loadsubreg(F,hkey,fn);
659     fclose(F);
660 }
661
662 /* NT REGISTRY LOADER */
663
664 #ifdef HAVE_SYS_MMAN_H
665 # include <sys/mman.h>
666 #endif
667
668 #ifndef MAP_FAILED
669 #define MAP_FAILED ((LPVOID)-1)
670 #endif
671
672 #define  NT_REG_BLOCK_SIZE              0x1000
673
674 #define NT_REG_HEADER_BLOCK_ID       0x66676572 /* regf */
675 #define NT_REG_POOL_BLOCK_ID         0x6E696268 /* hbin */
676 #define NT_REG_KEY_BLOCK_ID          0x6b6e
677 #define NT_REG_VALUE_BLOCK_ID        0x6b76
678 #define NT_REG_HASH_BLOCK_ID         0x666c
679 #define NT_REG_NOHASH_BLOCK_ID       0x696c
680 #define NT_REG_KEY_BLOCK_TYPE        0x20
681 #define NT_REG_ROOT_KEY_BLOCK_TYPE   0x2c
682
683 typedef struct 
684 {
685         DWORD   id;             /* 0x66676572 'regf'*/
686         DWORD   uk1;            /* 0x04 */
687         DWORD   uk2;            /* 0x08 */
688         FILETIME        DateModified;   /* 0x0c */
689         DWORD   uk3;            /* 0x14 */
690         DWORD   uk4;            /* 0x18 */
691         DWORD   uk5;            /* 0x1c */
692         DWORD   uk6;            /* 0x20 */
693         DWORD   RootKeyBlock;   /* 0x24 */
694         DWORD   BlockSize;      /* 0x28 */
695         DWORD   uk7[116];       
696         DWORD   Checksum; /* at offset 0x1FC */
697 } nt_regf;
698
699 typedef struct
700 {
701         DWORD   blocksize;
702         BYTE    data[1];
703 } nt_hbin_sub;
704
705 typedef struct
706 {
707         DWORD   id;             /* 0x6E696268 'hbin' */
708         DWORD   off_prev;
709         DWORD   off_next;
710         DWORD   uk1;
711         DWORD   uk2;            /* 0x10 */
712         DWORD   uk3;            /* 0x14 */
713         DWORD   uk4;            /* 0x18 */
714         DWORD   size;           /* 0x1C */
715         nt_hbin_sub     hbin_sub;       /* 0x20 */
716 } nt_hbin;
717
718 /*
719  * the value_list consists of offsets to the values (vk)
720  */
721 typedef struct
722 {
723         WORD    SubBlockId;             /* 0x00 0x6B6E */
724         WORD    Type;                   /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
725         FILETIME        writetime;      /* 0x04 */
726         DWORD   uk1;                    /* 0x0C */
727         DWORD   parent_off;             /* 0x10 Offset of Owner/Parent key */
728         DWORD   nr_subkeys;             /* 0x14 number of sub-Keys */
729         DWORD   uk8;                    /* 0x18 */
730         DWORD   lf_off;                 /* 0x1C Offset of the sub-key lf-Records */
731         DWORD   uk2;                    /* 0x20 */
732         DWORD   nr_values;              /* 0x24 number of values */
733         DWORD   valuelist_off;          /* 0x28 Offset of the Value-List */
734         DWORD   off_sk;                 /* 0x2c Offset of the sk-Record */
735         DWORD   off_class;              /* 0x30 Offset of the Class-Name */
736         DWORD   uk3;                    /* 0x34 */
737         DWORD   uk4;                    /* 0x38 */
738         DWORD   uk5;                    /* 0x3c */
739         DWORD   uk6;                    /* 0x40 */
740         DWORD   uk7;                    /* 0x44 */
741         WORD    name_len;               /* 0x48 name-length */
742         WORD    class_len;              /* 0x4a class-name length */
743         char    name[1];                /* 0x4c key-name */
744 } nt_nk;
745
746 typedef struct
747 {
748         DWORD   off_nk; /* 0x00 */
749         DWORD   name;   /* 0x04 */
750 } hash_rec;
751
752 typedef struct
753 {
754         WORD    id;             /* 0x00 0x666c */
755         WORD    nr_keys;        /* 0x06 */
756         hash_rec        hash_rec[1];
757 } nt_lf;
758
759 typedef struct
760 {
761         WORD    id;             /* 0x00 0x696c */
762         WORD    nr_keys;
763         DWORD   off_nk[1];
764 } nt_il;
765
766 typedef struct
767 {
768         WORD    id;             /* 0x00 'vk' */
769         WORD    nam_len;
770         DWORD   data_len;
771         DWORD   data_off;
772         DWORD   type;
773         WORD    flag;
774         WORD    uk1;
775         char    name[1];
776 } nt_vk;
777
778 LPSTR _strdupnA( LPCSTR str, int len )
779 {
780     LPSTR ret;
781
782     if (!str) return NULL;
783     ret = malloc( len + 1 );
784     lstrcpynA( ret, str, len );
785     ret[len] = 0x00;
786     return ret;
787 }
788
789 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
790 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
791 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
792
793
794 /*
795  * gets a value
796  *
797  * vk->flag:
798  *  0 value is a default value
799  *  1 the value has a name
800  *
801  * vk->data_len
802  *  len of the whole data block
803  *  - reg_sz (unicode)
804  *    bytes including the terminating \0 = 2*(number_of_chars+1)
805  *  - reg_dword, reg_binary:
806  *    if highest bit of data_len is set data_off contains the value
807  */
808 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
809 {
810         WCHAR name [256];
811         DWORD ret;
812         BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
813
814         if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
815
816         lstrcpynAtoW(name, vk->name, vk->nam_len+1);
817
818         ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
819                         (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
820                         (vk->data_len & 0x7fffffff) );
821         if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
822         return TRUE;
823 error:
824         ERR_(reg)("vk block invalid\n");
825         return FALSE;
826 }
827
828 /*
829  * get the subkeys
830  *
831  * this structure contains the hash of a keyname and points to all
832  * subkeys
833  *
834  * exception: if the id is 'il' there are no hash values and every 
835  * dword is a offset
836  */
837 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
838 {
839         int i;
840
841         if (lf->id == NT_REG_HASH_BLOCK_ID)
842         {
843           for (i=0; i<lf->nr_keys; i++)
844           {
845             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
846           }
847           
848         }
849         else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
850         {
851           for (i=0; i<lf->nr_keys; i++)
852           {
853             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
854           }
855         }
856         return TRUE;
857         
858 error:  ERR_(reg)("error reading lf block\n");
859         return FALSE;
860 }
861
862 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
863 {
864         char * name;
865         int i;
866         DWORD * vl;
867         HKEY subkey = hkey;
868
869         if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID) goto error;
870         if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
871            (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) goto error;
872
873         /* create the new key */
874         if(level <= 0)
875         {
876           name = _strdupnA( nk->name, nk->name_len+1);
877           if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
878           free(name);
879         }
880
881         /* loop through the subkeys */
882         if (nk->nr_subkeys)
883         {
884           nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
885           if (nk->nr_subkeys != lf->nr_keys) goto error1;
886           if (!_nt_parse_lf(subkey, base, lf, level-1)) goto error1;
887         }
888
889         /* loop trough the value list */
890         vl = (DWORD *)(base+nk->valuelist_off+4);
891         for (i=0; i<nk->nr_values; i++)
892         {
893           nt_vk * vk = (nt_vk*)(base+vl[i]+4);
894           if (!_nt_parse_vk(subkey, base, vk)) goto error1;
895         }
896
897         RegCloseKey(subkey);
898         return TRUE;
899         
900 error1: RegCloseKey(subkey);
901 error:  ERR_(reg)("error reading nk block\n");
902         return FALSE;
903 }
904
905 /* end nt loader */
906
907 /* windows 95 registry loader */
908
909 /* SECTION 1: main header
910  *
911  * once at offset 0
912  */
913 #define W95_REG_CREG_ID 0x47455243
914
915 typedef struct 
916 {
917         DWORD   id;             /* "CREG" = W95_REG_CREG_ID */
918         DWORD   version;        /* ???? 0x00010000 */
919         DWORD   rgdb_off;       /* 0x08 Offset of 1st RGDB-block */
920         DWORD   uk2;            /* 0x0c */
921         WORD    rgdb_num;       /* 0x10 # of RGDB-blocks */
922         WORD    uk3;
923         DWORD   uk[3];
924         /* rgkn */
925 } _w95creg;
926
927 /* SECTION 2: Directory information (tree structure)
928  *
929  * once on offset 0x20
930  *
931  * structure: [rgkn][dke]*      (repeat till rgkn->size is reached)
932  */
933 #define W95_REG_RGKN_ID 0x4e4b4752
934
935 typedef struct
936 {
937         DWORD   id;             /*"RGKN" = W95_REG_RGKN_ID */
938         DWORD   size;           /* Size of the RGKN-block */
939         DWORD   root_off;       /* Rel. Offset of the root-record */
940         DWORD   uk[5];
941 } _w95rgkn;
942
943 /* Disk Key Entry Structure
944  *
945  * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
946  * hive itself. It looks the same like other keys. Even the ID-number can
947  * be any value.
948  *
949  * The "hash"-value is a value representing the key's name. Windows will not
950  * search for the name, but for a matching hash-value. if it finds one, it
951  * will compare the actual string info, otherwise continue with the next key.
952  * To calculate the hash initialize a D-Word with 0 and add all ASCII-values 
953  * of the string which are smaller than 0x80 (128) to this D-Word.   
954  *
955  * If you want to modify key names, also modify the hash-values, since they
956  * cannot be found again (although they would be displayed in REGEDIT)
957  * End of list-pointers are filled with 0xFFFFFFFF
958  *
959  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
960  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
961  * structure) and reading another RGDB_section.
962  *
963  * there is a one to one relationship between dke and dkh
964  */
965  /* key struct, once per key */
966 typedef struct
967 {
968         DWORD   x1;             /* Free entry indicator(?) */
969         DWORD   hash;           /* sum of bytes of keyname */
970         DWORD   x3;             /* Root key indicator? usually 0xFFFFFFFF */
971         DWORD   prevlvl;        /* offset of previous key */
972         DWORD   nextsub;        /* offset of child key */
973         DWORD   next;           /* offset of sibling key */
974         WORD    nrLS;           /* id inside the rgdb block */
975         WORD    nrMS;           /* number of the rgdb block */
976 } _w95dke;
977
978 /* SECTION 3: key information, values and data
979  *
980  * structure:
981  *  section:    [blocks]*               (repeat creg->rgdb_num times)
982  *  blocks:     [rgdb] [subblocks]*     (repeat till block size reached )
983  *  subblocks:  [dkh] [dkv]*            (repeat dkh->values times )
984  *
985  * An interesting relationship exists in RGDB_section. The value at offset
986  * 10 equals the value at offset 4 minus the value at offset 8. I have no
987  * idea at the moment what this means.  (Kevin Cozens)
988  */
989
990 /* block header, once per block */
991 #define W95_REG_RGDB_ID 0x42444752
992
993 typedef struct
994 {
995         DWORD   id;     /* 0x00 'rgdb' = W95_REG_RGDB_ID */
996         DWORD   size;   /* 0x04 */
997         DWORD   uk1;    /* 0x08 */
998         DWORD   uk2;    /* 0x0c */
999         DWORD   uk3;    /* 0x10 */
1000         DWORD   uk4;    /* 0x14 */
1001         DWORD   uk5;    /* 0x18 */
1002         DWORD   uk6;    /* 0x1c */
1003         /* dkh */
1004 } _w95rgdb;
1005
1006 /* Disk Key Header structure (RGDB part), once per key */
1007 typedef struct 
1008 {
1009         DWORD   nextkeyoff;     /* 0x00 offset to next dkh*/
1010         WORD    nrLS;           /* 0x04 id inside the rgdb block */
1011         WORD    nrMS;           /* 0x06 number of the rgdb block */
1012         DWORD   bytesused;      /* 0x08 */
1013         WORD    keynamelen;     /* 0x0c len of name */
1014         WORD    values;         /* 0x0e number of values */
1015         DWORD   xx1;            /* 0x10 */
1016         char    name[1];        /* 0x14 */
1017         /* dkv */               /* 0x14 + keynamelen */
1018 } _w95dkh;
1019
1020 /* Disk Key Value structure, once per value */
1021 typedef struct
1022 {
1023         DWORD   type;           /* 0x00 */
1024         DWORD   x1;             /* 0x04 */
1025         WORD    valnamelen;     /* 0x08 length of name, 0 is default key */
1026         WORD    valdatalen;     /* 0x0A length of data */
1027         char    name[1];        /* 0x0c */
1028         /* raw data */          /* 0x0c + valnamelen */
1029 } _w95dkv;
1030
1031 /******************************************************************************
1032  * _w95_lookup_dkh [Internal]
1033  *
1034  * seeks the dkh belonging to a dke
1035  */
1036 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1037 {
1038         _w95rgdb * rgdb;
1039         _w95dkh * dkh;
1040         int i;
1041         
1042         rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);         /* get the beginning of the rgdb datastore */
1043         assert (creg->rgdb_num > nrMS);                         /* check: requested block < last_block) */
1044         
1045         /* find the right block */
1046         for(i=0; i<nrMS ;i++)
1047         {
1048           assert(rgdb->id == W95_REG_RGDB_ID);                          /* check the magic */
1049           rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size);          /* find next block */
1050         }
1051
1052         dkh = (_w95dkh*)(rgdb + 1);                             /* first sub block within the rgdb */
1053
1054         do
1055         {
1056           if(nrLS==dkh->nrLS ) return dkh;
1057           dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff);       /* find next subblock */
1058         } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1059
1060         return NULL;
1061 }       
1062  
1063 /******************************************************************************
1064  * _w95_parse_dkv [Internal]
1065  */
1066 static int _w95_parse_dkv (
1067         HKEY hkey,
1068         _w95dkh * dkh,
1069         int nrLS,
1070         int nrMS )
1071 {
1072         _w95dkv * dkv;
1073         int i;
1074         DWORD ret;
1075         char * name;
1076                         
1077         /* first value block */
1078         dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1079
1080         /* loop trought the values */
1081         for (i=0; i< dkh->values; i++)
1082         {
1083           name = _strdupnA(dkv->name, dkv->valnamelen+1);
1084           ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen); 
1085           if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1086           free (name);
1087
1088           /* next value */
1089           dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1090         }
1091         return TRUE;
1092 }
1093
1094 /******************************************************************************
1095  * _w95_parse_dke [Internal]
1096  */
1097 static int _w95_parse_dke( 
1098         HKEY hkey,
1099         _w95creg * creg,
1100         _w95rgkn *rgkn,
1101         _w95dke * dke,
1102         int level )
1103 {
1104         _w95dkh * dkh;
1105         HKEY hsubkey = hkey;
1106         char * name;
1107         int ret = FALSE;
1108
1109         /* get start address of root key block */
1110         if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1111         
1112         /* special root key */
1113         if (dke->nrLS == 0xffff || dke->nrMS==0xffff)           /* eg. the root key has no name */
1114         {
1115           /* parse the one subkey*/
1116           if (dke->nextsub != 0xffffffff) 
1117           {
1118             return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1119           }
1120           /* has no sibling keys */
1121           goto error;
1122         }
1123
1124         /* search subblock */
1125         if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1126         {
1127           fprintf(stderr, "dke pointing to missing dkh !\n");
1128           goto error;
1129         }
1130
1131         if ( level <= 0 )
1132         {
1133           /* walk sibling keys */
1134           if (dke->next != 0xffffffff )
1135           {
1136             if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1137           }
1138
1139           /* create subkey and insert values */
1140           name = _strdupnA( dkh->name, dkh->keynamelen+1);
1141           if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1142           free(name);
1143           if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1144         }  
1145         
1146         /* next sub key */
1147         if (dke->nextsub != 0xffffffff) 
1148         {
1149           if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1150         }
1151
1152         ret = TRUE;
1153 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1154 error:  return ret;
1155 }
1156 /* end windows 95 loader */
1157
1158 /******************************************************************************
1159  *      NativeRegLoadKey [Internal]
1160  *
1161  * Loads a native registry file (win95/nt)
1162  *      hkey    root key
1163  *      fn      filename
1164  *      level   number of levels to cut away (eg. ".Default" in user.dat)
1165  *
1166  * this function intentionally uses unix file functions to make it possible
1167  * to move it to a seperate registry helper programm
1168  */
1169 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1170 {
1171         int fd = 0;
1172         struct stat st;
1173         DOS_FULL_NAME full_name;
1174         int ret = FALSE;
1175         void * base;
1176                         
1177         if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1178         
1179         /* map the registry into the memory */
1180         if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1181         if ((fstat(fd, &st) == -1)) goto error;
1182         if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1183
1184         switch (*(LPDWORD)base)
1185         {
1186           /* windows 95 'creg' */
1187           case W95_REG_CREG_ID:
1188             {
1189               _w95creg * creg;
1190               _w95rgkn * rgkn;
1191               creg = base;
1192               TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1193
1194               /* load the header (rgkn) */
1195               rgkn = (_w95rgkn*)(creg + 1);
1196               if (rgkn->id != W95_REG_RGKN_ID) 
1197               {
1198                 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1199                 goto error1;
1200               }
1201
1202               ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1203             }
1204             break;
1205           /* nt 'regf'*/
1206           case NT_REG_HEADER_BLOCK_ID:
1207             {
1208               nt_regf * regf;
1209               nt_hbin * hbin;
1210               nt_hbin_sub * hbin_sub;
1211               nt_nk* nk;
1212
1213               TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1214
1215               /* start block */
1216               regf = base;
1217
1218               /* hbin block */
1219               hbin = base + 0x1000;
1220               if (hbin->id != NT_REG_POOL_BLOCK_ID)
1221               {
1222                 ERR_(reg)( "%s hbin block invalid\n", fn);
1223                 goto error1;
1224               }
1225
1226               /* hbin_sub block */
1227               hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1228               if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1229               {
1230                 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1231                 goto error1;
1232               }
1233
1234               /* nk block */
1235               nk = (nt_nk*)&(hbin_sub->data[0]);
1236               if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1237               {
1238                 ERR_(reg)( "%s special nk block not found\n", fn);
1239                 goto error1;
1240               }
1241
1242               ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
1243             }
1244             break;
1245           default:
1246             {
1247               ERR("unknown signature in registry file %s.\n",fn);
1248               goto error1;
1249             }
1250         }
1251         if(!ret) ERR("error loading registry file %s\n", fn);
1252 error1: munmap(base, st.st_size);
1253 error:  close(fd);
1254         return ret;     
1255 }
1256
1257 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1258 /*
1259     reghack - windows 3.11 registry data format demo program.
1260
1261     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1262     a combined hash table and tree description, and finally a text table.
1263
1264     The header is obvious from the struct header. The taboff1 and taboff2
1265     fields are always 0x20, and their usage is unknown.
1266
1267     The 8-byte entry table has various entry types.
1268
1269     tabent[0] is a root index. The second word has the index of the root of
1270             the directory.
1271     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1272             the index of the key/value that has that hash. Data with the same
1273             hash value are on a circular list. The other three words in the
1274             hash entry are always zero.
1275     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1276             entry: dirent and keyent/valent. They are identified by context.
1277     tabent[freeidx] is the first free entry. The first word in a free entry
1278             is the index of the next free entry. The last has 0 as a link.
1279             The other three words in the free list are probably irrelevant.
1280
1281     Entries in text table are preceeded by a word at offset-2. This word
1282     has the value (2*index)+1, where index is the referring keyent/valent
1283     entry in the table. I have no suggestion for the 2* and the +1.
1284     Following the word, there are N bytes of data, as per the keyent/valent
1285     entry length. The offset of the keyent/valent entry is from the start
1286     of the text table to the first data byte.
1287
1288     This information is not available from Microsoft. The data format is
1289     deduced from the reg.dat file by me. Mistakes may
1290     have been made. I claim no rights and give no guarantees for this program.
1291
1292     Tor Sjøwall, tor@sn.no
1293 */
1294
1295 /* reg.dat header format */
1296 struct _w31_header {
1297         char            cookie[8];      /* 'SHCC3.10' */
1298         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1299         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1300         unsigned long   tabcnt;         /* number of entries in index table */
1301         unsigned long   textoff;        /* offset of text part */
1302         unsigned long   textsize;       /* byte size of text part */
1303         unsigned short  hashsize;       /* hash size */
1304         unsigned short  freeidx;        /* free index */
1305 };
1306
1307 /* generic format of table entries */
1308 struct _w31_tabent {
1309         unsigned short w0, w1, w2, w3;
1310 };
1311
1312 /* directory tabent: */
1313 struct _w31_dirent {
1314         unsigned short  sibling_idx;    /* table index of sibling dirent */
1315         unsigned short  child_idx;      /* table index of child dirent */
1316         unsigned short  key_idx;        /* table index of key keyent */
1317         unsigned short  value_idx;      /* table index of value valent */
1318 };
1319
1320 /* key tabent: */
1321 struct _w31_keyent {
1322         unsigned short  hash_idx;       /* hash chain index for string */
1323         unsigned short  refcnt;         /* reference count */
1324         unsigned short  length;         /* length of string */
1325         unsigned short  string_off;     /* offset of string in text table */
1326 };
1327
1328 /* value tabent: */
1329 struct _w31_valent {
1330         unsigned short  hash_idx;       /* hash chain index for string */
1331         unsigned short  refcnt;         /* reference count */
1332         unsigned short  length;         /* length of string */
1333         unsigned short  string_off;     /* offset of string in text table */
1334 };
1335
1336 /* recursive helper function to display a directory tree */
1337 void
1338 __w31_dumptree( unsigned short idx,
1339                 unsigned char *txt,
1340                 struct _w31_tabent *tab,
1341                 struct _w31_header *head,
1342                 HKEY hkey,
1343                 time_t          lastmodified,
1344                 int             level
1345 ) {
1346         struct _w31_dirent      *dir;
1347         struct _w31_keyent      *key;
1348         struct _w31_valent      *val;
1349         HKEY subkey = 0;
1350         static char             tail[400];
1351
1352         while (idx!=0) {
1353                 dir=(struct _w31_dirent*)&tab[idx];
1354
1355                 if (dir->key_idx) {
1356                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1357
1358                         memcpy(tail,&txt[key->string_off],key->length);
1359                         tail[key->length]='\0';
1360                         /* all toplevel entries AND the entries in the 
1361                          * toplevel subdirectory belong to \SOFTWARE\Classes
1362                          */
1363                         if (!level && !lstrcmpA(tail,".classes")) {
1364                                 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1365                                 idx=dir->sibling_idx;
1366                                 continue;
1367                         }
1368                         if (subkey) RegCloseKey( subkey );
1369                         if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1370                         /* only add if leaf node or valued node */
1371                         if (dir->value_idx!=0||dir->child_idx==0) {
1372                                 if (dir->value_idx) {
1373                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1374                                         memcpy(tail,&txt[val->string_off],val->length);
1375                                         tail[val->length]='\0';
1376                                         RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1377                                 }
1378                         }
1379                 } else {
1380                         TRACE("strange: no directory key name, idx=%04x\n", idx);
1381                 }
1382                 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1383                 idx=dir->sibling_idx;
1384         }
1385         if (subkey) RegCloseKey( subkey );
1386 }
1387
1388
1389 /******************************************************************************
1390  * _w31_loadreg [Internal]
1391  */
1392 void _w31_loadreg(void) {
1393         HFILE                   hf;
1394         struct _w31_header      head;
1395         struct _w31_tabent      *tab;
1396         unsigned char           *txt;
1397         int                     len;
1398         OFSTRUCT                ofs;
1399         BY_HANDLE_FILE_INFORMATION hfinfo;
1400         time_t                  lastmodified;
1401
1402         TRACE("(void)\n");
1403
1404         hf = OpenFile("reg.dat",&ofs,OF_READ);
1405         if (hf==HFILE_ERROR)
1406                 return;
1407
1408         /* read & dump header */
1409         if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1410                 ERR("reg.dat is too short.\n");
1411                 _lclose(hf);
1412                 return;
1413         }
1414         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1415                 ERR("reg.dat has bad signature.\n");
1416                 _lclose(hf);
1417                 return;
1418         }
1419
1420         len = head.tabcnt * sizeof(struct _w31_tabent);
1421         /* read and dump index table */
1422         tab = xmalloc(len);
1423         if (len!=_lread(hf,tab,len)) {
1424                 ERR("couldn't read %d bytes.\n",len); 
1425                 free(tab);
1426                 _lclose(hf);
1427                 return;
1428         }
1429
1430         /* read text */
1431         txt = xmalloc(head.textsize);
1432         if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1433                 ERR("couldn't seek to textblock.\n"); 
1434                 free(tab);
1435                 free(txt);
1436                 _lclose(hf);
1437                 return;
1438         }
1439         if (head.textsize!=_lread(hf,txt,head.textsize)) {
1440                 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize); 
1441                 free(tab);
1442                 free(txt);
1443                 _lclose(hf);
1444                 return;
1445         }
1446
1447         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1448                 ERR("GetFileInformationByHandle failed?.\n"); 
1449                 free(tab);
1450                 free(txt);
1451                 _lclose(hf);
1452                 return;
1453         }
1454         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1455         __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1456         free(tab);
1457         free(txt);
1458         _lclose(hf);
1459         return;
1460 }
1461
1462 /**********************************************************************************
1463  * SetLoadLevel [Internal]
1464  *
1465  * set level to 0 for loading system files
1466  * set level to 1 for loading user files
1467  */
1468 static void SetLoadLevel(int level)
1469 {
1470         struct set_registry_levels_request *req = get_req_buffer();
1471
1472         req->current = level;
1473         req->saving  = 0;
1474         req->version = 1;
1475         server_call( REQ_SET_REGISTRY_LEVELS );
1476 }
1477
1478 /**********************************************************************************
1479  * SHELL_LoadRegistry [Internal]
1480  */
1481 void SHELL_LoadRegistry( void )
1482 {
1483   int   save_timeout;
1484   char  *fn, *home;
1485   HKEY  hkey;
1486
1487   TRACE("(void)\n");
1488
1489   if (!CLIENT_IsBootThread()) return;  /* already loaded */
1490
1491   REGISTRY_Init();
1492   SetLoadLevel(0);
1493
1494   if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1)) 
1495   { 
1496       /* Load windows 3.1 entries */
1497       _w31_loadreg();
1498   }
1499   if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1)) 
1500   { 
1501       /* Load windows 95 entries */
1502       NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1503       NativeRegLoadKey(HKEY_LOCAL_MACHINE, "system.dat", 0);
1504       NativeRegLoadKey(HKEY_CURRENT_USER, "user.dat", 1);
1505   }
1506   if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1)) 
1507   { 
1508       fn = xmalloc( MAX_PATHNAME_LEN ); 
1509       home = xmalloc ( MAX_PATHNAME_LEN );
1510       if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1)) 
1511       {
1512          GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1513          strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1514          strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1515          strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
1516          NativeRegLoadKey( HKEY_CURRENT_USER, fn, 1 );
1517       }     
1518       /*
1519       * FIXME
1520       *  map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1521       */
1522       GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1523
1524       strcpy(home, fn);
1525       strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
1526       NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1527
1528       strcpy(home, fn);
1529       strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
1530       NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1531
1532       strcpy(home, fn);
1533       strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
1534       NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1535
1536       strcpy(home, fn);
1537       strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
1538       NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1539
1540       free (home);
1541       free (fn);
1542       /* this key is generated when the nt-core booted successfully */
1543       if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1544         RegCloseKey(hkey);
1545   }
1546
1547   if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1548   {
1549       /* 
1550        * Load the global HKU hive directly from sysconfdir
1551        */ 
1552       _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1553
1554       /* 
1555        * Load the global machine defaults directly form sysconfdir
1556        */
1557       _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1558   }
1559
1560   SetLoadLevel(1);
1561
1562   /*
1563    * Load the user saved registries 
1564    */
1565   if (!(home = getenv( "HOME" )))
1566       WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1567   else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1568   {
1569       /* 
1570        * Load user's personal versions of global HKU/.Default keys
1571        */
1572       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1573                          strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1574       strcpy(fn, home);
1575       strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1576       _wine_loadreg( HKEY_USERS, fn ); 
1577       free(fn);
1578
1579       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1580       strcpy(fn, home);
1581       strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1582       _wine_loadreg( HKEY_CURRENT_USER, fn );
1583       free(fn);
1584
1585       /* 
1586        * Load HKLM, attempt to get the registry location from the config 
1587        * file first, if exist, load and keep going.
1588        */
1589       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1590       strcpy(fn,home);
1591       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1592       _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1593       free(fn);
1594   }
1595   
1596   /* 
1597    * Load HKCU, get the registry location from the config 
1598    * file, if exist, load and keep going.
1599    */      
1600   if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1601   {
1602       fn = xmalloc( MAX_PATHNAME_LEN ); 
1603       if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", 
1604                                      fn, MAX_PATHNAME_LEN - 1)) 
1605        {
1606          _wine_loadreg( HKEY_CURRENT_USER, fn );
1607        }
1608       free (fn);
1609       /*
1610        * Load HKU, get the registry location from the config
1611        * file, if exist, load and keep going.
1612        */
1613       fn = xmalloc ( MAX_PATHNAME_LEN );
1614       if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1615                                       fn, MAX_PATHNAME_LEN - 1))
1616        {
1617          _wine_loadreg( HKEY_USERS, fn );
1618        }
1619       free (fn);
1620       /*
1621        * Load HKLM, get the registry location from the config
1622        * file, if exist, load and keep going.
1623        */
1624       fn = xmalloc ( MAX_PATHNAME_LEN );
1625       if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1626                                      fn, MAX_PATHNAME_LEN - 1))
1627        {
1628          _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1629        }
1630       free (fn);
1631   }
1632   
1633   /* 
1634    * Make sure the update mode is there
1635    */
1636   if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) 
1637   {
1638     DWORD       junk,type,len;
1639     char        data[5];
1640
1641     len=4;
1642     if ((       RegQueryValueExA(
1643             hkey,
1644             VAL_SAVEUPDATED,
1645             &junk,
1646             &type,
1647             data,
1648             &len) != ERROR_SUCCESS) || (type != REG_SZ))
1649     {
1650       RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1651     }
1652
1653     RegCloseKey(hkey);
1654   }
1655
1656   if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1657   {
1658       SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1659   }
1660 }
1661
1662
1663 /********************* API FUNCTIONS ***************************************/
1664
1665
1666
1667
1668 /******************************************************************************
1669  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1670  * Immediately writes key to registry.
1671  * Only returns after data has been written to disk.
1672  *
1673  * FIXME: does it really wait until data is written ?
1674  *
1675  * PARAMS
1676  *    hkey [I] Handle of key to write
1677  *
1678  * RETURNS
1679  *    Success: ERROR_SUCCESS
1680  *    Failure: Error code
1681  */
1682 DWORD WINAPI RegFlushKey( HKEY hkey )
1683 {
1684     FIXME( "(%x): stub\n", hkey );
1685     return ERROR_SUCCESS;
1686 }
1687
1688 /******************************************************************************
1689  * RegConnectRegistry32W [ADVAPI32.128]
1690  *
1691  * PARAMS
1692  *    lpMachineName [I] Address of name of remote computer
1693  *    hHey          [I] Predefined registry handle
1694  *    phkResult     [I] Address of buffer for remote registry handle
1695  */
1696 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
1697                                    LPHKEY phkResult )
1698 {
1699     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1700
1701     if (!lpMachineName || !*lpMachineName) {
1702         /* Use the local machine name */
1703         return RegOpenKey16( hKey, "", phkResult );
1704     }
1705
1706     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1707     return ERROR_BAD_NETPATH;
1708 }
1709
1710
1711 /******************************************************************************
1712  * RegConnectRegistry32A [ADVAPI32.127]
1713  */
1714 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1715 {
1716     DWORD ret;
1717     LPWSTR machineW = strdupA2W(machine);
1718     ret = RegConnectRegistryW( machineW, hkey, reskey );
1719     free(machineW);
1720     return ret;
1721 }
1722
1723
1724 /******************************************************************************
1725  * RegGetKeySecurity [ADVAPI32.144]
1726  * Retrieves a copy of security descriptor protecting the registry key
1727  *
1728  * PARAMS
1729  *    hkey                   [I]   Open handle of key to set
1730  *    SecurityInformation    [I]   Descriptor contents
1731  *    pSecurityDescriptor    [O]   Address of descriptor for key
1732  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1733  *
1734  * RETURNS
1735  *    Success: ERROR_SUCCESS
1736  *    Failure: Error code
1737  */
1738 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
1739                                SECURITY_INFORMATION SecurityInformation,
1740                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1741                                LPDWORD lpcbSecurityDescriptor )
1742 {
1743     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1744           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1745
1746     /* FIXME: Check for valid SecurityInformation values */
1747
1748     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1749         return ERROR_INSUFFICIENT_BUFFER;
1750
1751     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1752           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1753
1754     return ERROR_SUCCESS;
1755 }
1756
1757
1758 /******************************************************************************
1759  * RegNotifyChangeKeyValue [ADVAPI32.???]
1760  *
1761  * PARAMS
1762  *    hkey            [I] Handle of key to watch
1763  *    fWatchSubTree   [I] Flag for subkey notification
1764  *    fdwNotifyFilter [I] Changes to be reported
1765  *    hEvent          [I] Handle of signaled event
1766  *    fAsync          [I] Flag for asynchronous reporting
1767  */
1768 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
1769                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1770                                      BOOL fAsync )
1771 {
1772     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1773           hEvent,fAsync);
1774     return ERROR_SUCCESS;
1775 }
1776
1777
1778 /******************************************************************************
1779  * RegUnLoadKey32W [ADVAPI32.173]
1780  *
1781  * PARAMS
1782  *    hkey     [I] Handle of open key
1783  *    lpSubKey [I] Address of name of subkey to unload
1784  */
1785 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1786 {
1787     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1788     return ERROR_SUCCESS;
1789 }
1790
1791
1792 /******************************************************************************
1793  * RegUnLoadKey32A [ADVAPI32.172]
1794  */
1795 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1796 {
1797     LONG ret;
1798     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1799     ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1800     if(lpSubKeyW) free(lpSubKeyW);
1801     return ret;
1802 }
1803
1804
1805 /******************************************************************************
1806  * RegSetKeySecurity [ADVAPI32.167]
1807  *
1808  * PARAMS
1809  *    hkey          [I] Open handle of key to set
1810  *    SecurityInfo  [I] Descriptor contents
1811  *    pSecurityDesc [I] Address of descriptor for key
1812  */
1813 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1814                                PSECURITY_DESCRIPTOR pSecurityDesc )
1815 {
1816     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1817
1818     /* It seems to perform this check before the hkey check */
1819     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1820         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1821         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1822         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1823         /* Param OK */
1824     } else
1825         return ERROR_INVALID_PARAMETER;
1826
1827     if (!pSecurityDesc)
1828         return ERROR_INVALID_PARAMETER;
1829
1830     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1831
1832     return ERROR_SUCCESS;
1833 }
1834
1835
1836 /******************************************************************************
1837  * RegRestoreKey32W [ADVAPI32.164]
1838  *
1839  * PARAMS
1840  *    hkey    [I] Handle of key where restore begins
1841  *    lpFile  [I] Address of filename containing saved tree
1842  *    dwFlags [I] Optional flags
1843  */
1844 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1845 {
1846     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1847
1848     /* It seems to do this check before the hkey check */
1849     if (!lpFile || !*lpFile)
1850         return ERROR_INVALID_PARAMETER;
1851
1852     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1853
1854     /* Check for file existence */
1855
1856     return ERROR_SUCCESS;
1857 }
1858
1859
1860 /******************************************************************************
1861  * RegRestoreKey32A [ADVAPI32.163]
1862  */
1863 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1864 {
1865     LONG ret;
1866     LPWSTR lpFileW = strdupA2W(lpFile);
1867     ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1868     if(lpFileW) free(lpFileW);
1869     return ret;
1870 }
1871
1872
1873 /******************************************************************************
1874  * RegReplaceKey32W [ADVAPI32.162]
1875  *
1876  * PARAMS
1877  *    hkey      [I] Handle of open key
1878  *    lpSubKey  [I] Address of name of subkey
1879  *    lpNewFile [I] Address of filename for file with new data
1880  *    lpOldFile [I] Address of filename for backup file
1881  */
1882 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1883                               LPCWSTR lpOldFile )
1884 {
1885     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
1886           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1887     return ERROR_SUCCESS;
1888 }
1889
1890
1891 /******************************************************************************
1892  * RegReplaceKey32A [ADVAPI32.161]
1893  */
1894 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1895                               LPCSTR lpOldFile )
1896 {
1897     LONG ret;
1898     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1899     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1900     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1901     ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1902     free(lpOldFileW);
1903     free(lpNewFileW);
1904     free(lpSubKeyW);
1905     return ret;
1906 }
1907
1908
1909
1910
1911
1912
1913 /* 16-bit functions */
1914
1915 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1916  * some programs. Do not remove those cases. -MM
1917  */
1918 static inline void fix_win16_hkey( HKEY *hkey )
1919 {
1920     if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1921 }
1922
1923 /******************************************************************************
1924  *           RegEnumKey16   [KERNEL.216] [SHELL.7]
1925  */
1926 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1927 {
1928     fix_win16_hkey( &hkey );
1929     return RegEnumKeyA( hkey, index, name, name_len );
1930 }
1931
1932 /******************************************************************************
1933  *           RegOpenKey16   [KERNEL.217] [SHELL.1]
1934  */
1935 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1936 {
1937     fix_win16_hkey( &hkey );
1938     return RegOpenKeyA( hkey, name, retkey );
1939 }
1940
1941 /******************************************************************************
1942  *           RegCreateKey16   [KERNEL.218] [SHELL.2]
1943  */
1944 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1945 {
1946     fix_win16_hkey( &hkey );
1947     return RegCreateKeyA( hkey, name, retkey );
1948 }
1949
1950 /******************************************************************************
1951  *           RegDeleteKey16   [KERNEL.219] [SHELL.4]
1952  */
1953 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1954 {
1955     fix_win16_hkey( &hkey );
1956     return RegDeleteKeyA( hkey, name );
1957 }
1958
1959 /******************************************************************************
1960  *           RegCloseKey16   [KERNEL.220] [SHELL.3]
1961  */
1962 DWORD WINAPI RegCloseKey16( HKEY hkey )
1963 {
1964     fix_win16_hkey( &hkey );
1965     return RegCloseKey( hkey );
1966 }
1967
1968 /******************************************************************************
1969  *           RegSetValue16   [KERNEL.221] [SHELL.5]
1970  */
1971 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1972 {
1973     fix_win16_hkey( &hkey );
1974     return RegSetValueA( hkey, name, type, data, count );
1975 }
1976
1977 /******************************************************************************
1978  *           RegDeleteValue16  [KERNEL.222]
1979  */
1980 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1981 {
1982     fix_win16_hkey( &hkey );
1983     return RegDeleteValueA( hkey, name );
1984 }
1985
1986 /******************************************************************************
1987  *           RegEnumValue16   [KERNEL.223]
1988  */
1989 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1990                              LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1991 {
1992     fix_win16_hkey( &hkey );
1993     return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1994 }
1995
1996 /******************************************************************************
1997  *           RegQueryValue16   [KERNEL.224] [SHELL.6]
1998  *
1999  * NOTES
2000  *    Is this HACK still applicable?
2001  *
2002  * HACK
2003  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2004  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
2005  *    Aldus FH4)
2006  */
2007 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2008 {
2009     fix_win16_hkey( &hkey );
2010     if (count) *count &= 0xffff;
2011     return RegQueryValueA( hkey, name, data, count );
2012 }
2013
2014 /******************************************************************************
2015  *           RegQueryValueEx16   [KERNEL.225]
2016  */
2017 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2018                                 LPBYTE data, LPDWORD count )
2019 {
2020     fix_win16_hkey( &hkey );
2021     return RegQueryValueExA( hkey, name, reserved, type, data, count );
2022 }
2023
2024 /******************************************************************************
2025  *           RegSetValueEx16   [KERNEL.226]
2026  */
2027 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2028                               CONST BYTE *data, DWORD count )
2029 {
2030     fix_win16_hkey( &hkey );
2031     return RegSetValueExA( hkey, name, reserved, type, data, count );
2032 }