Use min/max instead of MIN/MAX.
[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;
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     /* set saving level (0 for saving everything, 1 for saving only modified keys) */
353     req->current = 1;
354     req->saving  = !all;
355     req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
356     server_call( REQ_SET_REGISTRY_LEVELS );
357
358     SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
359     SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
360     SHELL_SaveRegistryBranch(HKEY_USERS);
361 }
362
363 /* Periodic save callback */
364 static void CALLBACK periodic_save( ULONG_PTR dummy )
365 {
366     SHELL_SaveRegistry();
367 }
368
369 /************************ LOAD Registry Function ****************************/
370
371
372
373 /******************************************************************************
374  * _find_or_add_key [Internal]
375  */
376 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
377 {
378     HKEY subkey;
379     if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
380     if (keyname) free( keyname );
381     return subkey;
382 }
383
384 /******************************************************************************
385  * _find_or_add_value [Internal]
386  */
387 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
388 {
389     RegSetValueExW( hkey, name, 0, type, data, len );
390     if (name) free( name );
391     if (data) free( data );
392 }
393
394
395 /******************************************************************************
396  * _wine_read_line [Internal]
397  *
398  * reads a line including dynamically enlarging the readbuffer and throwing
399  * away comments
400  */
401 static int _wine_read_line( FILE *F, char **buf, int *len )
402 {
403         char    *s,*curread;
404         int     mylen,curoff;
405
406         curread = *buf;
407         mylen   = *len;
408         **buf   = '\0';
409         while (1) {
410                 while (1) {
411                         s=fgets(curread,mylen,F);
412                         if (s==NULL)
413                                 return 0; /* EOF */
414                         if (NULL==(s=strchr(curread,'\n'))) {
415                                 /* buffer wasn't large enough */
416                                 curoff  = strlen(*buf);
417                                 curread = realloc(*buf,*len*2);
418                                 if(curread == NULL) {
419                                     WARN("Out of memory");
420                                     return 0;
421                                 }
422                                 *buf    = curread;
423                                 curread+= curoff;
424                                 mylen   = *len; /* we filled up the buffer and 
425                                                  * got new '*len' bytes to fill
426                                                  */
427                                 *len    = *len * 2;
428                         } else {
429                                 *s='\0';
430                                 break;
431                         }
432                 }
433                 /* throw away comments */
434                 if (**buf=='#' || **buf==';') {
435                         curread = *buf;
436                         mylen   = *len;
437                         continue;
438                 }
439                 if (s)  /* got end of line */
440                         break;
441         }
442         return 1;
443 }
444
445
446 /******************************************************************************
447  * _wine_read_USTRING [Internal]
448  *
449  * converts a char* into a UNICODE string (up to a special char)
450  * and returns the position exactly after that string
451  */
452 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
453 {
454         char    *s;
455         LPWSTR  ws;
456
457         /* read up to "=" or "\0" or "\n" */
458         s       = buf;
459         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
460         ws      = *str;
461         while (*s && (*s!='\n') && (*s!='=')) {
462                 if (*s!='\\')
463                         *ws++=*((unsigned char*)s++);
464                 else {
465                         s++;
466                         if (!*s) {
467                                 /* Dangling \ ... may only happen if a registry
468                                  * write was short. FIXME: What do to?
469                                  */
470                                  break;
471                         }
472                         if (*s=='\\') {
473                                 *ws++='\\';
474                                 s++;
475                                 continue;
476                         }
477                         if (*s!='u') {
478                                 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
479                                 *ws++='\\';
480                                 *ws++=*s++;
481                         } else {
482                                 char    xbuf[5];
483                                 int     wc;
484
485                                 s++;
486                                 memcpy(xbuf,s,4);xbuf[4]='\0';
487                                 if (!sscanf(xbuf,"%x",&wc))
488                                         WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
489                                 s+=4;
490                                 *ws++   =(unsigned short)wc;
491                         }
492                 }
493         }
494         *ws     = 0;
495         return s;
496 }
497
498
499 /******************************************************************************
500  * _wine_loadsubkey [Internal]
501  *
502  * NOTES
503  *    It seems like this is returning a boolean.  Should it?
504  *
505  * RETURNS
506  *    Success: 1
507  *    Failure: 0
508  */
509 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
510 {
511         HKEY subkey;
512         int             i;
513         char            *s;
514         LPWSTR          name;
515
516     TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
517
518     /* Good.  We already got a line here ... so parse it */
519     subkey = 0;
520     while (1) {
521         i=0;s=*buf;
522         while (*s=='\t') {
523             s++;
524             i++;
525         }
526         if (i>level) {
527             if (!subkey) {
528                 WARN("Got a subhierarchy without resp. key?\n");
529                 return 0;
530             }
531             if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
532                if (!_wine_read_line(F,buf,buflen))
533                   goto done;
534             continue;
535         }
536
537                 /* let the caller handle this line */
538                 if (i<level || **buf=='\0')
539                         goto done;
540
541                 /* it can be: a value or a keyname. Parse the name first */
542                 s=_wine_read_USTRING(s,&name);
543
544                 /* switch() default: hack to avoid gotos */
545                 switch (0) {
546                 default:
547                         if (*s=='\0') {
548                                 if (subkey) RegCloseKey( subkey );
549                                 subkey=_find_or_add_key(hkey,name);
550                         } else {
551                                 LPBYTE          data;
552                                 int             len,lastmodified,type;
553
554                                 if (*s!='=') {
555                                         WARN("Unexpected character: %c\n",*s);
556                                         break;
557                                 }
558                                 s++;
559                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
560                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
561                                         break;
562                                 }
563                                 /* skip the 2 , */
564                                 s=strchr(s,',');s++;
565                                 s=strchr(s,',');
566                                 if (!s++) {
567                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
568                                         break;
569                                 }
570                                 if (type == REG_SZ || type == REG_EXPAND_SZ) {
571                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
572                                         len = lstrlenW((LPWSTR)data)*2+2;
573                                 } else {
574                                         len=strlen(s)/2;
575                                         data = (LPBYTE)xmalloc(len+1);
576                                         for (i=0;i<len;i++) {
577                                                 data[i]=0;
578                                                 if (*s>='0' && *s<='9')
579                                                         data[i]=(*s-'0')<<4;
580                                                 if (*s>='a' && *s<='f')
581                                                         data[i]=(*s-'a'+'\xa')<<4;
582                                                 if (*s>='A' && *s<='F')
583                                                         data[i]=(*s-'A'+'\xa')<<4;
584                                                 s++;
585                                                 if (*s>='0' && *s<='9')
586                                                         data[i]|=*s-'0';
587                                                 if (*s>='a' && *s<='f')
588                                                         data[i]|=*s-'a'+'\xa';
589                                                 if (*s>='A' && *s<='F')
590                                                         data[i]|=*s-'A'+'\xa';
591                                                 s++;
592                                         }
593                                 }
594                                 _find_or_add_value(hkey,name,type,data,len);
595                         }
596                 }
597                 /* read the next line */
598                 if (!_wine_read_line(F,buf,buflen))
599                         goto done;
600     }
601  done:
602     if (subkey) RegCloseKey( subkey );
603     return 1;
604 }
605
606
607 /******************************************************************************
608  * _wine_loadsubreg [Internal]
609  */
610 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
611 {
612         int     ver;
613         char    *buf;
614         int     buflen;
615
616         buf=xmalloc(10);buflen=10;
617         if (!_wine_read_line(F,&buf,&buflen)) {
618                 free(buf);
619                 return 0;
620         }
621         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
622                 free(buf);
623                 return 0;
624         }
625         if (ver!=REGISTRY_SAVE_VERSION) {
626             if (ver == 2)  /* new version */
627             {
628                 HANDLE file;
629                 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
630                                              FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
631                 {
632                     struct load_registry_request *req = get_req_buffer();
633                     req->hkey    = hkey;
634                     req->file    = file;
635                     req->name[0] = 0;
636                     server_call( REQ_LOAD_REGISTRY );
637                     CloseHandle( file );
638                 }
639                 free( buf );
640                 return 1;
641             }
642             else
643             {
644                 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
645                 free(buf);
646                 return 0;
647             }
648         }
649         if (!_wine_read_line(F,&buf,&buflen)) {
650                 free(buf);
651                 return 0;
652         }
653         if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
654                 free(buf);
655                 return 0;
656         }
657         free(buf);
658         return 1;
659 }
660
661
662 /******************************************************************************
663  * _wine_loadreg [Internal]
664  */
665 static void _wine_loadreg( HKEY hkey, char *fn )
666 {
667     FILE *F;
668
669     TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
670
671     F = fopen(fn,"rb");
672     if (F==NULL) {
673         WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
674         return;
675     }
676     _wine_loadsubreg(F,hkey,fn);
677     fclose(F);
678 }
679
680 /* NT REGISTRY LOADER */
681
682 #ifdef HAVE_SYS_MMAN_H
683 # include <sys/mman.h>
684 #endif
685
686 #ifndef MAP_FAILED
687 #define MAP_FAILED ((LPVOID)-1)
688 #endif
689
690 #define  NT_REG_BLOCK_SIZE              0x1000
691
692 #define NT_REG_HEADER_BLOCK_ID       0x66676572 /* regf */
693 #define NT_REG_POOL_BLOCK_ID         0x6E696268 /* hbin */
694 #define NT_REG_KEY_BLOCK_ID          0x6b6e /* nk */
695 #define NT_REG_VALUE_BLOCK_ID        0x6b76 /* vk */
696
697 /* subblocks of nk */
698 #define NT_REG_HASH_BLOCK_ID         0x666c /* lf */
699 #define NT_REG_NOHASH_BLOCK_ID       0x696c /* li */
700 #define NT_REG_RI_BLOCK_ID           0x6972 /* ri */
701
702 #define NT_REG_KEY_BLOCK_TYPE        0x20
703 #define NT_REG_ROOT_KEY_BLOCK_TYPE   0x2c
704
705 typedef struct 
706 {
707         DWORD   id;             /* 0x66676572 'regf'*/
708         DWORD   uk1;            /* 0x04 */
709         DWORD   uk2;            /* 0x08 */
710         FILETIME        DateModified;   /* 0x0c */
711         DWORD   uk3;            /* 0x14 */
712         DWORD   uk4;            /* 0x18 */
713         DWORD   uk5;            /* 0x1c */
714         DWORD   uk6;            /* 0x20 */
715         DWORD   RootKeyBlock;   /* 0x24 */
716         DWORD   BlockSize;      /* 0x28 */
717         DWORD   uk7[116];       
718         DWORD   Checksum; /* at offset 0x1FC */
719 } nt_regf;
720
721 typedef struct
722 {
723         DWORD   blocksize;
724         BYTE    data[1];
725 } nt_hbin_sub;
726
727 typedef struct
728 {
729         DWORD   id;             /* 0x6E696268 'hbin' */
730         DWORD   off_prev;
731         DWORD   off_next;
732         DWORD   uk1;
733         DWORD   uk2;            /* 0x10 */
734         DWORD   uk3;            /* 0x14 */
735         DWORD   uk4;            /* 0x18 */
736         DWORD   size;           /* 0x1C */
737         nt_hbin_sub     hbin_sub;       /* 0x20 */
738 } nt_hbin;
739
740 /*
741  * the value_list consists of offsets to the values (vk)
742  */
743 typedef struct
744 {
745         WORD    SubBlockId;             /* 0x00 0x6B6E */
746         WORD    Type;                   /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
747         FILETIME        writetime;      /* 0x04 */
748         DWORD   uk1;                    /* 0x0C */
749         DWORD   parent_off;             /* 0x10 Offset of Owner/Parent key */
750         DWORD   nr_subkeys;             /* 0x14 number of sub-Keys */
751         DWORD   uk8;                    /* 0x18 */
752         DWORD   lf_off;                 /* 0x1C Offset of the sub-key lf-Records */
753         DWORD   uk2;                    /* 0x20 */
754         DWORD   nr_values;              /* 0x24 number of values */
755         DWORD   valuelist_off;          /* 0x28 Offset of the Value-List */
756         DWORD   off_sk;                 /* 0x2c Offset of the sk-Record */
757         DWORD   off_class;              /* 0x30 Offset of the Class-Name */
758         DWORD   uk3;                    /* 0x34 */
759         DWORD   uk4;                    /* 0x38 */
760         DWORD   uk5;                    /* 0x3c */
761         DWORD   uk6;                    /* 0x40 */
762         DWORD   uk7;                    /* 0x44 */
763         WORD    name_len;               /* 0x48 name-length */
764         WORD    class_len;              /* 0x4a class-name length */
765         char    name[1];                /* 0x4c key-name */
766 } nt_nk;
767
768 typedef struct
769 {
770         DWORD   off_nk; /* 0x00 */
771         DWORD   name;   /* 0x04 */
772 } hash_rec;
773
774 typedef struct
775 {
776         WORD    id;             /* 0x00 0x666c */
777         WORD    nr_keys;        /* 0x06 */
778         hash_rec        hash_rec[1];
779 } nt_lf;
780
781 /*
782  list of subkeys without hash
783
784  li --+-->nk
785       |
786       +-->nk
787  */
788 typedef struct
789 {
790         WORD    id;             /* 0x00 0x696c */
791         WORD    nr_keys;
792         DWORD   off_nk[1];
793 } nt_li;
794
795 /*
796  this is a intermediate node
797
798  ri --+-->li--+-->nk
799       |       +
800       |       +-->nk
801       |
802       +-->li--+-->nk
803               +
804               +-->nk
805  */
806 typedef struct
807 {
808         WORD    id;             /* 0x00 0x6972 */
809         WORD    nr_li;          /* 0x02 number off offsets */
810         DWORD   off_li[1];      /* 0x04 points to li */
811 } nt_ri;
812
813 typedef struct
814 {
815         WORD    id;             /* 0x00 'vk' */
816         WORD    nam_len;
817         DWORD   data_len;
818         DWORD   data_off;
819         DWORD   type;
820         WORD    flag;
821         WORD    uk1;
822         char    name[1];
823 } nt_vk;
824
825 LPSTR _strdupnA( LPCSTR str, int len )
826 {
827     LPSTR ret;
828
829     if (!str) return NULL;
830     ret = malloc( len + 1 );
831     lstrcpynA( ret, str, len );
832     ret[len] = 0x00;
833     return ret;
834 }
835
836 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
837 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
838 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
839
840
841 /*
842  * gets a value
843  *
844  * vk->flag:
845  *  0 value is a default value
846  *  1 the value has a name
847  *
848  * vk->data_len
849  *  len of the whole data block
850  *  - reg_sz (unicode)
851  *    bytes including the terminating \0 = 2*(number_of_chars+1)
852  *  - reg_dword, reg_binary:
853  *    if highest bit of data_len is set data_off contains the value
854  */
855 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
856 {
857         WCHAR name [256];
858         DWORD ret;
859         BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
860
861         if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
862
863         lstrcpynAtoW(name, vk->name, vk->nam_len+1);
864
865         ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
866                         (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
867                         (vk->data_len & 0x7fffffff) );
868         if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
869         return TRUE;
870 error:
871         ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
872         return FALSE;
873 }
874
875 /*
876  * get the subkeys
877  *
878  * this structure contains the hash of a keyname and points to all
879  * subkeys
880  *
881  * exception: if the id is 'il' there are no hash values and every 
882  * dword is a offset
883  */
884 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
885 {
886         int i;
887
888         if (lf->id == NT_REG_HASH_BLOCK_ID)
889         {
890           if (subkeys != lf->nr_keys) goto error1;
891
892           for (i=0; i<lf->nr_keys; i++)
893           {
894             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
895           }
896         }
897         else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
898         {
899           nt_li * li = (nt_li*)lf;
900           if (subkeys != li->nr_keys) goto error1;
901
902           for (i=0; i<li->nr_keys; i++)
903           {
904             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
905           }
906         }
907         else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
908         {
909           nt_ri * ri = (nt_ri*)lf;
910           int li_subkeys = 0;
911
912           /* count all subkeys */
913           for (i=0; i<ri->nr_li; i++)
914           {
915             nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
916             if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
917             li_subkeys += li->nr_keys;
918           }
919
920           /* check number */
921           if (subkeys != li_subkeys) goto error1;
922
923           /* loop through the keys */
924           for (i=0; i<ri->nr_li; i++)
925           {
926             nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
927             if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
928           }
929         }
930         else 
931         {
932           goto error2;
933         }
934         return TRUE;
935
936 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
937         return TRUE;
938         
939 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
940         return FALSE;
941
942 error:  ERR_(reg)("error reading lf block\n");
943         return FALSE;
944 }
945
946 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
947 {
948         char * name;
949         int i;
950         DWORD * vl;
951         HKEY subkey = hkey;
952
953         if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
954         {
955           ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
956           goto error;
957         }
958
959         if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
960            (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
961         {
962           ERR_(reg)("registry file corrupt!\n");
963           goto error;
964         }
965
966         /* create the new key */
967         if(level <= 0)
968         {
969           name = _strdupnA( nk->name, nk->name_len+1);
970           if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
971           free(name);
972         }
973
974         /* loop through the subkeys */
975         if (nk->nr_subkeys)
976         {
977           nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
978           if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
979         }
980
981         /* loop trough the value list */
982         vl = (DWORD *)(base+nk->valuelist_off+4);
983         for (i=0; i<nk->nr_values; i++)
984         {
985           nt_vk * vk = (nt_vk*)(base+vl[i]+4);
986           if (!_nt_parse_vk(subkey, base, vk)) goto error1;
987         }
988
989         RegCloseKey(subkey);
990         return TRUE;
991         
992 error1: RegCloseKey(subkey);
993 error:  return FALSE;
994 }
995
996 /* end nt loader */
997
998 /* windows 95 registry loader */
999
1000 /* SECTION 1: main header
1001  *
1002  * once at offset 0
1003  */
1004 #define W95_REG_CREG_ID 0x47455243
1005
1006 typedef struct 
1007 {
1008         DWORD   id;             /* "CREG" = W95_REG_CREG_ID */
1009         DWORD   version;        /* ???? 0x00010000 */
1010         DWORD   rgdb_off;       /* 0x08 Offset of 1st RGDB-block */
1011         DWORD   uk2;            /* 0x0c */
1012         WORD    rgdb_num;       /* 0x10 # of RGDB-blocks */
1013         WORD    uk3;
1014         DWORD   uk[3];
1015         /* rgkn */
1016 } _w95creg;
1017
1018 /* SECTION 2: Directory information (tree structure)
1019  *
1020  * once on offset 0x20
1021  *
1022  * structure: [rgkn][dke]*      (repeat till rgkn->size is reached)
1023  */
1024 #define W95_REG_RGKN_ID 0x4e4b4752
1025
1026 typedef struct
1027 {
1028         DWORD   id;             /*"RGKN" = W95_REG_RGKN_ID */
1029         DWORD   size;           /* Size of the RGKN-block */
1030         DWORD   root_off;       /* Rel. Offset of the root-record */
1031         DWORD   uk[5];
1032 } _w95rgkn;
1033
1034 /* Disk Key Entry Structure
1035  *
1036  * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
1037  * hive itself. It looks the same like other keys. Even the ID-number can
1038  * be any value.
1039  *
1040  * The "hash"-value is a value representing the key's name. Windows will not
1041  * search for the name, but for a matching hash-value. if it finds one, it
1042  * will compare the actual string info, otherwise continue with the next key.
1043  * To calculate the hash initialize a D-Word with 0 and add all ASCII-values 
1044  * of the string which are smaller than 0x80 (128) to this D-Word.   
1045  *
1046  * If you want to modify key names, also modify the hash-values, since they
1047  * cannot be found again (although they would be displayed in REGEDIT)
1048  * End of list-pointers are filled with 0xFFFFFFFF
1049  *
1050  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1051  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1052  * structure) and reading another RGDB_section.
1053  *
1054  * there is a one to one relationship between dke and dkh
1055  */
1056  /* key struct, once per key */
1057 typedef struct
1058 {
1059         DWORD   x1;             /* Free entry indicator(?) */
1060         DWORD   hash;           /* sum of bytes of keyname */
1061         DWORD   x3;             /* Root key indicator? usually 0xFFFFFFFF */
1062         DWORD   prevlvl;        /* offset of previous key */
1063         DWORD   nextsub;        /* offset of child key */
1064         DWORD   next;           /* offset of sibling key */
1065         WORD    nrLS;           /* id inside the rgdb block */
1066         WORD    nrMS;           /* number of the rgdb block */
1067 } _w95dke;
1068
1069 /* SECTION 3: key information, values and data
1070  *
1071  * structure:
1072  *  section:    [blocks]*               (repeat creg->rgdb_num times)
1073  *  blocks:     [rgdb] [subblocks]*     (repeat till block size reached )
1074  *  subblocks:  [dkh] [dkv]*            (repeat dkh->values times )
1075  *
1076  * An interesting relationship exists in RGDB_section. The value at offset
1077  * 10 equals the value at offset 4 minus the value at offset 8. I have no
1078  * idea at the moment what this means.  (Kevin Cozens)
1079  */
1080
1081 /* block header, once per block */
1082 #define W95_REG_RGDB_ID 0x42444752
1083
1084 typedef struct
1085 {
1086         DWORD   id;     /* 0x00 'rgdb' = W95_REG_RGDB_ID */
1087         DWORD   size;   /* 0x04 */
1088         DWORD   uk1;    /* 0x08 */
1089         DWORD   uk2;    /* 0x0c */
1090         DWORD   uk3;    /* 0x10 */
1091         DWORD   uk4;    /* 0x14 */
1092         DWORD   uk5;    /* 0x18 */
1093         DWORD   uk6;    /* 0x1c */
1094         /* dkh */
1095 } _w95rgdb;
1096
1097 /* Disk Key Header structure (RGDB part), once per key */
1098 typedef struct 
1099 {
1100         DWORD   nextkeyoff;     /* 0x00 offset to next dkh*/
1101         WORD    nrLS;           /* 0x04 id inside the rgdb block */
1102         WORD    nrMS;           /* 0x06 number of the rgdb block */
1103         DWORD   bytesused;      /* 0x08 */
1104         WORD    keynamelen;     /* 0x0c len of name */
1105         WORD    values;         /* 0x0e number of values */
1106         DWORD   xx1;            /* 0x10 */
1107         char    name[1];        /* 0x14 */
1108         /* dkv */               /* 0x14 + keynamelen */
1109 } _w95dkh;
1110
1111 /* Disk Key Value structure, once per value */
1112 typedef struct
1113 {
1114         DWORD   type;           /* 0x00 */
1115         DWORD   x1;             /* 0x04 */
1116         WORD    valnamelen;     /* 0x08 length of name, 0 is default key */
1117         WORD    valdatalen;     /* 0x0A length of data */
1118         char    name[1];        /* 0x0c */
1119         /* raw data */          /* 0x0c + valnamelen */
1120 } _w95dkv;
1121
1122 /******************************************************************************
1123  * _w95_lookup_dkh [Internal]
1124  *
1125  * seeks the dkh belonging to a dke
1126  */
1127 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1128 {
1129         _w95rgdb * rgdb;
1130         _w95dkh * dkh;
1131         int i;
1132         
1133         rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);         /* get the beginning of the rgdb datastore */
1134         assert (creg->rgdb_num > nrMS);                         /* check: requested block < last_block) */
1135         
1136         /* find the right block */
1137         for(i=0; i<nrMS ;i++)
1138         {
1139           assert(rgdb->id == W95_REG_RGDB_ID);                          /* check the magic */
1140           rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size);          /* find next block */
1141         }
1142
1143         dkh = (_w95dkh*)(rgdb + 1);                             /* first sub block within the rgdb */
1144
1145         do
1146         {
1147           if(nrLS==dkh->nrLS ) return dkh;
1148           dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff);       /* find next subblock */
1149         } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1150
1151         return NULL;
1152 }       
1153  
1154 /******************************************************************************
1155  * _w95_parse_dkv [Internal]
1156  */
1157 static int _w95_parse_dkv (
1158         HKEY hkey,
1159         _w95dkh * dkh,
1160         int nrLS,
1161         int nrMS )
1162 {
1163         _w95dkv * dkv;
1164         int i;
1165         DWORD ret;
1166         char * name;
1167                         
1168         /* first value block */
1169         dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1170
1171         /* loop trought the values */
1172         for (i=0; i< dkh->values; i++)
1173         {
1174           name = _strdupnA(dkv->name, dkv->valnamelen+1);
1175           ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen); 
1176           if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1177           free (name);
1178
1179           /* next value */
1180           dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1181         }
1182         return TRUE;
1183 }
1184
1185 /******************************************************************************
1186  * _w95_parse_dke [Internal]
1187  */
1188 static int _w95_parse_dke( 
1189         HKEY hkey,
1190         _w95creg * creg,
1191         _w95rgkn *rgkn,
1192         _w95dke * dke,
1193         int level )
1194 {
1195         _w95dkh * dkh;
1196         HKEY hsubkey = hkey;
1197         char * name;
1198         int ret = FALSE;
1199
1200         /* get start address of root key block */
1201         if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1202         
1203         /* special root key */
1204         if (dke->nrLS == 0xffff || dke->nrMS==0xffff)           /* eg. the root key has no name */
1205         {
1206           /* parse the one subkey*/
1207           if (dke->nextsub != 0xffffffff) 
1208           {
1209             return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1210           }
1211           /* has no sibling keys */
1212           goto error;
1213         }
1214
1215         /* search subblock */
1216         if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1217         {
1218           fprintf(stderr, "dke pointing to missing dkh !\n");
1219           goto error;
1220         }
1221
1222         if ( level <= 0 )
1223         {
1224           /* walk sibling keys */
1225           if (dke->next != 0xffffffff )
1226           {
1227             if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1228           }
1229
1230           /* create subkey and insert values */
1231           name = _strdupnA( dkh->name, dkh->keynamelen+1);
1232           if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1233           free(name);
1234           if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1235         }  
1236         
1237         /* next sub key */
1238         if (dke->nextsub != 0xffffffff) 
1239         {
1240           if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1241         }
1242
1243         ret = TRUE;
1244 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1245 error:  return ret;
1246 }
1247 /* end windows 95 loader */
1248
1249 /******************************************************************************
1250  *      NativeRegLoadKey [Internal]
1251  *
1252  * Loads a native registry file (win95/nt)
1253  *      hkey    root key
1254  *      fn      filename
1255  *      level   number of levels to cut away (eg. ".Default" in user.dat)
1256  *
1257  * this function intentionally uses unix file functions to make it possible
1258  * to move it to a seperate registry helper programm
1259  */
1260 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1261 {
1262         int fd = 0;
1263         struct stat st;
1264         DOS_FULL_NAME full_name;
1265         int ret = FALSE;
1266         void * base;
1267                         
1268         if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1269         
1270         /* map the registry into the memory */
1271         if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1272         if ((fstat(fd, &st) == -1)) goto error;
1273         if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1274
1275         switch (*(LPDWORD)base)
1276         {
1277           /* windows 95 'creg' */
1278           case W95_REG_CREG_ID:
1279             {
1280               _w95creg * creg;
1281               _w95rgkn * rgkn;
1282               creg = base;
1283               TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1284
1285               /* load the header (rgkn) */
1286               rgkn = (_w95rgkn*)(creg + 1);
1287               if (rgkn->id != W95_REG_RGKN_ID) 
1288               {
1289                 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1290                 goto error1;
1291               }
1292
1293               ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1294             }
1295             break;
1296           /* nt 'regf'*/
1297           case NT_REG_HEADER_BLOCK_ID:
1298             {
1299               nt_regf * regf;
1300               nt_hbin * hbin;
1301               nt_hbin_sub * hbin_sub;
1302               nt_nk* nk;
1303
1304               TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1305
1306               /* start block */
1307               regf = base;
1308
1309               /* hbin block */
1310               hbin = (nt_hbin *) ((char *) base + 0x1000);
1311               if (hbin->id != NT_REG_POOL_BLOCK_ID)
1312               {
1313                 ERR_(reg)( "%s hbin block invalid\n", fn);
1314                 goto error1;
1315               }
1316
1317               /* hbin_sub block */
1318               hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1319               if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1320               {
1321                 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1322                 goto error1;
1323               }
1324
1325               /* nk block */
1326               nk = (nt_nk*)&(hbin_sub->data[0]);
1327               if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1328               {
1329                 ERR_(reg)( "%s special nk block not found\n", fn);
1330                 goto error1;
1331               }
1332
1333               ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1334             }
1335             break;
1336           default:
1337             {
1338               ERR("unknown signature in registry file %s.\n",fn);
1339               goto error1;
1340             }
1341         }
1342         if(!ret) ERR("error loading registry file %s\n", fn);
1343 error1: munmap(base, st.st_size);
1344 error:  close(fd);
1345         return ret;     
1346 }
1347
1348 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1349 /*
1350     reghack - windows 3.11 registry data format demo program.
1351
1352     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1353     a combined hash table and tree description, and finally a text table.
1354
1355     The header is obvious from the struct header. The taboff1 and taboff2
1356     fields are always 0x20, and their usage is unknown.
1357
1358     The 8-byte entry table has various entry types.
1359
1360     tabent[0] is a root index. The second word has the index of the root of
1361             the directory.
1362     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1363             the index of the key/value that has that hash. Data with the same
1364             hash value are on a circular list. The other three words in the
1365             hash entry are always zero.
1366     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1367             entry: dirent and keyent/valent. They are identified by context.
1368     tabent[freeidx] is the first free entry. The first word in a free entry
1369             is the index of the next free entry. The last has 0 as a link.
1370             The other three words in the free list are probably irrelevant.
1371
1372     Entries in text table are preceeded by a word at offset-2. This word
1373     has the value (2*index)+1, where index is the referring keyent/valent
1374     entry in the table. I have no suggestion for the 2* and the +1.
1375     Following the word, there are N bytes of data, as per the keyent/valent
1376     entry length. The offset of the keyent/valent entry is from the start
1377     of the text table to the first data byte.
1378
1379     This information is not available from Microsoft. The data format is
1380     deduced from the reg.dat file by me. Mistakes may
1381     have been made. I claim no rights and give no guarantees for this program.
1382
1383     Tor Sjøwall, tor@sn.no
1384 */
1385
1386 /* reg.dat header format */
1387 struct _w31_header {
1388         char            cookie[8];      /* 'SHCC3.10' */
1389         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1390         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1391         unsigned long   tabcnt;         /* number of entries in index table */
1392         unsigned long   textoff;        /* offset of text part */
1393         unsigned long   textsize;       /* byte size of text part */
1394         unsigned short  hashsize;       /* hash size */
1395         unsigned short  freeidx;        /* free index */
1396 };
1397
1398 /* generic format of table entries */
1399 struct _w31_tabent {
1400         unsigned short w0, w1, w2, w3;
1401 };
1402
1403 /* directory tabent: */
1404 struct _w31_dirent {
1405         unsigned short  sibling_idx;    /* table index of sibling dirent */
1406         unsigned short  child_idx;      /* table index of child dirent */
1407         unsigned short  key_idx;        /* table index of key keyent */
1408         unsigned short  value_idx;      /* table index of value valent */
1409 };
1410
1411 /* key tabent: */
1412 struct _w31_keyent {
1413         unsigned short  hash_idx;       /* hash chain index for string */
1414         unsigned short  refcnt;         /* reference count */
1415         unsigned short  length;         /* length of string */
1416         unsigned short  string_off;     /* offset of string in text table */
1417 };
1418
1419 /* value tabent: */
1420 struct _w31_valent {
1421         unsigned short  hash_idx;       /* hash chain index for string */
1422         unsigned short  refcnt;         /* reference count */
1423         unsigned short  length;         /* length of string */
1424         unsigned short  string_off;     /* offset of string in text table */
1425 };
1426
1427 /* recursive helper function to display a directory tree */
1428 void
1429 __w31_dumptree( unsigned short idx,
1430                 unsigned char *txt,
1431                 struct _w31_tabent *tab,
1432                 struct _w31_header *head,
1433                 HKEY hkey,
1434                 time_t          lastmodified,
1435                 int             level
1436 ) {
1437         struct _w31_dirent      *dir;
1438         struct _w31_keyent      *key;
1439         struct _w31_valent      *val;
1440         HKEY subkey = 0;
1441         static char             tail[400];
1442
1443         while (idx!=0) {
1444                 dir=(struct _w31_dirent*)&tab[idx];
1445
1446                 if (dir->key_idx) {
1447                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1448
1449                         memcpy(tail,&txt[key->string_off],key->length);
1450                         tail[key->length]='\0';
1451                         /* all toplevel entries AND the entries in the 
1452                          * toplevel subdirectory belong to \SOFTWARE\Classes
1453                          */
1454                         if (!level && !lstrcmpA(tail,".classes")) {
1455                                 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1456                                 idx=dir->sibling_idx;
1457                                 continue;
1458                         }
1459                         if (subkey) RegCloseKey( subkey );
1460                         if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1461                         /* only add if leaf node or valued node */
1462                         if (dir->value_idx!=0||dir->child_idx==0) {
1463                                 if (dir->value_idx) {
1464                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1465                                         memcpy(tail,&txt[val->string_off],val->length);
1466                                         tail[val->length]='\0';
1467                                         RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1468                                 }
1469                         }
1470                 } else {
1471                         TRACE("strange: no directory key name, idx=%04x\n", idx);
1472                 }
1473                 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1474                 idx=dir->sibling_idx;
1475         }
1476         if (subkey) RegCloseKey( subkey );
1477 }
1478
1479
1480 /******************************************************************************
1481  * _w31_loadreg [Internal]
1482  */
1483 void _w31_loadreg(void) {
1484         HFILE                   hf;
1485         struct _w31_header      head;
1486         struct _w31_tabent      *tab;
1487         unsigned char           *txt;
1488         int                     len;
1489         OFSTRUCT                ofs;
1490         BY_HANDLE_FILE_INFORMATION hfinfo;
1491         time_t                  lastmodified;
1492
1493         TRACE("(void)\n");
1494
1495         hf = OpenFile("reg.dat",&ofs,OF_READ);
1496         if (hf==HFILE_ERROR)
1497                 return;
1498
1499         /* read & dump header */
1500         if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1501                 ERR("reg.dat is too short.\n");
1502                 _lclose(hf);
1503                 return;
1504         }
1505         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1506                 ERR("reg.dat has bad signature.\n");
1507                 _lclose(hf);
1508                 return;
1509         }
1510
1511         len = head.tabcnt * sizeof(struct _w31_tabent);
1512         /* read and dump index table */
1513         tab = xmalloc(len);
1514         if (len!=_lread(hf,tab,len)) {
1515                 ERR("couldn't read %d bytes.\n",len); 
1516                 free(tab);
1517                 _lclose(hf);
1518                 return;
1519         }
1520
1521         /* read text */
1522         txt = xmalloc(head.textsize);
1523         if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1524                 ERR("couldn't seek to textblock.\n"); 
1525                 free(tab);
1526                 free(txt);
1527                 _lclose(hf);
1528                 return;
1529         }
1530         if (head.textsize!=_lread(hf,txt,head.textsize)) {
1531                 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize); 
1532                 free(tab);
1533                 free(txt);
1534                 _lclose(hf);
1535                 return;
1536         }
1537
1538         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1539                 ERR("GetFileInformationByHandle failed?.\n"); 
1540                 free(tab);
1541                 free(txt);
1542                 _lclose(hf);
1543                 return;
1544         }
1545         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1546         __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1547         free(tab);
1548         free(txt);
1549         _lclose(hf);
1550         return;
1551 }
1552
1553 /**********************************************************************************
1554  * SetLoadLevel [Internal]
1555  *
1556  * set level to 0 for loading system files
1557  * set level to 1 for loading user files
1558  */
1559 static void SetLoadLevel(int level)
1560 {
1561         struct set_registry_levels_request *req = get_req_buffer();
1562
1563         req->current = level;
1564         req->saving  = 0;
1565         req->version = 1;
1566         server_call( REQ_SET_REGISTRY_LEVELS );
1567 }
1568
1569 /**********************************************************************************
1570  * SHELL_LoadRegistry [Internal]
1571  */
1572 #define REG_DONTLOAD -1
1573 #define REG_WIN31  0
1574 #define REG_WIN95  1
1575 #define REG_WINNT  2
1576
1577 void SHELL_LoadRegistry( void )
1578 {
1579   char  *fn, *home;
1580   HKEY  hkey;
1581   char windir[MAX_PATHNAME_LEN];
1582   char path[MAX_PATHNAME_LEN];
1583   int  systemtype = REG_WIN31;
1584
1585   TRACE("(void)\n");
1586
1587   if (!CLIENT_IsBootThread()) return;  /* already loaded */
1588
1589   REGISTRY_Init();
1590   SetLoadLevel(0);
1591
1592   GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1593
1594   if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1595   {
1596     /* test %windir%/system32/config/system --> winnt */
1597     strcpy(path, windir);
1598     strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1599     if(GetFileAttributesA(path) != -1) 
1600     {
1601       systemtype = REG_WINNT;
1602     }
1603     else
1604     {
1605        /* test %windir%/system.dat --> win95 */
1606       strcpy(path, windir);
1607       strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1608       if(GetFileAttributesA(path) != -1)
1609       {
1610         systemtype = REG_WIN95;
1611       }
1612     }
1613
1614     if ((systemtype==REG_WINNT)
1615       && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1616     {
1617        MESSAGE("When you are running with a native NT directory specify\n");
1618        MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1619        MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1620        systemtype = REG_DONTLOAD;
1621     }
1622   }
1623   else
1624   {
1625     /* only wine registry */
1626     systemtype = REG_DONTLOAD;
1627   }  
1628
1629   switch (systemtype)
1630   {
1631     case REG_WIN31:
1632       _w31_loadreg();
1633       break;
1634
1635     case REG_WIN95:  
1636       /* Load windows 95 entries */
1637       NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1638
1639       strcpy(path, windir);
1640       strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1641       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1642
1643       if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1644       {
1645         /* user specific user.dat */
1646         strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1647         if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1648         {
1649           MESSAGE("can't load win95 user-registry %s\n", path);
1650           MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1651         }
1652         /* default user.dat */
1653         if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1654         {
1655           strcpy(path, windir);
1656           strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1657           NativeRegLoadKey(hkey, path, 1);
1658           RegCloseKey(hkey);
1659         }
1660       }
1661       else
1662       {
1663         /* global user.dat */
1664         strcpy(path, windir);
1665         strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1666         NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1667       }
1668       break;
1669
1670     case REG_WINNT:  
1671       /* default user.dat */
1672       if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1673       {
1674         strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1675         if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1676         {
1677            MESSAGE("can't load NT user-registry %s\n", path);
1678            MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1679         }
1680       }
1681
1682       /* default user.dat */
1683       if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1684       {
1685         strcpy(path, windir);
1686         strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1687         NativeRegLoadKey(hkey, path, 1);
1688         RegCloseKey(hkey);
1689       }
1690
1691       /*
1692       * FIXME
1693       *  map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1694       */
1695
1696       strcpy(path, windir);
1697       strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1698       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1699
1700       strcpy(path, windir);
1701       strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1702       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1703
1704       strcpy(path, windir);
1705       strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1706       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1707
1708       strcpy(path, windir);
1709       strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1710       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1711
1712       /* this key is generated when the nt-core booted successfully */
1713       if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1714         RegCloseKey(hkey);
1715       break;
1716   } /* switch */
1717   
1718   if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1719   {
1720       /* 
1721        * Load the global HKU hive directly from sysconfdir
1722        */ 
1723       _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1724
1725       /* 
1726        * Load the global machine defaults directly form sysconfdir
1727        */
1728       _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1729   }
1730
1731   SetLoadLevel(1);
1732
1733   /*
1734    * Load the user saved registries 
1735    */
1736   if (!(home = getenv( "HOME" )))
1737       WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1738   else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1739   {
1740       /* 
1741        * Load user's personal versions of global HKU/.Default keys
1742        */
1743       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1744                          strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1745       strcpy(fn, home);
1746       strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1747       _wine_loadreg( HKEY_USERS, fn ); 
1748       free(fn);
1749
1750       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1751       strcpy(fn, home);
1752       strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1753       _wine_loadreg( HKEY_CURRENT_USER, fn );
1754       free(fn);
1755
1756       /* 
1757        * Load HKLM, attempt to get the registry location from the config 
1758        * file first, if exist, load and keep going.
1759        */
1760       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1761       strcpy(fn,home);
1762       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1763       _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1764       free(fn);
1765   }
1766   
1767   /* 
1768    * Load HKCU, get the registry location from the config 
1769    * file, if exist, load and keep going.
1770    */      
1771   if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1772   {
1773       fn = xmalloc( MAX_PATHNAME_LEN ); 
1774       if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", 
1775                                      fn, MAX_PATHNAME_LEN - 1)) 
1776        {
1777          _wine_loadreg( HKEY_CURRENT_USER, fn );
1778        }
1779       free (fn);
1780       /*
1781        * Load HKU, get the registry location from the config
1782        * file, if exist, load and keep going.
1783        */
1784       fn = xmalloc ( MAX_PATHNAME_LEN );
1785       if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1786                                       fn, MAX_PATHNAME_LEN - 1))
1787        {
1788          _wine_loadreg( HKEY_USERS, fn );
1789        }
1790       free (fn);
1791       /*
1792        * Load HKLM, get the registry location from the config
1793        * file, if exist, load and keep going.
1794        */
1795       fn = xmalloc ( MAX_PATHNAME_LEN );
1796       if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1797                                      fn, MAX_PATHNAME_LEN - 1))
1798        {
1799          _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1800        }
1801       free (fn);
1802   }
1803   
1804 }
1805
1806 /* start the periodic saving timer */
1807 void SHELL_InitRegistrySaving(void)
1808 {
1809   int   save_timeout;
1810
1811   if (!CLIENT_IsBootThread()) return;
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 }