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