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