Removed 2 useless include winversion.h
[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 <sys/fcntl.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36 #include <time.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/winbase16.h"
40 #include "wine/winestring.h"
41 #include "winerror.h"
42 #include "file.h"
43 #include "heap.h"
44 #include "debugtools.h"
45 #include "xmalloc.h"
46 #include "options.h"
47 #include "winreg.h"
48 #include "server.h"
49 #include "services.h"
50
51 DEFAULT_DEBUG_CHANNEL(reg)
52
53 static void REGISTRY_Init(void);
54 /* FIXME: following defines should be configured global ... */
55
56 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
57 #define WINE_PREFIX                 "/.wine"
58 #define SAVE_USERS_DEFAULT          ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT  ETCDIR"/wine.systemreg"
60
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER           "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT    "wine.userreg"
64 #define SAVE_LOCAL_MACHINE          "system.reg"
65
66 #define KEY_REGISTRY                "Software\\The WINE team\\WINE\\Registry"
67 #define VAL_SAVEUPDATED             "SaveOnlyUpdatedKeys"
68
69
70 /* what valuetypes do we need to convert? */
71 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
72
73
74
75 /*
76  * QUESTION
77  *   Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
78  *   If so, can we remove them?
79  * ANSWER
80  *   No, the memory handling functions are called very often in here, 
81  *   just replacing them by HeapAlloc(SystemHeap,...) makes registry
82  *   loading 100 times slower. -MM
83  */
84 static LPWSTR strdupA2W(LPCSTR src)
85 {
86     if(src) {
87         LPWSTR dest=xmalloc(2*strlen(src)+2);
88         lstrcpyAtoW(dest,src);
89         return dest;
90     }
91     return NULL;
92 }
93
94 LPWSTR strcvtA2W(LPCSTR src, int nchars)
95
96 {
97    LPWSTR dest = xmalloc (2 * nchars + 2);
98
99    lstrcpynAtoW(dest,src,nchars+1);
100    dest[nchars] = 0;
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 #include <sys/mman.h>
736
737 #ifndef MAP_FAILED
738 #define MAP_FAILED ((LPVOID)-1)
739 #endif
740
741 #define LONG_DUMP 1
742
743 #define  REG_BLOCK_SIZE         0x1000
744
745 #define  REG_HEADER_BLOCK_ID    0x66676572      /* regf */
746 #define  REG_POOL_BLOCK_ID      0x6E696268      /* hbin */
747 #define  REG_KEY_BLOCK_ID       0x6b6e
748 #define  REG_VALUE_BLOCK_ID     0x6b76
749 #define  REG_HASH_BLOCK_ID      0x666c
750 #define  REG_NOHASH_BLOCK_ID    0x696c
751 #define  REG_KEY_BLOCK_TYPE     0x20
752 #define  REG_ROOT_KEY_BLOCK_TYPE        0x2c
753
754 typedef struct 
755 {
756         DWORD   id;             /* 0x66676572 'regf'*/
757         DWORD   uk1;            /* 0x04 */
758         DWORD   uk2;            /* 0x08 */
759         FILETIME        DateModified;   /* 0x0c */
760         DWORD   uk3;            /* 0x14 */
761         DWORD   uk4;            /* 0x18 */
762         DWORD   uk5;            /* 0x1c */
763         DWORD   uk6;            /* 0x20 */
764         DWORD   RootKeyBlock;   /* 0x24 */
765         DWORD   BlockSize;      /* 0x28 */
766         DWORD   uk7[116];       
767         DWORD   Checksum; /* at offset 0x1FC */
768 } nt_regf;
769
770 typedef struct
771 {
772         DWORD   blocksize;
773         BYTE    data[1];
774 } nt_hbin_sub;
775
776 typedef struct
777 {
778         DWORD   id;             /* 0x6E696268 'hbin' */
779         DWORD   off_prev;
780         DWORD   off_next;
781         DWORD   uk1;
782         DWORD   uk2;            /* 0x10 */
783         DWORD   uk3;            /* 0x14 */
784         DWORD   uk4;            /* 0x18 */
785         DWORD   size;           /* 0x1C */
786         nt_hbin_sub     hbin_sub;       /* 0x20 */
787 } nt_hbin;
788
789 /*
790  * the value_list consists of offsets to the values (vk)
791  */
792 typedef struct
793 {
794         WORD    SubBlockId;             /* 0x00 0x6B6E */
795         WORD    Type;                   /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
796         FILETIME        writetime;      /* 0x04 */
797         DWORD   uk1;                    /* 0x0C */
798         DWORD   parent_off;             /* 0x10 Offset of Owner/Parent key */
799         DWORD   nr_subkeys;             /* 0x14 number of sub-Keys */
800         DWORD   uk8;                    /* 0x18 */
801         DWORD   lf_off;                 /* 0x1C Offset of the sub-key lf-Records */
802         DWORD   uk2;                    /* 0x20 */
803         DWORD   nr_values;              /* 0x24 number of values */
804         DWORD   valuelist_off;          /* 0x28 Offset of the Value-List */
805         DWORD   off_sk;                 /* 0x2c Offset of the sk-Record */
806         DWORD   off_class;              /* 0x30 Offset of the Class-Name */
807         DWORD   uk3;                    /* 0x34 */
808         DWORD   uk4;                    /* 0x38 */
809         DWORD   uk5;                    /* 0x3c */
810         DWORD   uk6;                    /* 0x40 */
811         DWORD   uk7;                    /* 0x44 */
812         WORD    name_len;               /* 0x48 name-length */
813         WORD    class_len;              /* 0x4a class-name length */
814         char    name[1];                /* 0x4c key-name */
815 } nt_nk;
816
817 typedef struct
818 {
819         DWORD   off_nk; /* 0x00 */
820         DWORD   name;   /* 0x04 */
821 } hash_rec;
822
823 typedef struct
824 {
825         WORD    id;             /* 0x00 0x666c */
826         WORD    nr_keys;        /* 0x06 */
827         hash_rec        hash_rec[1];
828 } nt_lf;
829
830 typedef struct
831 {
832         WORD    id;             /* 0x00 0x696c */
833         WORD    nr_keys;
834         DWORD   off_nk[1];
835 } nt_il;
836
837 typedef struct
838 {
839         WORD    id;             /* 0x00 'vk' */
840         WORD    nam_len;
841         DWORD   data_len;
842         DWORD   data_off;
843         DWORD   type;
844         WORD    flag;
845         WORD    uk1;
846         char    name[1];
847 } nt_vk;
848
849 #define vk_sz           0x0001
850 #define vk_expsz        0x0002
851 #define vk_bin          0x0003
852 #define vk_dword        0x0004
853 #define vk_multisz      0x0007
854 #define vk_u2           0x0008
855 #define vk_u1           0x000a
856
857 LPSTR _strdupnA( LPCSTR str, int len )
858 {
859     LPSTR ret;
860
861     if (!str) return NULL;
862     ret = malloc( len + 1 );
863     lstrcpynA( ret, str, len );
864     ret[len] = 0x00;
865     return ret;
866 }
867
868 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
869 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level);
870 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
871
872
873 /*
874  * gets a value
875  *
876  * vk->flag:
877  *  0 value is a default value
878  *  1 the value has a name
879  *
880  * vk->data_len
881  *  len of the whole data block
882  *  - reg_sz (unicode)
883  *    bytes including the terminating \0 = 2*(number_of_chars+1)
884  *  - reg_dword, reg_binary:
885  *    if highest bit of data_len is set data_off contains the value
886  */
887 int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level)
888 {
889         WCHAR name [256];
890         BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
891
892         if(vk->id != REG_VALUE_BLOCK_ID) goto error;
893
894         lstrcpynAtoW(name, vk->name, vk->nam_len+1);
895
896         if (RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
897                         (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
898                         (vk->data_len & 0x7fffffff) )) goto error;
899         return TRUE;
900 error:
901         ERR_(reg)("vk block invalid\n");
902         return FALSE;
903 }
904
905 /*
906  * get the subkeys
907  *
908  * this structure contains the hash of a keyname and points to all
909  * subkeys
910  *
911  * exception: if the id is 'il' there are no hash values and every 
912  * dword is a offset
913  */
914 int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
915 {
916         int i;
917
918         if (lf->id == REG_HASH_BLOCK_ID)
919         {
920           for (i=0; i<lf->nr_keys; i++)
921           {
922             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
923           }
924           
925         }
926         else if (lf->id == REG_NOHASH_BLOCK_ID)
927         {
928           for (i=0; i<lf->nr_keys; i++)
929           {
930             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
931           }
932         }
933         return TRUE;
934         
935 error:  ERR_(reg)("error reading lf block\n");
936         return FALSE;
937 }
938
939 int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
940 {
941         char * name;
942         int i;
943         DWORD * vl;
944         HKEY subkey;
945
946         if(nk->SubBlockId != REG_KEY_BLOCK_ID) goto error;
947         if((nk->Type!=REG_ROOT_KEY_BLOCK_TYPE) &&
948            (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != REG_KEY_BLOCK_ID)) goto error;
949
950         /* create the new key */
951         name = _strdupnA( nk->name, nk->name_len+1);
952         if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
953         free(name);
954
955         /* loop through the subkeys */
956         if (nk->nr_subkeys)
957         {
958           nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
959           if (nk->nr_subkeys != lf->nr_keys) goto error1;
960           if (!_nt_parse_lf(subkey, base, lf, level+1)) goto error1;
961         }
962
963         /* loop trough the value list */
964         vl = (DWORD *)(base+nk->valuelist_off+4);
965         for (i=0; i<nk->nr_values; i++)
966         {
967           nt_vk * vk = (nt_vk*)(base+vl[i]+4);
968           if (!_nt_parse_vk(subkey, base, vk, level+1 )) goto error1;
969         }
970
971         RegCloseKey(subkey);
972         return TRUE;
973         
974 error1: RegCloseKey(subkey);
975 error:  ERR_(reg)("error reading nk block\n");
976         return FALSE;
977 }
978
979 /*
980  * this function intentionally uses unix file functions to make it possible
981  * to move it to a seperate registry helper programm
982  */
983 static int _nt_loadreg( HKEY hkey, char* fn )
984 {
985         void * base;
986         int len, fd;
987         struct stat st;
988         nt_regf * regf;
989         nt_hbin * hbin;
990         nt_hbin_sub * hbin_sub;
991         nt_nk* nk;
992         DOS_FULL_NAME full_name;
993         
994         if (!DOSFS_GetFullName( fn, 0, &full_name ));
995
996         TRACE_(reg)("Loading NT registry database '%s' '%s'\n",fn, full_name.long_name);
997
998         if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
999         if (fstat(fd, &st ) == -1) goto error1;
1000         len = st.st_size;
1001         if ((base=mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1002
1003         /* start block */
1004         regf = base;
1005         if(regf->id != REG_HEADER_BLOCK_ID)     /* 'regf' */
1006         {
1007           ERR( "%s is not a nt-registry\n", fn);
1008           goto error;
1009         }
1010         TRACE_(reg)( "%p [regf] offset=%lx size=%lx\n", regf, regf->RootKeyBlock, regf->BlockSize);
1011         
1012         /* hbin block */
1013         hbin = base + 0x1000;
1014         if (hbin->id != REG_POOL_BLOCK_ID)
1015         {
1016           ERR_(reg)( "%s hbin block invalid\n", fn);
1017           goto error;
1018         }
1019         TRACE_(reg)( "%p [hbin]  prev=%lx next=%lx size=%lx\n", hbin, hbin->off_prev, hbin->off_next, hbin->size);
1020
1021         /* hbin_sub block */
1022         hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1023         if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1024         {
1025           ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1026           goto error;
1027         }
1028         TRACE_(reg)( "%p [hbin sub] size=%lx\n", hbin_sub, hbin_sub->blocksize);
1029                 
1030         /* nk block */
1031         nk = (nt_nk*)&(hbin_sub->data[0]);
1032         if (nk->Type != REG_ROOT_KEY_BLOCK_TYPE)
1033         {
1034           ERR_(reg)( "%s special nk block not found\n", fn);
1035           goto error;
1036         }
1037
1038         _nt_parse_nk (hkey, base+0x1000, nk, 0);
1039
1040         munmap(base, len);
1041         close(fd);
1042         return 1;
1043
1044 error:  munmap(base, len);
1045 error1: close(fd);
1046         ERR_(reg)("error reading registry file\n");
1047         return 0;
1048 }
1049 /* end nt loader */
1050
1051 /* WINDOWS 95 REGISTRY LOADER */
1052 /* 
1053  * Structure of a win95 registry database.
1054  * main header:
1055  * 0 :  "CREG"  - magic
1056  * 4 :  DWORD version
1057  * 8 :  DWORD offset_of_RGDB_part
1058  * 0C..0F:      ? (someone fill in please)
1059  * 10:  WORD    number of RGDB blocks
1060  * 12:  WORD    ?
1061  * 14:  WORD    always 0000?
1062  * 16:  WORD    always 0001?
1063  * 18..1F:      ? (someone fill in please)
1064  *
1065  * 20: RGKN_section:
1066  *   header:
1067  *      0 :             "RGKN"  - magic
1068  *      4 : DWORD       offset to first RGDB section
1069  *      8 : DWORD       offset to the root record
1070  *      C..0x1B:        ? (fill in)
1071  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1072  *
1073  *   Disk Key Entry Structure:
1074  *      00: DWORD       - Free entry indicator(?)
1075  *      04: DWORD       - Hash = sum of bytes of keyname
1076  *      08: DWORD       - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1077  *      0C: DWORD       - disk address of PreviousLevel Key.
1078  *      10: DWORD       - disk address of Next Sublevel Key.
1079  *      14: DWORD       - disk address of Next Key (on same level).
1080  * DKEP>18: WORD        - Nr, Low Significant part.
1081  *      1A: WORD        - Nr, High Significant part.
1082  *
1083  * The disk address always points to the nr part of the previous key entry 
1084  * of the referenced key. Don't ask me why, or even if I got this correct
1085  * from staring at 1kg of hexdumps. (DKEP)
1086  *
1087  * The High significant part of the structure seems to equal the number
1088  * of the RGDB section. The low significant part is a unique ID within
1089  * that RGDB section
1090  *
1091  * There are two minor corrections to the position of that structure.
1092  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
1093  *    the DKE reread from there.
1094  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1095  * CPS - I have not experienced the above phenomenon in my registry files
1096  *
1097  * RGDB_section:
1098  *      00:             "RGDB"  - magic
1099  *      04: DWORD       offset to next RGDB section
1100  *      08: DWORD       ?
1101  *      0C: WORD        always 000d?
1102  *      0E: WORD        RGDB block number
1103  *      10:     DWORD   ? (equals value at offset 4 - value at offset 8)
1104  *      14..1F:         ?
1105  *      20.....:        disk keys
1106  *
1107  * disk key:
1108  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
1109  *      08:     WORD    nrLS            - low significant part of NR
1110  *      0A:     WORD    nrHS            - high significant part of NR
1111  *      0C:     DWORD   bytesused       - bytes used in this structure.
1112  *      10:     WORD    name_len        - length of name in bytes. without \0
1113  *      12:     WORD    nr_of_values    - number of values.
1114  *      14:     char    name[name_len]  - name string. No \0.
1115  *      14+name_len: disk values
1116  *      nextkeyoffset: ... next disk key
1117  *
1118  * disk value:
1119  *      00:     DWORD   type            - value type (hmm, could be WORD too)
1120  *      04:     DWORD                   - unknown, usually 0
1121  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
1122  *      0C:     WORD    datalen         - length of Data.
1123  *      10:     char    name[namelen]   - name, no \0
1124  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
1125  *      10+namelen+datalen: next values or disk key
1126  *
1127  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1128  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1129  * structure) and reading another RGDB_section.
1130  * repeat until end of file.
1131  *
1132  * An interesting relationship exists in RGDB_section. The value at offset
1133  * 10 equals the value at offset 4 minus the value at offset 8. I have no
1134  * idea at the moment what this means.  (Kevin Cozens)
1135  *
1136  * FIXME: this description needs some serious help, yes.
1137  */
1138
1139 struct  _w95keyvalue {
1140         unsigned long           type;
1141         unsigned short          datalen;
1142         char                    *name;
1143         unsigned char           *data;
1144         unsigned long           x1;
1145         int                     lastmodified;
1146 };
1147
1148 struct  _w95key {
1149         char                    *name;
1150         int                     nrofvals;
1151         struct  _w95keyvalue    *values;
1152         struct _w95key          *prevlvl;
1153         struct _w95key          *nextsub;
1154         struct _w95key          *next;
1155 };
1156
1157
1158 struct _w95_info {
1159   char *rgknbuffer;
1160   int  rgknsize;
1161   char *rgdbbuffer;
1162   int  rgdbsize;
1163   int  depth;
1164   int  lastmodified;
1165 };
1166
1167
1168 /******************************************************************************
1169  * _w95_processKey [Internal]
1170  */
1171 static HKEY _w95_processKey ( HKEY hkey, int nrLS, int nrMS, struct _w95_info *info )
1172
1173 {
1174   /* Disk Key Header structure (RGDB part) */
1175         struct  dkh {
1176                 unsigned long           nextkeyoff; 
1177                 unsigned short          nrLS;
1178                 unsigned short          nrMS;
1179                 unsigned long           bytesused;
1180                 unsigned short          keynamelen;
1181                 unsigned short          values;
1182                 unsigned long           xx1;
1183                 /* keyname */
1184                 /* disk key values or nothing */
1185         };
1186         /* Disk Key Value structure */
1187         struct  dkv {
1188                 unsigned long           type;
1189                 unsigned long           x1;
1190                 unsigned short          valnamelen;
1191                 unsigned short          valdatalen;
1192                 /* valname, valdata */
1193         };
1194
1195         
1196         struct  dkh dkh;
1197         int     bytesread = 0;
1198         char    *rgdbdata = info->rgdbbuffer;
1199         int     nbytes = info->rgdbsize;
1200         char    *curdata = rgdbdata;
1201         char    *end = rgdbdata + nbytes;
1202         int     off_next_rgdb;
1203         char    *next = rgdbdata;
1204         int     nrgdb, i;
1205         HKEY subkey;
1206         
1207         do {
1208           curdata = next;
1209           if (strncmp(curdata, "RGDB", 4)) return 0;
1210             
1211           memcpy(&off_next_rgdb,curdata+4,4);
1212           next = curdata + off_next_rgdb;
1213           nrgdb = (int) *((short *)curdata + 7);
1214
1215         } while (nrgdb != nrMS && (next < end));
1216
1217         /* curdata now points to the start of the right RGDB section */
1218         curdata += 0x20;
1219
1220 #define XREAD(whereto,len) \
1221         if ((curdata + len) <= end) {\
1222                 memcpy(whereto,curdata,len);\
1223                 curdata+=len;\
1224                 bytesread+=len;\
1225         }
1226
1227         while (curdata < next) {
1228           struct        dkh *xdkh = (struct dkh*)curdata;
1229
1230           bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1231           if (xdkh->nrLS == nrLS) {
1232                 memcpy(&dkh,xdkh,sizeof(dkh));
1233                 curdata += sizeof(dkh);
1234                 break;
1235           }
1236           curdata += xdkh->nextkeyoff;
1237         };
1238
1239         if (dkh.nrLS != nrLS) return 0;
1240
1241         if (nrgdb != dkh.nrMS)
1242           return 0;
1243
1244         assert((dkh.keynamelen<2) || curdata[0]);
1245         subkey=_find_or_add_key(hkey,strcvtA2W(curdata, dkh.keynamelen));
1246         curdata += dkh.keynamelen;
1247
1248         for (i=0;i< dkh.values; i++) {
1249           struct dkv dkv;
1250           LPBYTE data;
1251           int len;
1252           LPWSTR name;
1253
1254           XREAD(&dkv,sizeof(dkv));
1255
1256           name = strcvtA2W(curdata, dkv.valnamelen);
1257           curdata += dkv.valnamelen;
1258
1259           if ((1 << dkv.type) & UNICONVMASK) {
1260             data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1261             len = 2*(dkv.valdatalen + 1);
1262           } else {
1263             /* I don't think we want to NULL terminate all data */
1264             data = xmalloc(dkv.valdatalen);
1265             memcpy (data, curdata, dkv.valdatalen);
1266             len = dkv.valdatalen;
1267           }
1268
1269           curdata += dkv.valdatalen;
1270           
1271           _find_or_add_value( subkey, name, dkv.type, data, len );
1272         }
1273         return subkey;
1274 }
1275
1276 /******************************************************************************
1277  * _w95_walkrgkn [Internal]
1278  */
1279 static void _w95_walkrgkn( HKEY prevkey, char *off, 
1280                            struct _w95_info *info )
1281
1282 {
1283   /* Disk Key Entry structure (RGKN part) */
1284   struct        dke {
1285     unsigned long               x1;
1286     unsigned long               x2;
1287     unsigned long               x3;/*usually 0xFFFFFFFF */
1288     unsigned long               prevlvl;
1289     unsigned long               nextsub;
1290     unsigned long               next;
1291     unsigned short              nrLS;
1292     unsigned short              nrMS;
1293   } *dke = (struct dke *)off;
1294   HKEY subkey;
1295
1296   if (dke == NULL) {
1297     dke = (struct dke *) ((char *)info->rgknbuffer);
1298   }
1299
1300   subkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1301
1302   if (dke->nextsub != -1 && 
1303       ((dke->nextsub - 0x20) < info->rgknsize) 
1304       && (dke->nextsub > 0x20)) {
1305     
1306     _w95_walkrgkn(subkey ? subkey : prevkey, /* XXX <-- This is a hack*/
1307                   info->rgknbuffer + dke->nextsub - 0x20, 
1308                   info);
1309   }
1310   if (subkey) RegCloseKey( subkey );
1311
1312   if (dke->next != -1 && 
1313       ((dke->next - 0x20) < info->rgknsize) && 
1314       (dke->next > 0x20)) {
1315     _w95_walkrgkn(prevkey,  
1316                   info->rgknbuffer + dke->next - 0x20,
1317                   info);
1318   }
1319 }
1320
1321
1322 /******************************************************************************
1323  * _w95_loadreg [Internal]
1324  */
1325 static void _w95_loadreg( char* fn, HKEY hkey )
1326 {
1327         HFILE           hfd;
1328         char            magic[5];
1329         unsigned long   where,version,rgdbsection,end;
1330         struct          _w95_info info;
1331         OFSTRUCT        ofs;
1332         BY_HANDLE_FILE_INFORMATION hfdinfo;
1333
1334         TRACE("Loading Win95 registry database '%s'\n",fn);
1335         hfd=OpenFile(fn,&ofs,OF_READ);
1336         if (hfd==HFILE_ERROR)
1337                 return;
1338         magic[4]=0;
1339         if (4!=_lread(hfd,magic,4))
1340                 return;
1341         if (strcmp(magic,"CREG")) {
1342                 WARN("%s is not a w95 registry.\n",fn);
1343                 return;
1344         }
1345         if (4!=_lread(hfd,&version,4))
1346                 return;
1347         if (4!=_lread(hfd,&rgdbsection,4))
1348                 return;
1349         if (-1==_llseek(hfd,0x20,SEEK_SET))
1350                 return;
1351         if (4!=_lread(hfd,magic,4))
1352                 return;
1353         if (strcmp(magic,"RGKN")) {
1354                 WARN("second IFF header not RGKN, but %s\n", magic);
1355                 return;
1356         }
1357
1358         /* STEP 1: Keylink structures */
1359         if (-1==_llseek(hfd,0x40,SEEK_SET))
1360                 return;
1361         where   = 0x40;
1362         end     = rgdbsection;
1363
1364         info.rgknsize = end - where;
1365         info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1366         if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1367                 return;
1368
1369         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1370                 return;
1371
1372         end = hfdinfo.nFileSizeLow;
1373         info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1374
1375         if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1376                 return;
1377
1378         info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1379         info.rgdbsize = end - rgdbsection;
1380
1381         if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1382                 return;
1383         _lclose(hfd);
1384
1385         _w95_walkrgkn(hkey, NULL, &info);
1386
1387         free (info.rgdbbuffer);
1388         free (info.rgknbuffer);
1389 }
1390
1391
1392 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1393
1394 /*
1395     reghack - windows 3.11 registry data format demo program.
1396
1397     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1398     a combined hash table and tree description, and finally a text table.
1399
1400     The header is obvious from the struct header. The taboff1 and taboff2
1401     fields are always 0x20, and their usage is unknown.
1402
1403     The 8-byte entry table has various entry types.
1404
1405     tabent[0] is a root index. The second word has the index of the root of
1406             the directory.
1407     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1408             the index of the key/value that has that hash. Data with the same
1409             hash value are on a circular list. The other three words in the
1410             hash entry are always zero.
1411     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1412             entry: dirent and keyent/valent. They are identified by context.
1413     tabent[freeidx] is the first free entry. The first word in a free entry
1414             is the index of the next free entry. The last has 0 as a link.
1415             The other three words in the free list are probably irrelevant.
1416
1417     Entries in text table are preceeded by a word at offset-2. This word
1418     has the value (2*index)+1, where index is the referring keyent/valent
1419     entry in the table. I have no suggestion for the 2* and the +1.
1420     Following the word, there are N bytes of data, as per the keyent/valent
1421     entry length. The offset of the keyent/valent entry is from the start
1422     of the text table to the first data byte.
1423
1424     This information is not available from Microsoft. The data format is
1425     deduced from the reg.dat file by me. Mistakes may
1426     have been made. I claim no rights and give no guarantees for this program.
1427
1428     Tor Sjøwall, tor@sn.no
1429 */
1430
1431 /* reg.dat header format */
1432 struct _w31_header {
1433         char            cookie[8];      /* 'SHCC3.10' */
1434         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1435         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1436         unsigned long   tabcnt;         /* number of entries in index table */
1437         unsigned long   textoff;        /* offset of text part */
1438         unsigned long   textsize;       /* byte size of text part */
1439         unsigned short  hashsize;       /* hash size */
1440         unsigned short  freeidx;        /* free index */
1441 };
1442
1443 /* generic format of table entries */
1444 struct _w31_tabent {
1445         unsigned short w0, w1, w2, w3;
1446 };
1447
1448 /* directory tabent: */
1449 struct _w31_dirent {
1450         unsigned short  sibling_idx;    /* table index of sibling dirent */
1451         unsigned short  child_idx;      /* table index of child dirent */
1452         unsigned short  key_idx;        /* table index of key keyent */
1453         unsigned short  value_idx;      /* table index of value valent */
1454 };
1455
1456 /* key tabent: */
1457 struct _w31_keyent {
1458         unsigned short  hash_idx;       /* hash chain index for string */
1459         unsigned short  refcnt;         /* reference count */
1460         unsigned short  length;         /* length of string */
1461         unsigned short  string_off;     /* offset of string in text table */
1462 };
1463
1464 /* value tabent: */
1465 struct _w31_valent {
1466         unsigned short  hash_idx;       /* hash chain index for string */
1467         unsigned short  refcnt;         /* reference count */
1468         unsigned short  length;         /* length of string */
1469         unsigned short  string_off;     /* offset of string in text table */
1470 };
1471
1472 /* recursive helper function to display a directory tree */
1473 void
1474 __w31_dumptree( unsigned short idx,
1475                 unsigned char *txt,
1476                 struct _w31_tabent *tab,
1477                 struct _w31_header *head,
1478                 HKEY hkey,
1479                 time_t          lastmodified,
1480                 int             level
1481 ) {
1482         struct _w31_dirent      *dir;
1483         struct _w31_keyent      *key;
1484         struct _w31_valent      *val;
1485         HKEY subkey = 0;
1486         static char             tail[400];
1487
1488         while (idx!=0) {
1489                 dir=(struct _w31_dirent*)&tab[idx];
1490
1491                 if (dir->key_idx) {
1492                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1493
1494                         memcpy(tail,&txt[key->string_off],key->length);
1495                         tail[key->length]='\0';
1496                         /* all toplevel entries AND the entries in the 
1497                          * toplevel subdirectory belong to \SOFTWARE\Classes
1498                          */
1499                         if (!level && !lstrcmpA(tail,".classes")) {
1500                                 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1501                                 idx=dir->sibling_idx;
1502                                 continue;
1503                         }
1504                         if (subkey) RegCloseKey( subkey );
1505                         if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1506                         /* only add if leaf node or valued node */
1507                         if (dir->value_idx!=0||dir->child_idx==0) {
1508                                 if (dir->value_idx) {
1509                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1510                                         memcpy(tail,&txt[val->string_off],val->length);
1511                                         tail[val->length]='\0';
1512                                         RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1513                                 }
1514                         }
1515                 } else {
1516                         TRACE("strange: no directory key name, idx=%04x\n", idx);
1517                 }
1518                 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1519                 idx=dir->sibling_idx;
1520         }
1521         if (subkey) RegCloseKey( subkey );
1522 }
1523
1524
1525 /******************************************************************************
1526  * _w31_loadreg [Internal]
1527  */
1528 void _w31_loadreg(void) {
1529         HFILE                   hf;
1530         struct _w31_header      head;
1531         struct _w31_tabent      *tab;
1532         unsigned char           *txt;
1533         int                     len;
1534         OFSTRUCT                ofs;
1535         BY_HANDLE_FILE_INFORMATION hfinfo;
1536         time_t                  lastmodified;
1537
1538         TRACE("(void)\n");
1539
1540         hf = OpenFile("reg.dat",&ofs,OF_READ);
1541         if (hf==HFILE_ERROR)
1542                 return;
1543
1544         /* read & dump header */
1545         if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1546                 ERR("reg.dat is too short.\n");
1547                 _lclose(hf);
1548                 return;
1549         }
1550         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1551                 ERR("reg.dat has bad signature.\n");
1552                 _lclose(hf);
1553                 return;
1554         }
1555
1556         len = head.tabcnt * sizeof(struct _w31_tabent);
1557         /* read and dump index table */
1558         tab = xmalloc(len);
1559         if (len!=_lread(hf,tab,len)) {
1560                 ERR("couldn't read %d bytes.\n",len); 
1561                 free(tab);
1562                 _lclose(hf);
1563                 return;
1564         }
1565
1566         /* read text */
1567         txt = xmalloc(head.textsize);
1568         if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1569                 ERR("couldn't seek to textblock.\n"); 
1570                 free(tab);
1571                 free(txt);
1572                 _lclose(hf);
1573                 return;
1574         }
1575         if (head.textsize!=_lread(hf,txt,head.textsize)) {
1576                 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize); 
1577                 free(tab);
1578                 free(txt);
1579                 _lclose(hf);
1580                 return;
1581         }
1582
1583         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1584                 ERR("GetFileInformationByHandle failed?.\n"); 
1585                 free(tab);
1586                 free(txt);
1587                 _lclose(hf);
1588                 return;
1589         }
1590         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1591         __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1592         free(tab);
1593         free(txt);
1594         _lclose(hf);
1595         return;
1596 }
1597
1598
1599 /**********************************************************************************
1600  * SHELL_LoadRegistry [Internal]
1601  */
1602 void SHELL_LoadRegistry( void )
1603 {
1604   struct set_registry_levels_request *req = get_req_buffer();
1605   int save_timeout;
1606   char        *fn, *home;
1607   HKEY              hkey;
1608
1609   TRACE("(void)\n");
1610
1611   REGISTRY_Init();
1612
1613   /* set level to 0 for loading system files */
1614   req->current = 0;
1615   req->saving  = 0;
1616   req->version = 1;
1617   server_call( REQ_SET_REGISTRY_LEVELS );
1618
1619   if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1)) 
1620   { 
1621       /* Load windows 3.1 entries */
1622       _w31_loadreg();
1623   }
1624   if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1)) 
1625   { 
1626       /* Load windows 95 entries */
1627       _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE);
1628       _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE);
1629       _w95_loadreg("user.dat", HKEY_USERS);
1630   }
1631   if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1)) 
1632   { 
1633       fn = xmalloc( MAX_PATHNAME_LEN ); 
1634       home = xmalloc ( MAX_PATHNAME_LEN );
1635       if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1)) 
1636       {
1637          GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1638          strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1639          strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1640          strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
1641          _nt_loadreg( HKEY_USERS, fn );
1642       }     
1643       /*
1644       * FIXME
1645       *  map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1646       */
1647       GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1648
1649       strcpy(home, fn);
1650       strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
1651       _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1652
1653       strcpy(home, fn);
1654       strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
1655       _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1656
1657       strcpy(home, fn);
1658       strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
1659       _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1660
1661       strcpy(home, fn);
1662       strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
1663       _nt_loadreg(HKEY_LOCAL_MACHINE, home);
1664
1665       free (home);
1666       free (fn);
1667   }
1668
1669   if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1670   {
1671       /* 
1672        * Load the global HKU hive directly from sysconfdir
1673        */ 
1674       _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1675
1676       /* 
1677        * Load the global machine defaults directly form sysconfdir
1678        */
1679       _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1680   }
1681
1682   /* set level to 1 for loading user files */
1683   req->current = 1;
1684   req->saving  = 0;
1685   req->version = 1;
1686   server_call( REQ_SET_REGISTRY_LEVELS );
1687
1688   /*
1689    * Load the user saved registries 
1690    */
1691   if (!(home = getenv( "HOME" )))
1692       WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1693   else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1694   {
1695       /* 
1696        * Load user's personal versions of global HKU/.Default keys
1697        */
1698       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1699                          strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1700       strcpy(fn, home);
1701       strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1702       _wine_loadreg( HKEY_USERS, fn ); 
1703       free(fn);
1704
1705       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1706       strcpy(fn, home);
1707       strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1708       _wine_loadreg( HKEY_CURRENT_USER, fn );
1709       free(fn);
1710
1711       /* 
1712        * Load HKLM, attempt to get the registry location from the config 
1713        * file first, if exist, load and keep going.
1714        */
1715       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1716       strcpy(fn,home);
1717       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1718       _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1719       free(fn);
1720   }
1721   
1722   /* 
1723    * Load HKCU, get the registry location from the config 
1724    * file, if exist, load and keep going.
1725    */      
1726   if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1727   {
1728       fn = xmalloc( MAX_PATHNAME_LEN ); 
1729       if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", 
1730                                      fn, MAX_PATHNAME_LEN - 1)) 
1731        {
1732          _wine_loadreg( HKEY_CURRENT_USER, fn );
1733        }
1734       free (fn);
1735       /*
1736        * Load HKU, get the registry location from the config
1737        * file, if exist, load and keep going.
1738        */
1739       fn = xmalloc ( MAX_PATHNAME_LEN );
1740       if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1741                                       fn, MAX_PATHNAME_LEN - 1))
1742        {
1743          _wine_loadreg( HKEY_USERS, fn );
1744        }
1745       free (fn);
1746       /*
1747        * Load HKLM, get the registry location from the config
1748        * file, if exist, load and keep going.
1749        */
1750       fn = xmalloc ( MAX_PATHNAME_LEN );
1751       if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1752                                      fn, MAX_PATHNAME_LEN - 1))
1753        {
1754          _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1755        }
1756       free (fn);
1757     }
1758   
1759   /* 
1760    * Obtain the handle of the HKU\.Default key.
1761    * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER 
1762    */
1763   if (RegCreateKeyA(HKEY_USERS,".Default",&hkey) != ERROR_SUCCESS)
1764       WARN("Could not create global user default key\n");
1765   else
1766     _copy_registry( hkey, HKEY_CURRENT_USER );
1767   RegCloseKey(hkey);
1768
1769   /* 
1770    * Since HKU is built from the global HKU and the local user HKU file we must
1771    * flush the HKU tree we have built at this point otherwise the part brought
1772    * in from the global HKU is saved into the local HKU.  To avoid this 
1773    * useless dupplication of HKU keys we reread the local HKU key.
1774    */
1775
1776   /* Allways flush the HKU hive and reload it only with user's personal HKU */
1777   _flush_registry( HKEY_USERS ); 
1778
1779   /* Reload user's local HKU hive */
1780   if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
1781   {
1782       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1783                          + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
1784       
1785       strcpy(fn,home);
1786       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1787
1788       _wine_loadreg( HKEY_USERS, fn );
1789
1790       free(fn);
1791   }
1792
1793   /* 
1794    * Make sure the update mode is there
1795    */
1796   if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) 
1797   {
1798     DWORD       junk,type,len;
1799     char        data[5];
1800
1801     len=4;
1802     if ((       RegQueryValueExA(
1803             hkey,
1804             VAL_SAVEUPDATED,
1805             &junk,
1806             &type,
1807             data,
1808             &len) != ERROR_SUCCESS) || (type != REG_SZ))
1809     {
1810       RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1811     }
1812
1813     RegCloseKey(hkey);
1814   }
1815
1816   if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1817   {
1818       SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1819   }
1820 }
1821
1822
1823 /********************* API FUNCTIONS ***************************************/
1824
1825
1826
1827
1828 /******************************************************************************
1829  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1830  * Immediately writes key to registry.
1831  * Only returns after data has been written to disk.
1832  *
1833  * FIXME: does it really wait until data is written ?
1834  *
1835  * PARAMS
1836  *    hkey [I] Handle of key to write
1837  *
1838  * RETURNS
1839  *    Success: ERROR_SUCCESS
1840  *    Failure: Error code
1841  */
1842 DWORD WINAPI RegFlushKey( HKEY hkey )
1843 {
1844     FIXME( "(%x): stub\n", hkey );
1845     return ERROR_SUCCESS;
1846 }
1847
1848 /******************************************************************************
1849  * RegConnectRegistry32W [ADVAPI32.128]
1850  *
1851  * PARAMS
1852  *    lpMachineName [I] Address of name of remote computer
1853  *    hHey          [I] Predefined registry handle
1854  *    phkResult     [I] Address of buffer for remote registry handle
1855  */
1856 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
1857                                    LPHKEY phkResult )
1858 {
1859     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1860
1861     if (!lpMachineName || !*lpMachineName) {
1862         /* Use the local machine name */
1863         return RegOpenKey16( hKey, "", phkResult );
1864     }
1865
1866     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1867     return ERROR_BAD_NETPATH;
1868 }
1869
1870
1871 /******************************************************************************
1872  * RegConnectRegistry32A [ADVAPI32.127]
1873  */
1874 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1875 {
1876     DWORD ret;
1877     LPWSTR machineW = strdupA2W(machine);
1878     ret = RegConnectRegistryW( machineW, hkey, reskey );
1879     free(machineW);
1880     return ret;
1881 }
1882
1883
1884 /******************************************************************************
1885  * RegGetKeySecurity [ADVAPI32.144]
1886  * Retrieves a copy of security descriptor protecting the registry key
1887  *
1888  * PARAMS
1889  *    hkey                   [I]   Open handle of key to set
1890  *    SecurityInformation    [I]   Descriptor contents
1891  *    pSecurityDescriptor    [O]   Address of descriptor for key
1892  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1893  *
1894  * RETURNS
1895  *    Success: ERROR_SUCCESS
1896  *    Failure: Error code
1897  */
1898 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
1899                                SECURITY_INFORMATION SecurityInformation,
1900                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1901                                LPDWORD lpcbSecurityDescriptor )
1902 {
1903     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1904           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1905
1906     /* FIXME: Check for valid SecurityInformation values */
1907
1908     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1909         return ERROR_INSUFFICIENT_BUFFER;
1910
1911     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1912           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1913
1914     return ERROR_SUCCESS;
1915 }
1916
1917
1918 /******************************************************************************
1919  * RegNotifyChangeKeyValue [ADVAPI32.???]
1920  *
1921  * PARAMS
1922  *    hkey            [I] Handle of key to watch
1923  *    fWatchSubTree   [I] Flag for subkey notification
1924  *    fdwNotifyFilter [I] Changes to be reported
1925  *    hEvent          [I] Handle of signaled event
1926  *    fAsync          [I] Flag for asynchronous reporting
1927  */
1928 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
1929                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1930                                      BOOL fAsync )
1931 {
1932     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1933           hEvent,fAsync);
1934     return ERROR_SUCCESS;
1935 }
1936
1937
1938 /******************************************************************************
1939  * RegUnLoadKey32W [ADVAPI32.173]
1940  *
1941  * PARAMS
1942  *    hkey     [I] Handle of open key
1943  *    lpSubKey [I] Address of name of subkey to unload
1944  */
1945 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1946 {
1947     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1948     return ERROR_SUCCESS;
1949 }
1950
1951
1952 /******************************************************************************
1953  * RegUnLoadKey32A [ADVAPI32.172]
1954  */
1955 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1956 {
1957     LONG ret;
1958     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1959     ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1960     if(lpSubKeyW) free(lpSubKeyW);
1961     return ret;
1962 }
1963
1964
1965 /******************************************************************************
1966  * RegSetKeySecurity [ADVAPI32.167]
1967  *
1968  * PARAMS
1969  *    hkey          [I] Open handle of key to set
1970  *    SecurityInfo  [I] Descriptor contents
1971  *    pSecurityDesc [I] Address of descriptor for key
1972  */
1973 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1974                                PSECURITY_DESCRIPTOR pSecurityDesc )
1975 {
1976     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1977
1978     /* It seems to perform this check before the hkey check */
1979     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1980         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1981         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1982         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1983         /* Param OK */
1984     } else
1985         return ERROR_INVALID_PARAMETER;
1986
1987     if (!pSecurityDesc)
1988         return ERROR_INVALID_PARAMETER;
1989
1990     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1991
1992     return ERROR_SUCCESS;
1993 }
1994
1995
1996 /******************************************************************************
1997  * RegRestoreKey32W [ADVAPI32.164]
1998  *
1999  * PARAMS
2000  *    hkey    [I] Handle of key where restore begins
2001  *    lpFile  [I] Address of filename containing saved tree
2002  *    dwFlags [I] Optional flags
2003  */
2004 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2005 {
2006     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2007
2008     /* It seems to do this check before the hkey check */
2009     if (!lpFile || !*lpFile)
2010         return ERROR_INVALID_PARAMETER;
2011
2012     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2013
2014     /* Check for file existence */
2015
2016     return ERROR_SUCCESS;
2017 }
2018
2019
2020 /******************************************************************************
2021  * RegRestoreKey32A [ADVAPI32.163]
2022  */
2023 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2024 {
2025     LONG ret;
2026     LPWSTR lpFileW = strdupA2W(lpFile);
2027     ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
2028     if(lpFileW) free(lpFileW);
2029     return ret;
2030 }
2031
2032
2033 /******************************************************************************
2034  * RegReplaceKey32W [ADVAPI32.162]
2035  *
2036  * PARAMS
2037  *    hkey      [I] Handle of open key
2038  *    lpSubKey  [I] Address of name of subkey
2039  *    lpNewFile [I] Address of filename for file with new data
2040  *    lpOldFile [I] Address of filename for backup file
2041  */
2042 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2043                               LPCWSTR lpOldFile )
2044 {
2045     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
2046           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2047     return ERROR_SUCCESS;
2048 }
2049
2050
2051 /******************************************************************************
2052  * RegReplaceKey32A [ADVAPI32.161]
2053  */
2054 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2055                               LPCSTR lpOldFile )
2056 {
2057     LONG ret;
2058     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
2059     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
2060     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
2061     ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
2062     free(lpOldFileW);
2063     free(lpNewFileW);
2064     free(lpSubKeyW);
2065     return ret;
2066 }
2067
2068
2069
2070
2071
2072
2073 /* 16-bit functions */
2074
2075 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
2076  * some programs. Do not remove those cases. -MM
2077  */
2078 static inline void fix_win16_hkey( HKEY *hkey )
2079 {
2080     if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
2081 }
2082
2083 /******************************************************************************
2084  *           RegEnumKey16   [KERNEL.216] [SHELL.7]
2085  */
2086 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2087 {
2088     fix_win16_hkey( &hkey );
2089     return RegEnumKeyA( hkey, index, name, name_len );
2090 }
2091
2092 /******************************************************************************
2093  *           RegOpenKey16   [KERNEL.217] [SHELL.1]
2094  */
2095 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2096 {
2097     fix_win16_hkey( &hkey );
2098     return RegOpenKeyA( hkey, name, retkey );
2099 }
2100
2101 /******************************************************************************
2102  *           RegCreateKey16   [KERNEL.218] [SHELL.2]
2103  */
2104 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2105 {
2106     fix_win16_hkey( &hkey );
2107     return RegCreateKeyA( hkey, name, retkey );
2108 }
2109
2110 /******************************************************************************
2111  *           RegDeleteKey16   [KERNEL.219] [SHELL.4]
2112  */
2113 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2114 {
2115     fix_win16_hkey( &hkey );
2116     return RegDeleteKeyA( hkey, name );
2117 }
2118
2119 /******************************************************************************
2120  *           RegCloseKey16   [KERNEL.220] [SHELL.3]
2121  */
2122 DWORD WINAPI RegCloseKey16( HKEY hkey )
2123 {
2124     fix_win16_hkey( &hkey );
2125     return RegCloseKey( hkey );
2126 }
2127
2128 /******************************************************************************
2129  *           RegSetValue16   [KERNEL.221] [SHELL.5]
2130  */
2131 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2132 {
2133     fix_win16_hkey( &hkey );
2134     return RegSetValueA( hkey, name, type, data, count );
2135 }
2136
2137 /******************************************************************************
2138  *           RegDeleteValue16  [KERNEL.222]
2139  */
2140 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2141 {
2142     fix_win16_hkey( &hkey );
2143     return RegDeleteValueA( hkey, name );
2144 }
2145
2146 /******************************************************************************
2147  *           RegEnumValue16   [KERNEL.223]
2148  */
2149 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2150                              LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2151 {
2152     fix_win16_hkey( &hkey );
2153     return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2154 }
2155
2156 /******************************************************************************
2157  *           RegQueryValue16   [KERNEL.224] [SHELL.6]
2158  *
2159  * NOTES
2160  *    Is this HACK still applicable?
2161  *
2162  * HACK
2163  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2164  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
2165  *    Aldus FH4)
2166  */
2167 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2168 {
2169     fix_win16_hkey( &hkey );
2170     if (count) *count &= 0xffff;
2171     return RegQueryValueA( hkey, name, data, count );
2172 }
2173
2174 /******************************************************************************
2175  *           RegQueryValueEx16   [KERNEL.225]
2176  */
2177 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2178                                 LPBYTE data, LPDWORD count )
2179 {
2180     fix_win16_hkey( &hkey );
2181     return RegQueryValueExA( hkey, name, reserved, type, data, count );
2182 }
2183
2184 /******************************************************************************
2185  *           RegSetValueEx16   [KERNEL.226]
2186  */
2187 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2188                               CONST BYTE *data, DWORD count )
2189 {
2190     fix_win16_hkey( &hkey );
2191     return RegSetValueExA( hkey, name, reserved, type, data, count );
2192 }