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