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