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