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