Removed gets message.
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  * Copyright 1998 Matthew Becker
6  *
7  * December 21, 1997 - Kevin Cozens
8  * Fixed bugs in the _w95_loadreg() function. Added extra information
9  * regarding the format of the Windows '95 registry files.
10  *
11  * NOTES
12  *    When changing this file, please re-run the regtest program to ensure
13  *    the conditions are handled properly.
14  *
15  * TODO
16  *    Security access
17  *    Option handling
18  *    Time for RegEnumKey*, RegQueryInfoKey*
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <assert.h>
32 #include <time.h>
33 #include "windows.h"
34 #include "win.h"
35 #include "winerror.h"
36 #include "file.h"
37 #include "heap.h"
38 #include "debug.h"
39 #include "xmalloc.h"
40 #include "winreg.h"
41 #include "winversion.h"
42
43 static void REGISTRY_Init(void);
44 /* FIXME: following defines should be configured global ... */
45
46 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
47 #define WINE_PREFIX                     "/.wine"
48 #define SAVE_USERS_DEFAULT              "/usr/local/etc/wine.userreg"
49 #define SAVE_LOCAL_MACHINE_DEFAULT      "/usr/local/etc/wine.systemreg"
50
51 /* relative in ~user/.wine/ : */
52 #define SAVE_CURRENT_USER               "user.reg"
53 #define SAVE_LOCAL_MACHINE              "system.reg"
54
55 #define KEY_REGISTRY    "Software\\The WINE team\\WINE\\Registry"
56 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57
58 /* one value of a key */
59 typedef struct tagKEYVALUE
60 {
61     LPWSTR   name;          /* name of value (UNICODE) or NULL for win31 */
62     DWORD    type;          /* type of value */
63     DWORD    len;           /* length of data in BYTEs */
64     DWORD    lastmodified;  /* time of seconds since 1.1.1970 */
65     LPBYTE   data;          /* content, may be strings, binaries, etc. */
66 } KEYVALUE,*LPKEYVALUE;
67
68 /* a registry key */
69 typedef struct tagKEYSTRUCT
70 {
71     LPWSTR               keyname;       /* name of THIS key (UNICODE) */
72     DWORD                flags;         /* flags. */
73     LPWSTR               class;
74     /* values */
75     DWORD                nrofvalues;    /* nr of values in THIS key */
76     LPKEYVALUE           values;        /* values in THIS key */
77     /* key management pointers */
78     struct tagKEYSTRUCT *next;          /* next key on same hierarchy */
79     struct tagKEYSTRUCT *nextsub;       /* keys that hang below THIS key */
80 } KEYSTRUCT, *LPKEYSTRUCT;
81
82
83 static KEYSTRUCT        *key_classes_root=NULL; /* windows 3.1 global values */
84 static KEYSTRUCT        *key_current_user=NULL; /* user specific values */
85 static KEYSTRUCT        *key_local_machine=NULL;/* machine specific values */
86 static KEYSTRUCT        *key_users=NULL;        /* all users? */
87
88 /* dynamic, not saved */
89 static KEYSTRUCT        *key_performance_data=NULL;
90 static KEYSTRUCT        *key_current_config=NULL;
91 static KEYSTRUCT        *key_dyn_data=NULL;
92
93 /* what valuetypes do we need to convert? */
94 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
95
96
97 static struct openhandle {
98         LPKEYSTRUCT     lpkey;
99         HKEY            hkey;
100         REGSAM          accessmask;
101 }  *openhandles=NULL;
102 static int      nrofopenhandles=0;
103 /* Starts after 1 because 0,1 are reserved for Win16 */
104 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
105          HKEYs for remote registry access */
106 static int      currenthandle=2;
107
108
109 /*
110  * QUESTION
111  *   Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112  *   If so, can we remove them?
113  * ANSWER
114  *   No, the memory handling functions are called very often in here, 
115  *   just replacing them by HeapAlloc(SystemHeap,...) makes registry
116  *   loading 100 times slower. -MM
117  */
118 static LPWSTR strdupA2W(LPCSTR src)
119 {
120     if(src) {
121         LPWSTR dest=xmalloc(2*strlen(src)+2);
122         lstrcpyAtoW(dest,src);
123         return dest;
124     }
125     return NULL;
126 }
127
128 static LPWSTR strdupW(LPCWSTR a) {
129         LPWSTR  b;
130         int     len;
131
132     if(a) {
133         len=sizeof(WCHAR)*(lstrlen32W(a)+1);
134         b=(LPWSTR)xmalloc(len);
135         memcpy(b,a,len);
136         return b;
137     }
138     return NULL;
139 }
140
141 LPWSTR strcvtA2W(LPCSTR src, int nchars)
142
143 {
144    LPWSTR dest = xmalloc (2 * nchars + 2);
145
146    lstrcpynAtoW(dest,src,nchars+1);
147    dest[nchars] = 0;
148    return dest;
149 }
150
151
152 /******************************************************************************
153  * is_standard_hkey [Internal]
154  * Determines if a hkey is a standard key
155  */
156 static BOOL32 is_standard_hkey( HKEY hkey )
157 {
158     switch(hkey) {
159         case 0x00000000:
160         case 0x00000001:
161         case HKEY_CLASSES_ROOT:
162         case HKEY_CURRENT_CONFIG:
163         case HKEY_CURRENT_USER:
164         case HKEY_LOCAL_MACHINE:
165         case HKEY_USERS:
166         case HKEY_PERFORMANCE_DATA:
167         case HKEY_DYN_DATA:
168             return TRUE;
169         default:
170             return FALSE;
171     }
172 }
173
174 /******************************************************************************
175  * add_handle [Internal]
176  */
177 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
178 {
179     int i;
180
181     TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
182     /* Check for duplicates */
183     for (i=0;i<nrofopenhandles;i++) {
184         if (openhandles[i].lpkey==lpkey) {
185             /* This is not really an error - the user is allowed to create
186                two (or more) handles to the same key */
187             /*WARN(reg, "Adding key %p twice\n",lpkey);*/
188         }
189         if (openhandles[i].hkey==hkey) {
190             WARN(reg, "Adding handle %x twice\n",hkey);
191         }
192     }
193     openhandles=xrealloc( openhandles, 
194                           sizeof(struct openhandle)*(nrofopenhandles+1));
195
196     openhandles[i].lpkey = lpkey;
197     openhandles[i].hkey = hkey;
198     openhandles[i].accessmask = accessmask;
199     nrofopenhandles++;
200 }
201
202
203 /******************************************************************************
204  * get_handle [Internal]
205  *
206  * RETURNS
207  *    Success: Pointer to key
208  *    Failure: NULL
209  */
210 static LPKEYSTRUCT get_handle( HKEY hkey )
211 {
212     int i;
213
214     for (i=0; i<nrofopenhandles; i++)
215         if (openhandles[i].hkey == hkey)
216             return openhandles[i].lpkey;
217     WARN(reg, "Could not find handle 0x%x\n",hkey);
218     return NULL;
219 }
220
221
222 /******************************************************************************
223  * remove_handle [Internal]
224  *
225  * PARAMS
226  *    hkey [I] Handle of key to remove
227  *
228  * RETURNS
229  *    Success: ERROR_SUCCESS
230  *    Failure: ERROR_INVALID_HANDLE
231  */
232 static DWORD remove_handle( HKEY hkey )
233 {
234     int i;
235
236     for (i=0;i<nrofopenhandles;i++)
237         if (openhandles[i].hkey==hkey)
238             break;
239
240     if (i == nrofopenhandles) {
241         WARN(reg, "Could not find handle 0x%x\n",hkey);
242         return ERROR_INVALID_HANDLE;
243     }
244
245     memcpy( openhandles+i,
246             openhandles+i+1,
247             sizeof(struct openhandle)*(nrofopenhandles-i-1)
248     );
249     openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
250     nrofopenhandles--;
251     return ERROR_SUCCESS;
252 }
253
254 /******************************************************************************
255  * lookup_hkey [Internal]
256  * 
257  * Just as the name says. Creates the root keys on demand, so we can call the
258  * Reg* functions at any time.
259  *
260  * RETURNS
261  *    Success: Pointer to key structure
262  *    Failure: NULL
263  */
264 #define ADD_ROOT_KEY(xx) \
265         xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
266         memset(xx,'\0',sizeof(KEYSTRUCT));\
267         xx->keyname= strdupA2W("<should_not_appear_anywhere>");
268
269 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
270 {
271         switch (hkey) {
272         /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
273          * some programs. Do not remove those cases. -MM
274          */
275         case 0x00000000:
276         case 0x00000001:
277         case HKEY_CLASSES_ROOT: {
278                 if (!key_classes_root) {
279                         HKEY    cl_r_hkey;
280
281                         /* calls lookup_hkey recursively, TWICE */
282                         if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
283                                 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
284                                 exit(1);
285                         }
286                         key_classes_root = lookup_hkey(cl_r_hkey);
287                 }
288                 return key_classes_root;
289         }
290         case HKEY_CURRENT_USER:
291                 if (!key_current_user) {
292                         HKEY    c_u_hkey;
293                         struct  passwd  *pwd;
294
295                         pwd=getpwuid(getuid());
296                         /* calls lookup_hkey recursively, TWICE */
297                         if (pwd && pwd->pw_name) {
298                                 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
299                                         ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
300                                         exit(1);
301                                 }
302                                 key_current_user = lookup_hkey(c_u_hkey);
303                         } else {
304                                 /* nothing found, use standalone */
305                                 ADD_ROOT_KEY(key_current_user);
306                         }
307                 }
308                 return key_current_user;
309         case HKEY_LOCAL_MACHINE:
310                 if (!key_local_machine) {
311                         ADD_ROOT_KEY(key_local_machine);
312                         REGISTRY_Init();
313                 }
314                 return key_local_machine;
315         case HKEY_USERS:
316                 if (!key_users) {
317                         ADD_ROOT_KEY(key_users);
318                 }
319                 return key_users;
320         case HKEY_PERFORMANCE_DATA:
321                 if (!key_performance_data) {
322                         ADD_ROOT_KEY(key_performance_data);
323                 }
324                 return key_performance_data;
325         case HKEY_DYN_DATA:
326                 if (!key_dyn_data) {
327                         ADD_ROOT_KEY(key_dyn_data);
328                 }
329                 return key_dyn_data;
330         case HKEY_CURRENT_CONFIG:
331                 if (!key_current_config) {
332                         ADD_ROOT_KEY(key_current_config);
333                 }
334                 return key_current_config;
335         default:
336                 return get_handle(hkey);
337         }
338         /*NOTREACHED*/
339 }
340 #undef ADD_ROOT_KEY
341 /* so we don't accidently access them ... */
342 #define key_current_config NULL NULL
343 #define key_current_user NULL NULL
344 #define key_users NULL NULL
345 #define key_local_machine NULL NULL
346 #define key_classes_root NULL NULL
347 #define key_dyn_data NULL NULL
348 #define key_performance_data NULL NULL
349
350 /******************************************************************************
351  * split_keypath [Internal]
352  * splits the unicode string 'wp' into an array of strings.
353  * the array is allocated by this function. 
354  * Free the array using FREE_KEY_PATH
355  *
356  * PARAMS
357  *    wp  [I] String to split up
358  *    wpv [O] Array of pointers to strings
359  *    wpc [O] Number of components
360  */
361 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
362 {
363     int i,j,len;
364     LPWSTR ws;
365
366     TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
367
368     ws  = HEAP_strdupW( SystemHeap, 0, wp );
369
370     /* We know we have at least one substring */
371     *wpc = 1;
372
373     /* Replace each backslash with NULL, and increment the count */
374     for (i=0;ws[i];i++) {
375         if (ws[i]=='\\') {
376             ws[i]=0;
377             (*wpc)++;
378         }
379     }
380
381     len = i;
382
383     /* Allocate the space for the array of pointers, leaving room for the
384        NULL at the end */
385     *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
386     (*wpv)[0]= ws;
387
388     /* Assign each pointer to the appropriate character in the string */
389     j = 1;
390     for (i=1;i<len;i++)
391         if (ws[i-1]==0) {
392             (*wpv)[j++]=ws+i;
393             /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
394         }
395
396     (*wpv)[j]=NULL;
397 }
398 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
399
400
401
402
403 /******************************************************************************
404  * REGISTRY_Init [Internal]
405  * Registry initialisation, allocates some default keys. 
406  */
407 static void REGISTRY_Init(void) {
408         HKEY    hkey;
409         char    buf[200];
410
411         TRACE(reg,"(void)\n");
412
413         RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
414         RegCloseKey(hkey);
415
416         /* This was an Open, but since it is called before the real registries
417            are loaded, it was changed to a Create - MTB 980507*/
418         RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
419         RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
420         RegCloseKey(hkey);
421
422         /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
423          *                                              CurrentVersion
424          *                                              CurrentBuildNumber
425          *                                              CurrentType
426          *                                      string  RegisteredOwner
427          *                                      string  RegisteredOrganization
428          *
429          */
430         /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
431          *                                      string  SysContact
432          *                                      string  SysLocation
433          *                                              SysServices
434          */                                             
435         if (-1!=gethostname(buf,200)) {
436                 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
437                 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
438                 RegCloseKey(hkey);
439         }
440 }
441
442
443 /************************ SAVE Registry Function ****************************/
444
445 #define REGISTRY_SAVE_VERSION   0x00000001
446
447 /* Registry saveformat:
448  * If you change it, increase above number by 1, which will flush
449  * old registry database files.
450  * 
451  * Global:
452  *      "WINE REGISTRY Version %d"
453  *      subkeys....
454  * Subkeys:
455  *      keyname
456  *              valuename=lastmodified,type,data
457  *              ...
458  *              subkeys
459  *      ...
460  * keyname,valuename,stringdata:
461  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
462  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
463  *      ( "=\\\t" escaped in \uXXXX form.)
464  * type,lastmodified: 
465  *      int
466  * 
467  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
468  *
469  * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
470  * SaveOnlyUpdatedKeys=yes
471  */
472
473 /******************************************************************************
474  * _save_check_tainted [Internal]
475  */
476 static int _save_check_tainted( LPKEYSTRUCT lpkey )
477 {
478         int             tainted;
479
480         if (!lpkey)
481                 return 0;
482         if (lpkey->flags & REG_OPTION_TAINTED)
483                 tainted = 1;
484         else
485                 tainted = 0;
486         while (lpkey) {
487                 if (_save_check_tainted(lpkey->nextsub)) {
488                         lpkey->flags |= REG_OPTION_TAINTED;
489                         tainted = 1;
490                 }
491                 lpkey   = lpkey->next;
492         }
493         return tainted;
494 }
495
496 /******************************************************************************
497  * _save_USTRING [Internal]
498  */
499 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
500 {
501         LPWSTR  s;
502         int     doescape;
503
504         if (wstr==NULL)
505                 return;
506         s=wstr;
507         while (*s) {
508                 doescape=0;
509                 if (*s>0xff)
510                         doescape = 1;
511                 if (*s=='\n')
512                         doescape = 1;
513                 if (escapeeq && *s=='=')
514                         doescape = 1;
515                 if (*s=='\\')
516                         fputc(*s,F); /* if \\ then put it twice. */
517                 if (doescape)
518                         fprintf(F,"\\u%04x",*((unsigned short*)s));
519                 else
520                         fputc(*s,F);
521                 s++;
522         }
523 }
524
525 /******************************************************************************
526  * _savesubkey [Internal]
527  */
528 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
529 {
530         LPKEYSTRUCT     lpxkey;
531         int             i,tabs,j;
532
533         lpxkey  = lpkey;
534         while (lpxkey) {
535                 if (    !(lpxkey->flags & REG_OPTION_VOLATILE) &&
536                         (all || (lpxkey->flags & REG_OPTION_TAINTED))
537                 ) {
538                         for (tabs=level;tabs--;)
539                                 fputc('\t',F);
540                         _save_USTRING(F,lpxkey->keyname,1);
541                         fputs("\n",F);
542                         for (i=0;i<lpxkey->nrofvalues;i++) {
543                                 LPKEYVALUE      val=lpxkey->values+i;
544
545                                 for (tabs=level+1;tabs--;)
546                                         fputc('\t',F);
547                                 _save_USTRING(F,val->name,0);
548                                 fputc('=',F);
549                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
550                                 if ((1<<val->type) & UNICONVMASK)
551                                         _save_USTRING(F,(LPWSTR)val->data,0);
552                                 else
553                                         for (j=0;j<val->len;j++)
554                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
555                                 fputs("\n",F);
556                         }
557                         /* descend recursively */
558                         if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
559                                 return 0;
560                 }
561                 lpxkey=lpxkey->next;
562         }
563         return 1;
564 }
565
566
567 /******************************************************************************
568  * _savesubreg [Internal]
569  */
570 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
571 {
572         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
573         _save_check_tainted(lpkey->nextsub);
574         return _savesubkey(F,lpkey->nextsub,0,all);
575 }
576
577
578 /******************************************************************************
579  * _savereg [Internal]
580  */
581 static BOOL32 _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
582 {
583         FILE    *F;
584
585         F=fopen(fn,"w");
586         if (F==NULL) {
587                 WARN(reg,"Couldn't open %s for writing: %s\n",
588                         fn,strerror(errno)
589                 );
590                 return FALSE;
591         }
592         if (!_savesubreg(F,lpkey,all)) {
593                 fclose(F);
594                 unlink(fn);
595                 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
596                 return FALSE;
597         }
598         fclose(F);
599         return TRUE;
600 }
601
602
603 /******************************************************************************
604  * SHELL_SaveRegistry [Internal]
605  */
606 void SHELL_SaveRegistry( void )
607 {
608         char    *fn;
609         struct  passwd  *pwd;
610         char    buf[4];
611         HKEY    hkey;
612         int     all;
613
614     TRACE(reg,"(void)\n");
615
616         all=0;
617         if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
618                 strcpy(buf,"yes");
619         } else {
620                 DWORD len,junk,type;
621
622                 len=4;
623                 if (    (ERROR_SUCCESS!=RegQueryValueEx32A(
624                                 hkey,
625                                 VAL_SAVEUPDATED,
626                                 &junk,
627                                 &type,
628                                 buf,
629                                 &len
630                         ))|| (type!=REG_SZ)
631                 )
632                         strcpy(buf,"yes");
633                 RegCloseKey(hkey);
634         }
635         if (lstrcmpi32A(buf,"yes"))
636                 all=1;
637         pwd=getpwuid(getuid());
638         if (pwd!=NULL && pwd->pw_dir!=NULL)
639         {
640                 char *tmp;
641
642                 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
643                                    strlen(SAVE_CURRENT_USER) + 2 );
644                 strcpy(fn,pwd->pw_dir);
645                 strcat(fn,WINE_PREFIX);
646                 /* create the directory. don't care about errorcodes. */
647                 mkdir(fn,0755); /* drwxr-xr-x */
648                 strcat(fn,"/"SAVE_CURRENT_USER);
649                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
650                 strcpy(tmp,fn);strcat(tmp,".tmp");
651                 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
652                         if (-1==rename(tmp,fn)) {
653                                 perror("rename tmp registry");
654                                 unlink(tmp);
655                         }
656                 }
657                 free(tmp);
658                 free(fn);
659                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
660                 strcpy(fn,pwd->pw_dir);
661                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
662                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
663                 strcpy(tmp,fn);strcat(tmp,".tmp");
664                 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
665                         if (-1==rename(tmp,fn)) {
666                                 perror("rename tmp registry");
667                                 unlink(tmp);
668                         }
669                 }
670                 free(tmp);
671                 free(fn);
672         } else
673                 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
674 }
675
676
677 /************************ LOAD Registry Function ****************************/
678
679
680
681 /******************************************************************************
682  * _find_or_add_key [Internal]
683  */
684 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
685 {
686         LPKEYSTRUCT     lpxkey,*lplpkey;
687
688         if ((!keyname) || (keyname[0]==0)) {
689                 free(keyname);
690                 return lpkey;
691         }
692         lplpkey= &(lpkey->nextsub);
693         lpxkey  = *lplpkey;
694         while (lpxkey) {
695                 if (    (lpxkey->keyname[0]==keyname[0]) && 
696                         !lstrcmpi32W(lpxkey->keyname,keyname)
697                 )
698                         break;
699                 lplpkey = &(lpxkey->next);
700                 lpxkey  = *lplpkey;
701         }
702         if (lpxkey==NULL) {
703                 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
704                 lpxkey  = *lplpkey;
705                 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
706                 lpxkey->keyname = keyname;
707         } else
708                 free(keyname);
709         return lpxkey;
710 }
711
712 /******************************************************************************
713  * _find_or_add_value [Internal]
714  */
715 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
716                                 LPBYTE data, DWORD len, DWORD lastmodified )
717 {
718         LPKEYVALUE      val=NULL;
719         int             i;
720
721         if (name && !*name) {/* empty string equals default (NULL) value */
722                 free(name);
723                 name = NULL;
724         }
725
726         for (i=0;i<lpkey->nrofvalues;i++) {
727                 val=lpkey->values+i;
728                 if (name==NULL) {
729                         if (val->name==NULL)
730                                 break;
731                 } else {
732                         if (    val->name!=NULL && 
733                                 val->name[0]==name[0] &&
734                                 !lstrcmpi32W(val->name,name)
735                         )
736                                 break;
737                 }
738         }
739         if (i==lpkey->nrofvalues) {
740                 lpkey->values = xrealloc(
741                         lpkey->values,
742                         (++lpkey->nrofvalues)*sizeof(KEYVALUE)
743                 );
744                 val=lpkey->values+i;
745                 memset(val,'\0',sizeof(KEYVALUE));
746                 val->name = name;
747         } else {
748                 if (name)
749                         free(name);
750         }
751         if (val->lastmodified<lastmodified) {
752                 val->lastmodified=lastmodified;
753                 val->type = type;
754                 val->len  = len;
755                 if (val->data) 
756                         free(val->data);
757                 val->data = data;
758         } else
759                 free(data);
760 }
761
762
763 /******************************************************************************
764  * _wine_read_line [Internal]
765  *
766  * reads a line including dynamically enlarging the readbuffer and throwing
767  * away comments
768  */
769 static int _wine_read_line( FILE *F, char **buf, int *len )
770 {
771         char    *s,*curread;
772         int     mylen,curoff;
773
774         curread = *buf;
775         mylen   = *len;
776         **buf   = '\0';
777         while (1) {
778                 while (1) {
779                         s=fgets(curread,mylen,F);
780                         if (s==NULL)
781                                 return 0; /* EOF */
782                         if (NULL==(s=strchr(curread,'\n'))) {
783                                 /* buffer wasn't large enough */
784                                 curoff  = strlen(*buf);
785                                 *buf    = xrealloc(*buf,*len*2);
786                                 curread = *buf + curoff;
787                                 mylen   = *len; /* we filled up the buffer and 
788                                                  * got new '*len' bytes to fill
789                                                  */
790                                 *len    = *len * 2;
791                         } else {
792                                 *s='\0';
793                                 break;
794                         }
795                 }
796                 /* throw away comments */
797                 if (**buf=='#' || **buf==';') {
798                         curread = *buf;
799                         mylen   = *len;
800                         continue;
801                 }
802                 if (s)  /* got end of line */
803                         break;
804         }
805         return 1;
806 }
807
808
809 /******************************************************************************
810  * _wine_read_USTRING [Internal]
811  *
812  * converts a char* into a UNICODE string (up to a special char)
813  * and returns the position exactly after that string
814  */
815 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
816 {
817         char    *s;
818         LPWSTR  ws;
819
820         /* read up to "=" or "\0" or "\n" */
821         s       = buf;
822         if (*s == '=') {
823                 /* empty string is the win3.1 default value(NULL)*/
824                 *str    = NULL;
825                 return s;
826         }
827         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
828         ws      = *str;
829         while (*s && (*s!='\n') && (*s!='=')) {
830                 if (*s!='\\')
831                         *ws++=*((unsigned char*)s++);
832                 else {
833                         s++;
834                         if (*s=='\\') {
835                                 *ws++='\\';
836                                 s++;
837                                 continue;
838                         }
839                         if (*s!='u') {
840                                 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
841                                 *ws++='\\';
842                                 *ws++=*s++;
843                         } else {
844                                 char    xbuf[5];
845                                 int     wc;
846
847                                 s++;
848                                 memcpy(xbuf,s,4);xbuf[4]='\0';
849                                 if (!sscanf(xbuf,"%x",&wc))
850                                         WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
851                                 s+=4;
852                                 *ws++   =(unsigned short)wc;
853                         }
854                 }
855         }
856         *ws     = 0;
857         ws      = *str;
858         if (*ws)
859                 *str    = strdupW(*str);
860         else
861                 *str    = NULL;
862         free(ws);
863         return s;
864 }
865
866
867 /******************************************************************************
868  * _wine_loadsubkey [Internal]
869  *
870  * NOTES
871  *    It seems like this is returning a boolean.  Should it?
872  *
873  * RETURNS
874  *    Success: 1
875  *    Failure: 0
876  */
877 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
878                              int *buflen, DWORD optflag )
879 {
880         LPKEYSTRUCT     lpxkey;
881         int             i;
882         char            *s;
883         LPWSTR          name;
884
885     TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
886           *buflen, optflag);
887
888     lpkey->flags |= optflag;
889
890     /* Good.  We already got a line here ... so parse it */
891     lpxkey = NULL;
892     while (1) {
893         i=0;s=*buf;
894         while (*s=='\t') {
895             s++;
896             i++;
897         }
898         if (i>level) {
899             if (lpxkey==NULL) {
900                 WARN(reg,"Got a subhierarchy without resp. key?\n");
901                 return 0;
902             }
903             _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
904             continue;
905         }
906
907                 /* let the caller handle this line */
908                 if (i<level || **buf=='\0')
909                         return 1;
910
911                 /* it can be: a value or a keyname. Parse the name first */
912                 s=_wine_read_USTRING(s,&name);
913
914                 /* switch() default: hack to avoid gotos */
915                 switch (0) {
916                 default:
917                         if (*s=='\0') {
918                                 lpxkey=_find_or_add_key(lpkey,name);
919                         } else {
920                                 LPBYTE          data;
921                                 int             len,lastmodified,type;
922
923                                 if (*s!='=') {
924                                         WARN(reg,"Unexpected character: %c\n",*s);
925                                         break;
926                                 }
927                                 s++;
928                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
929                                         WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
930                                         break;
931                                 }
932                                 /* skip the 2 , */
933                                 s=strchr(s,',');s++;
934                                 s=strchr(s,',');s++;
935                                 if ((1<<type) & UNICONVMASK) {
936                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
937                                         if (data)
938                                                 len = lstrlen32W((LPWSTR)data)*2+2;
939                                         else    
940                                                 len = 0;
941                                 } else {
942                                         len=strlen(s)/2;
943                                         data = (LPBYTE)xmalloc(len+1);
944                                         for (i=0;i<len;i++) {
945                                                 data[i]=0;
946                                                 if (*s>='0' && *s<='9')
947                                                         data[i]=(*s-'0')<<4;
948                                                 if (*s>='a' && *s<='f')
949                                                         data[i]=(*s-'a'+'\xa')<<4;
950                                                 if (*s>='A' && *s<='F')
951                                                         data[i]=(*s-'A'+'\xa')<<4;
952                                                 s++;
953                                                 if (*s>='0' && *s<='9')
954                                                         data[i]|=*s-'0';
955                                                 if (*s>='a' && *s<='f')
956                                                         data[i]|=*s-'a'+'\xa';
957                                                 if (*s>='A' && *s<='F')
958                                                         data[i]|=*s-'A'+'\xa';
959                                                 s++;
960                                         }
961                                 }
962                                 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
963                         }
964                 }
965                 /* read the next line */
966                 if (!_wine_read_line(F,buf,buflen))
967                         return 1;
968     }
969     return 1;
970 }
971
972
973 /******************************************************************************
974  * _wine_loadsubreg [Internal]
975  */
976 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
977 {
978         int     ver;
979         char    *buf;
980         int     buflen;
981
982         buf=xmalloc(10);buflen=10;
983         if (!_wine_read_line(F,&buf,&buflen)) {
984                 free(buf);
985                 return 0;
986         }
987         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
988                 free(buf);
989                 return 0;
990         }
991         if (ver!=REGISTRY_SAVE_VERSION) {
992                 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
993                 free(buf);
994                 return 0;
995         }
996         if (!_wine_read_line(F,&buf,&buflen)) {
997                 free(buf);
998                 return 0;
999         }
1000         if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1001                 free(buf);
1002                 return 0;
1003         }
1004         free(buf);
1005         return 1;
1006 }
1007
1008
1009 /******************************************************************************
1010  * _wine_loadreg [Internal]
1011  */
1012 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1013 {
1014     FILE *F;
1015
1016     TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1017
1018     F = fopen(fn,"rb");
1019     if (F==NULL) {
1020         WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1021         return;
1022     }
1023     if (!_wine_loadsubreg(F,lpkey,optflag)) {
1024         fclose(F);
1025         unlink(fn);
1026         return;
1027     }
1028     fclose(F);
1029 }
1030
1031
1032 /******************************************************************************
1033  * _copy_registry [Internal]
1034  */
1035 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1036 {
1037         LPKEYSTRUCT     lpxkey;
1038         int             j;
1039         LPKEYVALUE      valfrom;
1040
1041         from=from->nextsub;
1042         while (from) {
1043                 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1044
1045                 for (j=0;j<from->nrofvalues;j++) {
1046                         LPWSTR  name;
1047                         LPBYTE  data;
1048
1049                         valfrom = from->values+j;
1050                         name=valfrom->name;
1051                         if (name) name=strdupW(name);
1052                         data=(LPBYTE)xmalloc(valfrom->len);
1053                         memcpy(data,valfrom->data,valfrom->len);
1054
1055                         _find_or_add_value(
1056                                 lpxkey,
1057                                 name,
1058                                 valfrom->type,
1059                                 data,
1060                                 valfrom->len,
1061                                 valfrom->lastmodified
1062                         );
1063                 }
1064                 _copy_registry(from,lpxkey);
1065                 from = from->next;
1066         }
1067 }
1068
1069
1070 /* WINDOWS 95 REGISTRY LOADER */
1071 /* 
1072  * Structure of a win95 registry database.
1073  * main header:
1074  * 0 :  "CREG"  - magic
1075  * 4 :  DWORD version
1076  * 8 :  DWORD offset_of_RGDB_part
1077  * 0C..0F:      ? (someone fill in please)
1078  * 10:  WORD    number of RGDB blocks
1079  * 12:  WORD    ?
1080  * 14:  WORD    always 0000?
1081  * 16:  WORD    always 0001?
1082  * 18..1F:      ? (someone fill in please)
1083  *
1084  * 20: RGKN_section:
1085  *   header:
1086  *      0 :             "RGKN"  - magic
1087  *      4 : DWORD       offset to first RGDB section
1088  *      8 : DWORD       offset to the root record
1089  *      C..0x1B:        ? (fill in)
1090  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1091  *
1092  *   Disk Key Entry Structure:
1093  *      00: DWORD       - Free entry indicator(?)
1094  *      04: DWORD       - Hash = sum of bytes of keyname
1095  *      08: DWORD       - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1096  *      0C: DWORD       - disk address of PreviousLevel Key.
1097  *      10: DWORD       - disk address of Next Sublevel Key.
1098  *      14: DWORD       - disk address of Next Key (on same level).
1099  * DKEP>18: WORD        - Nr, Low Significant part.
1100  *      1A: WORD        - Nr, High Significant part.
1101  *
1102  * The disk address always points to the nr part of the previous key entry 
1103  * of the referenced key. Don't ask me why, or even if I got this correct
1104  * from staring at 1kg of hexdumps. (DKEP)
1105  *
1106  * The High significant part of the structure seems to equal the number
1107  * of the RGDB section. The low significant part is a unique ID within
1108  * that RGDB section
1109  *
1110  * There are two minor corrections to the position of that structure.
1111  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
1112  *    the DKE reread from there.
1113  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1114  * CPS - I have not experienced the above phenomenon in my registry files
1115  *
1116  * RGDB_section:
1117  *      00:             "RGDB"  - magic
1118  *      04: DWORD       offset to next RGDB section
1119  *      08: DWORD       ?
1120  *      0C: WORD        always 000d?
1121  *      0E: WORD        RGDB block number
1122  *      10:     DWORD   ? (equals value at offset 4 - value at offset 8)
1123  *      14..1F:         ?
1124  *      20.....:        disk keys
1125  *
1126  * disk key:
1127  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
1128  *      08:     WORD    nrLS            - low significant part of NR
1129  *      0A:     WORD    nrHS            - high significant part of NR
1130  *      0C:     DWORD   bytesused       - bytes used in this structure.
1131  *      10:     WORD    name_len        - length of name in bytes. without \0
1132  *      12:     WORD    nr_of_values    - number of values.
1133  *      14:     char    name[name_len]  - name string. No \0.
1134  *      14+name_len: disk values
1135  *      nextkeyoffset: ... next disk key
1136  *
1137  * disk value:
1138  *      00:     DWORD   type            - value type (hmm, could be WORD too)
1139  *      04:     DWORD                   - unknown, usually 0
1140  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
1141  *      0C:     WORD    datalen         - length of Data.
1142  *      10:     char    name[namelen]   - name, no \0
1143  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
1144  *      10+namelen+datalen: next values or disk key
1145  *
1146  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1147  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1148  * structure) and reading another RGDB_section.
1149  * repeat until end of file.
1150  *
1151  * An interesting relationship exists in RGDB_section. The value at offset
1152  * 10 equals the value at offset 4 minus the value at offset 8. I have no
1153  * idea at the moment what this means.  (Kevin Cozens)
1154  *
1155  * FIXME: this description needs some serious help, yes.
1156  */
1157
1158 struct  _w95keyvalue {
1159         unsigned long           type;
1160         unsigned short          datalen;
1161         char                    *name;
1162         unsigned char           *data;
1163         unsigned long           x1;
1164         int                     lastmodified;
1165 };
1166
1167 struct  _w95key {
1168         char                    *name;
1169         int                     nrofvals;
1170         struct  _w95keyvalue    *values;
1171         struct _w95key          *prevlvl;
1172         struct _w95key          *nextsub;
1173         struct _w95key          *next;
1174 };
1175
1176
1177 struct _w95_info {
1178   char *rgknbuffer;
1179   int  rgknsize;
1180   char *rgdbbuffer;
1181   int  rgdbsize;
1182   int  depth;
1183   int  lastmodified;
1184 };
1185
1186
1187 /******************************************************************************
1188  * _w95_processKey [Internal]
1189  */
1190 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey, 
1191                                    int nrLS, int nrMS, struct _w95_info *info )
1192
1193 {
1194   /* Disk Key Header structure (RGDB part) */
1195         struct  dkh {
1196                 unsigned long           nextkeyoff; 
1197                 unsigned short          nrLS;
1198                 unsigned short          nrMS;
1199                 unsigned long           bytesused;
1200                 unsigned short          keynamelen;
1201                 unsigned short          values;
1202                 unsigned long           xx1;
1203                 /* keyname */
1204                 /* disk key values or nothing */
1205         };
1206         /* Disk Key Value structure */
1207         struct  dkv {
1208                 unsigned long           type;
1209                 unsigned long           x1;
1210                 unsigned short          valnamelen;
1211                 unsigned short          valdatalen;
1212                 /* valname, valdata */
1213         };
1214
1215         
1216         struct  dkh dkh;
1217         int     bytesread = 0;
1218         char    *rgdbdata = info->rgdbbuffer;
1219         int     nbytes = info->rgdbsize;
1220         char    *curdata = rgdbdata;
1221         char    *end = rgdbdata + nbytes;
1222         int     off_next_rgdb;
1223         char    *next = rgdbdata;
1224         int     nrgdb, i;
1225         LPKEYSTRUCT     lpxkey;
1226         
1227         do {
1228           curdata = next;
1229           if (strncmp(curdata, "RGDB", 4)) return (NULL);
1230             
1231           memcpy(&off_next_rgdb,curdata+4,4);
1232           next = curdata + off_next_rgdb;
1233           nrgdb = (int) *((short *)curdata + 7);
1234
1235         } while (nrgdb != nrMS && (next < end));
1236
1237         /* curdata now points to the start of the right RGDB section */
1238         curdata += 0x20;
1239
1240 #define XREAD(whereto,len) \
1241         if ((curdata + len) <end) {\
1242                 memcpy(whereto,curdata,len);\
1243                 curdata+=len;\
1244                 bytesread+=len;\
1245         }
1246
1247         while (curdata < next) {
1248           struct        dkh *xdkh = (struct dkh*)curdata;
1249
1250           bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1251           if (xdkh->nrLS == nrLS) {
1252                 memcpy(&dkh,xdkh,sizeof(dkh));
1253                 curdata += sizeof(dkh);
1254                 break;
1255           }
1256           curdata += xdkh->nextkeyoff;
1257         };
1258
1259         if (dkh.nrLS != nrLS) return (NULL);
1260
1261         if (nrgdb != dkh.nrMS)
1262           return (NULL);
1263
1264         assert((dkh.keynamelen<2) || curdata[0]);
1265         lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1266         curdata += dkh.keynamelen;
1267
1268         for (i=0;i< dkh.values; i++) {
1269           struct dkv dkv;
1270           LPBYTE data;
1271           int len;
1272           LPWSTR name;
1273
1274           XREAD(&dkv,sizeof(dkv));
1275
1276           name = strcvtA2W(curdata, dkv.valnamelen);
1277           curdata += dkv.valnamelen;
1278
1279           if ((1 << dkv.type) & UNICONVMASK) {
1280             data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1281             len = 2*(dkv.valdatalen + 1);
1282           } else {
1283             /* I don't think we want to NULL terminate all data */
1284             data = xmalloc(dkv.valdatalen);
1285             memcpy (data, curdata, dkv.valdatalen);
1286             len = dkv.valdatalen;
1287           }
1288
1289           curdata += dkv.valdatalen;
1290           
1291           _find_or_add_value(
1292                              lpxkey,
1293                              name,
1294                              dkv.type,
1295                              data,
1296                              len,
1297                              info->lastmodified
1298                              );
1299         }
1300         return (lpxkey);
1301 }
1302
1303 /******************************************************************************
1304  * _w95_walkrgkn [Internal]
1305  */
1306 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off, 
1307                            struct _w95_info *info )
1308
1309 {
1310   /* Disk Key Entry structure (RGKN part) */
1311   struct        dke {
1312     unsigned long               x1;
1313     unsigned long               x2;
1314     unsigned long               x3;/*usually 0xFFFFFFFF */
1315     unsigned long               prevlvl;
1316     unsigned long               nextsub;
1317     unsigned long               next;
1318     unsigned short              nrLS;
1319     unsigned short              nrMS;
1320   } *dke = (struct dke *)off;
1321   LPKEYSTRUCT  lpxkey;
1322
1323   if (dke == NULL) {
1324     dke = (struct dke *) ((char *)info->rgknbuffer);
1325   }
1326
1327   lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1328   /* XXX <-- This is a hack*/
1329   if (!lpxkey) {
1330     lpxkey = prevkey;
1331   }
1332
1333   if (dke->nextsub != -1 && 
1334       ((dke->nextsub - 0x20) < info->rgknsize) 
1335       && (dke->nextsub > 0x20)) {
1336     
1337     _w95_walkrgkn(lpxkey, 
1338                   info->rgknbuffer + dke->nextsub - 0x20, 
1339                   info);
1340   }
1341   
1342   if (dke->next != -1 && 
1343       ((dke->next - 0x20) < info->rgknsize) && 
1344       (dke->next > 0x20)) {
1345     _w95_walkrgkn(prevkey,  
1346                   info->rgknbuffer + dke->next - 0x20,
1347                   info);
1348   }
1349
1350   return;
1351 }
1352
1353
1354 /******************************************************************************
1355  * _w95_loadreg [Internal]
1356  */
1357 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1358 {
1359         HFILE32         hfd;
1360         char            magic[5];
1361         unsigned long   where,version,rgdbsection,end;
1362         struct          _w95_info info;
1363         OFSTRUCT        ofs;
1364         BY_HANDLE_FILE_INFORMATION hfdinfo;
1365
1366         TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1367         hfd=OpenFile32(fn,&ofs,OF_READ);
1368         if (hfd==HFILE_ERROR32)
1369                 return;
1370         magic[4]=0;
1371         if (4!=_lread32(hfd,magic,4))
1372                 return;
1373         if (strcmp(magic,"CREG")) {
1374                 WARN(reg,"%s is not a w95 registry.\n",fn);
1375                 return;
1376         }
1377         if (4!=_lread32(hfd,&version,4))
1378                 return;
1379         if (4!=_lread32(hfd,&rgdbsection,4))
1380                 return;
1381         if (-1==_llseek32(hfd,0x20,SEEK_SET))
1382                 return;
1383         if (4!=_lread32(hfd,magic,4))
1384                 return;
1385         if (strcmp(magic,"RGKN")) {
1386                 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1387                 return;
1388         }
1389
1390         /* STEP 1: Keylink structures */
1391         if (-1==_llseek32(hfd,0x40,SEEK_SET))
1392                 return;
1393         where   = 0x40;
1394         end     = rgdbsection;
1395
1396         info.rgknsize = end - where;
1397         info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1398         if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1399                 return;
1400
1401         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1402                 return;
1403
1404         end = hfdinfo.nFileSizeLow;
1405         info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1406
1407         if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1408                 return;
1409
1410         info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1411         info.rgdbsize = end - rgdbsection;
1412
1413         if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1414                 return;
1415         _lclose32(hfd);
1416
1417         _w95_walkrgkn(lpkey, NULL, &info);
1418
1419         free (info.rgdbbuffer);
1420         free (info.rgknbuffer);
1421 }
1422
1423
1424 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1425
1426 /*
1427     reghack - windows 3.11 registry data format demo program.
1428
1429     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1430     a combined hash table and tree description, and finally a text table.
1431
1432     The header is obvious from the struct header. The taboff1 and taboff2
1433     fields are always 0x20, and their usage is unknown.
1434
1435     The 8-byte entry table has various entry types.
1436
1437     tabent[0] is a root index. The second word has the index of the root of
1438             the directory.
1439     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1440             the index of the key/value that has that hash. Data with the same
1441             hash value are on a circular list. The other three words in the
1442             hash entry are always zero.
1443     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1444             entry: dirent and keyent/valent. They are identified by context.
1445     tabent[freeidx] is the first free entry. The first word in a free entry
1446             is the index of the next free entry. The last has 0 as a link.
1447             The other three words in the free list are probably irrelevant.
1448
1449     Entries in text table are preceeded by a word at offset-2. This word
1450     has the value (2*index)+1, where index is the referring keyent/valent
1451     entry in the table. I have no suggestion for the 2* and the +1.
1452     Following the word, there are N bytes of data, as per the keyent/valent
1453     entry length. The offset of the keyent/valent entry is from the start
1454     of the text table to the first data byte.
1455
1456     This information is not available from Microsoft. The data format is
1457     deduced from the reg.dat file by me. Mistakes may
1458     have been made. I claim no rights and give no guarantees for this program.
1459
1460     Tor Sjøwall, tor@sn.no
1461 */
1462
1463 /* reg.dat header format */
1464 struct _w31_header {
1465         char            cookie[8];      /* 'SHCC3.10' */
1466         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1467         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1468         unsigned long   tabcnt;         /* number of entries in index table */
1469         unsigned long   textoff;        /* offset of text part */
1470         unsigned long   textsize;       /* byte size of text part */
1471         unsigned short  hashsize;       /* hash size */
1472         unsigned short  freeidx;        /* free index */
1473 };
1474
1475 /* generic format of table entries */
1476 struct _w31_tabent {
1477         unsigned short w0, w1, w2, w3;
1478 };
1479
1480 /* directory tabent: */
1481 struct _w31_dirent {
1482         unsigned short  sibling_idx;    /* table index of sibling dirent */
1483         unsigned short  child_idx;      /* table index of child dirent */
1484         unsigned short  key_idx;        /* table index of key keyent */
1485         unsigned short  value_idx;      /* table index of value valent */
1486 };
1487
1488 /* key tabent: */
1489 struct _w31_keyent {
1490         unsigned short  hash_idx;       /* hash chain index for string */
1491         unsigned short  refcnt;         /* reference count */
1492         unsigned short  length;         /* length of string */
1493         unsigned short  string_off;     /* offset of string in text table */
1494 };
1495
1496 /* value tabent: */
1497 struct _w31_valent {
1498         unsigned short  hash_idx;       /* hash chain index for string */
1499         unsigned short  refcnt;         /* reference count */
1500         unsigned short  length;         /* length of string */
1501         unsigned short  string_off;     /* offset of string in text table */
1502 };
1503
1504 /* recursive helper function to display a directory tree */
1505 void
1506 __w31_dumptree( unsigned short idx,
1507                 unsigned char *txt,
1508                 struct _w31_tabent *tab,
1509                 struct _w31_header *head,
1510                 LPKEYSTRUCT     lpkey,
1511                 time_t          lastmodified,
1512                 int             level
1513 ) {
1514         struct _w31_dirent      *dir;
1515         struct _w31_keyent      *key;
1516         struct _w31_valent      *val;
1517         LPKEYSTRUCT             xlpkey = NULL;
1518         LPWSTR                  name,value;
1519         static char             tail[400];
1520
1521         while (idx!=0) {
1522                 dir=(struct _w31_dirent*)&tab[idx];
1523
1524                 if (dir->key_idx) {
1525                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1526
1527                         memcpy(tail,&txt[key->string_off],key->length);
1528                         tail[key->length]='\0';
1529                         /* all toplevel entries AND the entries in the 
1530                          * toplevel subdirectory belong to \SOFTWARE\Classes
1531                          */
1532                         if (!level && !lstrcmp32A(tail,".classes")) {
1533                                 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1534                                 idx=dir->sibling_idx;
1535                                 continue;
1536                         }
1537                         name=strdupA2W(tail);
1538
1539                         xlpkey=_find_or_add_key(lpkey,name);
1540
1541                         /* only add if leaf node or valued node */
1542                         if (dir->value_idx!=0||dir->child_idx==0) {
1543                                 if (dir->value_idx) {
1544                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1545                                         memcpy(tail,&txt[val->string_off],val->length);
1546                                         tail[val->length]='\0';
1547                                         value=strdupA2W(tail);
1548                                         _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1549                                 }
1550                         }
1551                 } else {
1552                         TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1553                 }
1554                 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1555                 idx=dir->sibling_idx;
1556         }
1557 }
1558
1559
1560 /******************************************************************************
1561  * _w31_loadreg [Internal]
1562  */
1563 void _w31_loadreg(void) {
1564         HFILE32                 hf;
1565         struct _w31_header      head;
1566         struct _w31_tabent      *tab;
1567         unsigned char           *txt;
1568         int                     len;
1569         OFSTRUCT                ofs;
1570         BY_HANDLE_FILE_INFORMATION hfinfo;
1571         time_t                  lastmodified;
1572         LPKEYSTRUCT             lpkey;
1573
1574         TRACE(reg,"(void)\n");
1575
1576         hf = OpenFile32("reg.dat",&ofs,OF_READ);
1577         if (hf==HFILE_ERROR32)
1578                 return;
1579
1580         /* read & dump header */
1581         if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1582                 ERR(reg, "reg.dat is too short.\n");
1583                 _lclose32(hf);
1584                 return;
1585         }
1586         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1587                 ERR(reg, "reg.dat has bad signature.\n");
1588                 _lclose32(hf);
1589                 return;
1590         }
1591
1592         len = head.tabcnt * sizeof(struct _w31_tabent);
1593         /* read and dump index table */
1594         tab = xmalloc(len);
1595         if (len!=_lread32(hf,tab,len)) {
1596                 ERR(reg,"couldn't read %d bytes.\n",len); 
1597                 free(tab);
1598                 _lclose32(hf);
1599                 return;
1600         }
1601
1602         /* read text */
1603         txt = xmalloc(head.textsize);
1604         if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1605                 ERR(reg,"couldn't seek to textblock.\n"); 
1606                 free(tab);
1607                 free(txt);
1608                 _lclose32(hf);
1609                 return;
1610         }
1611         if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1612                 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize); 
1613                 free(tab);
1614                 free(txt);
1615                 _lclose32(hf);
1616                 return;
1617         }
1618
1619         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1620                 ERR(reg,"GetFileInformationByHandle failed?.\n"); 
1621                 free(tab);
1622                 free(txt);
1623                 _lclose32(hf);
1624                 return;
1625         }
1626         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1627         lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1628         __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1629         free(tab);
1630         free(txt);
1631         _lclose32(hf);
1632         return;
1633 }
1634
1635
1636 /**********************************************************************************
1637  * SHELL_LoadRegistry [Internal]
1638  */
1639 void SHELL_LoadRegistry( void )
1640 {
1641         char    *fn;
1642         struct  passwd  *pwd;
1643         LPKEYSTRUCT     lpkey;
1644         HKEY            hkey;
1645
1646         TRACE(reg,"(void)\n");
1647
1648         /* Load windows 3.1 entries */
1649         _w31_loadreg();
1650         /* Load windows 95 entries */
1651         _w95_loadreg("C:\\system.1st",  lookup_hkey(HKEY_LOCAL_MACHINE));
1652         _w95_loadreg("system.dat",      lookup_hkey(HKEY_LOCAL_MACHINE));
1653         _w95_loadreg("user.dat",        lookup_hkey(HKEY_USERS));
1654
1655         /* the global user default is loaded under HKEY_USERS\\.Default */
1656         RegCreateKey16(HKEY_USERS,".Default",&hkey);
1657         lpkey = lookup_hkey(hkey);
1658         if(!lpkey)
1659             WARN(reg,"Could not create global user default key\n");
1660         _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1661
1662         /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1663         _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1664         RegCloseKey(hkey);
1665
1666         /* the global machine defaults */
1667         _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1668
1669         /* load the user saved registries */
1670
1671         /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1672
1673         pwd=getpwuid(getuid());
1674         if (pwd!=NULL && pwd->pw_dir!=NULL) {
1675                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1676                 strcpy(fn,pwd->pw_dir);
1677                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1678                 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1679                 free(fn);
1680                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1681                 strcpy(fn,pwd->pw_dir);
1682                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1683                 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1684                 free(fn);
1685         } else
1686                 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1687         if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1688                 DWORD   junk,type,len;
1689                 char    data[5];
1690
1691                 len=4;
1692                 if ((   RegQueryValueEx32A(
1693                                 hkey,
1694                                 VAL_SAVEUPDATED,
1695                                 &junk,
1696                                 &type,
1697                                 data,
1698                                 &len
1699                         )!=ERROR_SUCCESS) ||
1700                         type != REG_SZ
1701                 )
1702                         RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1703                 RegCloseKey(hkey);
1704         }
1705 }
1706
1707
1708 /********************* API FUNCTIONS ***************************************/
1709 /*
1710  * Open Keys.
1711  *
1712  * All functions are stubs to RegOpenKeyEx32W where all the
1713  * magic happens. 
1714  *
1715  * Callpath:
1716  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1717  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
1718  */
1719
1720
1721 /******************************************************************************
1722  * RegOpenKeyEx32W [ADVAPI32.150]
1723  * Opens the specified key
1724  *
1725  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1726  *
1727  * PARAMS
1728  *    hkey       [I] Handle of open key
1729  *    lpszSubKey [I] Name of subkey to open
1730  *    dwReserved [I] Reserved - must be zero
1731  *    samDesired [I] Security access mask
1732  *    retkey     [O] Address of handle of open key
1733  *
1734  * RETURNS
1735  *    Success: ERROR_SUCCESS
1736  *    Failure: Error code
1737  */
1738 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1739                               REGSAM samDesired, LPHKEY retkey )
1740 {
1741         LPKEYSTRUCT     lpNextKey,lpxkey;
1742         LPWSTR          *wps;
1743         int             wpc,i;
1744
1745     TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1746           samDesired,retkey);
1747
1748     lpNextKey = lookup_hkey( hkey );
1749     if (!lpNextKey)
1750         return ERROR_INVALID_HANDLE;
1751
1752     if (!lpszSubKey || !*lpszSubKey) {
1753         /* Either NULL or pointer to empty string, so return a new handle
1754            to the original hkey */
1755         currenthandle += 2;
1756         add_handle(currenthandle,lpNextKey,samDesired);
1757         *retkey=currenthandle;
1758         return ERROR_SUCCESS;
1759     }
1760
1761     if (lpszSubKey[0] == '\\') {
1762         WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1763         return ERROR_BAD_PATHNAME;
1764     }
1765
1766         split_keypath(lpszSubKey,&wps,&wpc);
1767         i = 0;
1768         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1769         lpxkey = lpNextKey;
1770
1771     while (wps[i]) {
1772         lpxkey=lpNextKey->nextsub;
1773         while (lpxkey) {
1774             if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1775                 break;
1776             }
1777             lpxkey=lpxkey->next;
1778         }
1779
1780         if (!lpxkey) {
1781             TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1782             FREE_KEY_PATH;
1783             return ERROR_FILE_NOT_FOUND;
1784         }
1785         i++;
1786         lpNextKey = lpxkey;
1787     }
1788
1789     currenthandle += 2;
1790     add_handle(currenthandle,lpxkey,samDesired);
1791     *retkey = currenthandle;
1792     TRACE(reg,"  Returning %x\n", currenthandle);
1793     FREE_KEY_PATH;
1794     return ERROR_SUCCESS;
1795 }
1796
1797
1798 /******************************************************************************
1799  * RegOpenKeyEx32A [ADVAPI32.149]
1800  */
1801 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1802                               REGSAM samDesired, LPHKEY retkey )
1803 {
1804     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1805     DWORD ret;
1806
1807     TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1808           samDesired,retkey);
1809     ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1810     free(lpszSubKeyW);
1811     return ret;
1812 }
1813
1814
1815 /******************************************************************************
1816  * RegOpenKey32W [ADVAPI32.151]
1817  *
1818  * PARAMS
1819  *    hkey       [I] Handle of open key
1820  *    lpszSubKey [I] Address of name of subkey to open
1821  *    retkey     [O] Address of handle of open key
1822  *
1823  * RETURNS
1824  *    Success: ERROR_SUCCESS
1825  *    Failure: Error code
1826  */
1827 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1828 {
1829     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1830     return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1831 }
1832
1833
1834 /******************************************************************************
1835  * RegOpenKey32A [ADVAPI32.148]
1836  */
1837 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1838 {
1839     DWORD ret;
1840     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1841     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1842     ret =  RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1843     free(lpszSubKeyW);
1844     return ret;
1845 }
1846
1847
1848 /******************************************************************************
1849  * RegOpenKey16 [SHELL.1] [KERNEL.217]
1850  */
1851 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1852 {
1853     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1854     return RegOpenKey32A( hkey, lpszSubKey, retkey );
1855 }
1856
1857
1858 /* 
1859  * Create keys
1860  * 
1861  * All those functions convert their respective 
1862  * arguments and call RegCreateKeyExW at the end.
1863  *
1864  * We stay away from the Ex functions as long as possible because there are
1865  * differences in the return values
1866  *
1867  * Callpath:
1868  *                                      RegCreateKeyEx32A \
1869  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W   -> RegCreateKeyEx32W
1870  */
1871
1872
1873 /******************************************************************************
1874  * RegCreateKeyEx32W [ADVAPI32.131]
1875  *
1876  * PARAMS
1877  *    hkey         [I] Handle of an open key
1878  *    lpszSubKey   [I] Address of subkey name
1879  *    dwReserved   [I] Reserved - must be 0
1880  *    lpszClass    [I] Address of class string
1881  *    fdwOptions   [I] Special options flag
1882  *    samDesired   [I] Desired security access
1883  *    lpSecAttribs [I] Address of key security structure
1884  *    retkey       [O] Address of buffer for opened handle
1885  *    lpDispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1886  */
1887 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, 
1888                                 DWORD dwReserved, LPWSTR lpszClass, 
1889                                 DWORD fdwOptions, REGSAM samDesired,
1890                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
1891                                 LPHKEY retkey, LPDWORD lpDispos )
1892 {
1893         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1894         LPWSTR          *wps;
1895         int             wpc,i;
1896
1897     TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1898                 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1899                 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1900
1901     lpNextKey = lookup_hkey(hkey);
1902     if (!lpNextKey)
1903         return ERROR_INVALID_HANDLE;
1904
1905     /* Check for valid options */
1906     switch(fdwOptions) {
1907         case REG_OPTION_NON_VOLATILE:
1908         case REG_OPTION_VOLATILE:
1909         case REG_OPTION_BACKUP_RESTORE:
1910             break;
1911         default:
1912             return ERROR_INVALID_PARAMETER;
1913     }
1914
1915     /* Sam has to be a combination of the following */
1916     if (!(samDesired & 
1917           (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY | 
1918            KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1919            KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1920         return ERROR_INVALID_PARAMETER;
1921
1922         if (!lpszSubKey || !*lpszSubKey) {
1923                 currenthandle += 2;
1924                 add_handle(currenthandle,lpNextKey,samDesired);
1925                 *retkey=currenthandle;
1926                 TRACE(reg, "Returning %x\n", currenthandle);
1927                 lpNextKey->flags|=REG_OPTION_TAINTED;
1928                 return ERROR_SUCCESS;
1929         }
1930
1931     if (lpszSubKey[0] == '\\') {
1932         WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1933         return ERROR_BAD_PATHNAME;
1934     }
1935
1936         split_keypath(lpszSubKey,&wps,&wpc);
1937         i       = 0;
1938         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1939         lpxkey  = lpNextKey;
1940         while (wps[i]) {
1941                 lpxkey=lpNextKey->nextsub;
1942                 while (lpxkey) {
1943                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1944                                 break;
1945                         lpxkey=lpxkey->next;
1946                 }
1947                 if (!lpxkey)
1948                         break;
1949                 i++;
1950                 lpNextKey       = lpxkey;
1951         }
1952         if (lpxkey) {
1953                 currenthandle += 2;
1954                 add_handle(currenthandle,lpxkey,samDesired);
1955                 lpxkey->flags  |= REG_OPTION_TAINTED;
1956                 *retkey         = currenthandle;
1957                 TRACE(reg, "Returning %x\n", currenthandle);
1958                 if (lpDispos)
1959                         *lpDispos       = REG_OPENED_EXISTING_KEY;
1960                 FREE_KEY_PATH;
1961                 return ERROR_SUCCESS;
1962         }
1963
1964         /* Good.  Now the hard part */
1965         while (wps[i]) {
1966                 lplpPrevKey     = &(lpNextKey->nextsub);
1967                 lpxkey          = *lplpPrevKey;
1968                 while (lpxkey) {
1969                         lplpPrevKey     = &(lpxkey->next);
1970                         lpxkey          = *lplpPrevKey;
1971                 }
1972                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1973                 if (!*lplpPrevKey) {
1974                         FREE_KEY_PATH;
1975                         TRACE(reg, "Returning OUTOFMEMORY\n");
1976                         return ERROR_OUTOFMEMORY;
1977                 }
1978                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1979                 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
1980                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1981                 (*lplpPrevKey)->next    = NULL;
1982                 (*lplpPrevKey)->nextsub = NULL;
1983                 (*lplpPrevKey)->values  = NULL;
1984                 (*lplpPrevKey)->nrofvalues = 0;
1985                 (*lplpPrevKey)->flags   = REG_OPTION_TAINTED;
1986                 if (lpszClass)
1987                         (*lplpPrevKey)->class = strdupW(lpszClass);
1988                 else
1989                         (*lplpPrevKey)->class = NULL;
1990                 lpNextKey       = *lplpPrevKey;
1991                 i++;
1992         }
1993         currenthandle += 2;
1994         add_handle(currenthandle,lpNextKey,samDesired);
1995
1996         /*FIXME: flag handling correct? */
1997         lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1998         if (lpszClass)
1999                 lpNextKey->class = strdupW(lpszClass);
2000         else
2001                 lpNextKey->class = NULL;
2002         *retkey         = currenthandle;
2003         TRACE(reg, "Returning %x\n", currenthandle);
2004         if (lpDispos)
2005                 *lpDispos       = REG_CREATED_NEW_KEY;
2006         FREE_KEY_PATH;
2007         return ERROR_SUCCESS;
2008 }
2009
2010
2011 /******************************************************************************
2012  * RegCreateKeyEx32A [ADVAPI32.130]
2013  */
2014 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2015                                 LPSTR lpszClass, DWORD fdwOptions, 
2016                                 REGSAM samDesired, 
2017                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
2018                                 LPHKEY retkey, LPDWORD lpDispos )
2019 {
2020     LPWSTR lpszSubKeyW, lpszClassW;
2021     DWORD  ret;
2022
2023     TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2024           dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2025           retkey,lpDispos);
2026
2027     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2028     lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2029
2030     ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW, 
2031                              fdwOptions, samDesired, lpSecAttribs, retkey, 
2032                              lpDispos );
2033
2034     if(lpszSubKeyW) free(lpszSubKeyW);
2035     if(lpszClassW) free(lpszClassW);
2036
2037     return ret;
2038 }
2039
2040
2041 /******************************************************************************
2042  * RegCreateKey32W [ADVAPI32.132]
2043  */
2044 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2045 {
2046     DWORD junk;
2047     LPKEYSTRUCT lpNextKey;
2048
2049     TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2050
2051     /* This check is here because the return value is different than the
2052        one from the Ex functions */
2053     lpNextKey = lookup_hkey(hkey);
2054     if (!lpNextKey)
2055         return ERROR_BADKEY;
2056
2057     return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL, 
2058                               REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2059                               retkey, &junk);
2060 }
2061
2062
2063 /******************************************************************************
2064  * RegCreateKey32A [ADVAPI32.129]
2065  */
2066 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2067 {
2068     DWORD ret;
2069     LPWSTR lpszSubKeyW;
2070
2071     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2072     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2073     ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2074     if(lpszSubKeyW) free(lpszSubKeyW);
2075     return ret;
2076 }
2077
2078
2079 /******************************************************************************
2080  * RegCreateKey16 [SHELL.2] [KERNEL.218]
2081  */
2082 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2083 {
2084     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2085     return RegCreateKey32A( hkey, lpszSubKey, retkey );
2086 }
2087
2088
2089 /* 
2090  * Query Value Functions
2091  * Win32 differs between keynames and valuenames. 
2092  * multiple values may belong to one key, the special value
2093  * with name NULL is the default value used by the win31
2094  * compat functions.
2095  *
2096  * Callpath:
2097  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2098  *                                        RegQueryValue32W -> RegQueryValueEx32W
2099  */
2100
2101
2102 /******************************************************************************
2103  * RegQueryValueEx32W [ADVAPI32.158]
2104  * Retrieves type and data for a specified name associated with an open key
2105  *
2106  * PARAMS
2107  *    hkey          [I]   Handle of key to query
2108  *    lpValueName   [I]   Name of value to query
2109  *    lpdwReserved  [I]   Reserved - must be NULL
2110  *    lpdwType      [O]   Address of buffer for value type.  If NULL, the type
2111  *                        is not required.
2112  *    lpbData       [O]   Address of data buffer.  If NULL, the actual data is
2113  *                        not required.
2114  *    lpcbData      [I/O] Address of data buffer size
2115  *
2116  * RETURNS 
2117  *    ERROR_SUCCESS:   Success
2118  *    ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2119  */
2120 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2121                                  LPDWORD lpdwReserved, LPDWORD lpdwType,
2122                                  LPBYTE lpbData, LPDWORD lpcbData )
2123 {
2124         LPKEYSTRUCT     lpkey;
2125         int             i;
2126
2127     TRACE(reg,"(0x%x,%s,%p,%p,%p,%ld)\n", hkey, debugstr_w(lpValueName),
2128           lpdwReserved, lpdwType, lpbData, lpcbData?*lpcbData:0);
2129
2130     lpkey = lookup_hkey(hkey);
2131     if (!lpkey)
2132         return ERROR_INVALID_HANDLE;
2133
2134     /* Reserved must be NULL (at least for now) */
2135     if (lpdwReserved)
2136         return ERROR_INVALID_PARAMETER;
2137
2138     /* An empty name string is equivalent to NULL */
2139     if (lpValueName && !*lpValueName)
2140         lpValueName = NULL;
2141
2142         if (lpValueName==NULL) {
2143                 /* Use key's unnamed or default value, if any */
2144                 for (i=0;i<lpkey->nrofvalues;i++)
2145                         if (lpkey->values[i].name==NULL)
2146                                 break;
2147         } else {
2148                 /* Search for the key name */
2149                 for (i=0;i<lpkey->nrofvalues;i++)
2150                         if (    lpkey->values[i].name &&
2151                                 !lstrcmpi32W(lpValueName,lpkey->values[i].name)
2152                         )
2153                                 break;
2154         }
2155
2156         if (i==lpkey->nrofvalues) {
2157                 TRACE(reg,"Key not found\n");
2158                 if (lpValueName==NULL) {
2159                         /* Empty keyname not found */
2160                         if (lpbData) {
2161                                 *(WCHAR*)lpbData = 0;
2162                                 *lpcbData       = 2;
2163                         }
2164                         if (lpdwType)
2165                                 *lpdwType       = REG_SZ;
2166                         TRACE(reg, "Returning an empty string\n");
2167                         return ERROR_SUCCESS;
2168                 }
2169                 return ERROR_BAD_PATHNAME;
2170         }
2171
2172     if (lpdwType)
2173         *lpdwType = lpkey->values[i].type;
2174
2175     if (lpbData==NULL) {
2176         /* Data is not required */
2177         if (lpcbData==NULL) {
2178             /* And data size is not required */
2179             /* So all that is returned is the type (set above) */
2180             return ERROR_SUCCESS;
2181         }
2182         /* Set the size required and return success */
2183         *lpcbData = lpkey->values[i].len;
2184         return ERROR_SUCCESS;
2185     }
2186
2187     if (*lpcbData<lpkey->values[i].len) {
2188         /* The size was specified, but the data is too big for it */
2189         /* Instead of setting it to NULL, fill in with as much as possible */
2190         /* But the docs do not specify how to handle the lpbData here */
2191         /* *(WCHAR*)lpbData= 0; */
2192         memcpy(lpbData,lpkey->values[i].data,*lpcbData);
2193         *lpcbData = lpkey->values[i].len;
2194         return ERROR_MORE_DATA;
2195     }
2196
2197     memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2198
2199     /* Extra debugging output */
2200     if (lpdwType) {
2201         switch(*lpdwType){
2202             case REG_SZ:
2203                 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
2204                 break;
2205             case REG_DWORD:
2206                 TRACE(reg," Data(dword)=%lx\n", (DWORD)*lpbData);
2207                 break;
2208             case REG_BINARY:
2209                 TRACE(reg," Data(binary)\n");
2210                 /* Is there a way of printing this in readable form? */
2211                 break;
2212             default:
2213                 TRACE(reg, "Unknown data type %ld\n", *lpdwType);
2214         } /* switch */
2215     } /* if */
2216
2217     /* Set the actual size */
2218     *lpcbData = lpkey->values[i].len;
2219     return ERROR_SUCCESS;
2220 }
2221
2222
2223 /******************************************************************************
2224  * RegQueryValue32W [ADVAPI32.159]
2225  */
2226 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2227                                LPDWORD lpcbData )
2228 {
2229         HKEY    xhkey;
2230         DWORD   ret,lpdwType;
2231
2232     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2233           lpcbData?*lpcbData:0);
2234
2235     /* Only open subkey, if we really do descend */
2236     if (lpszSubKey && *lpszSubKey) {
2237         ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2238         if (ret != ERROR_SUCCESS) {
2239             WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2240             return ret;
2241         }
2242     } else
2243         xhkey = hkey;
2244
2245     lpdwType = REG_SZ;
2246     ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2247                               lpcbData );
2248     if (xhkey != hkey)
2249         RegCloseKey(xhkey);
2250     return ret;
2251 }
2252
2253
2254 /******************************************************************************
2255  * RegQueryValueEx32A [ADVAPI32.157]
2256  */
2257 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2258                                  LPDWORD lpdwReserved, LPDWORD lpdwType,
2259                                  LPBYTE lpbData, LPDWORD lpcbData )
2260 {
2261         LPWSTR  lpszValueNameW;
2262         LPBYTE  buf;
2263         DWORD   ret,myxlen;
2264         DWORD   *mylen;
2265         DWORD   type;
2266
2267     TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey,debugstr_a(lpszValueName),
2268           lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2269
2270     lpszValueNameW = lpszValueName?strdupA2W(lpszValueName):NULL;
2271
2272     /* Why would this be set? It is just an output */
2273     if (lpdwType)
2274         type = *lpdwType;
2275
2276         if (lpbData) {
2277                 myxlen  = 0;
2278                 mylen   = &myxlen;
2279                 buf     = xmalloc(4);
2280                 /* Only get the size for now */
2281                 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved,
2282                                           &type, buf, mylen );
2283                 free(buf);
2284                 if (ret==ERROR_MORE_DATA) {
2285                         buf     = (LPBYTE)xmalloc(*mylen);
2286                 } else {
2287                         buf     = (LPBYTE)xmalloc(2*(*lpcbData));
2288                         myxlen  = 2*(*lpcbData);
2289                 }
2290         } else {
2291                 /* Data is not required */
2292                 buf=NULL;
2293                 if (lpcbData) {
2294                         myxlen  = *lpcbData*2;
2295                         mylen   = &myxlen;
2296                 } else
2297                         mylen   = NULL;
2298         }
2299
2300         /* Now get the data */
2301         ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &type,
2302                                   buf, mylen );
2303         if (lpdwType) 
2304                 *lpdwType=type;
2305
2306         if (ret==ERROR_SUCCESS) {
2307                 if (buf) {
2308                         if (UNICONVMASK & (1<<(type))) {
2309                                 /* convert UNICODE to ASCII */
2310                                 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2311                                 *lpcbData       = myxlen/2;
2312                         } else {
2313                                 if (myxlen>*lpcbData)
2314                                         ret     = ERROR_MORE_DATA;
2315                                 else
2316                                         memcpy(lpbData,buf,myxlen);
2317
2318                                 *lpcbData       = myxlen;
2319                         }
2320                 } else {
2321                         if ((UNICONVMASK & (1<<(type))) && lpcbData)
2322                                 *lpcbData       = myxlen/2;
2323                 }
2324         } else {
2325                 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2326                         *lpcbData       = myxlen/2;
2327         }
2328
2329     if(buf) free(buf);
2330     if(lpszValueNameW) free(lpszValueNameW);
2331     return ret;
2332 }
2333
2334
2335 /******************************************************************************
2336  * RegQueryValueEx16 [KERNEL.225]
2337  */
2338 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2339                                 LPDWORD lpdwReserved, LPDWORD lpdwType,
2340                                 LPBYTE lpbData, LPDWORD lpcbData )
2341 {
2342     TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2343           lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2344     return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2345                                lpbData, lpcbData );
2346 }
2347
2348
2349 /******************************************************************************
2350  * RegQueryValue32A [ADVAPI32.156]
2351  */
2352 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2353                                LPDWORD lpcbData )
2354 {
2355     HKEY xhkey;
2356     DWORD ret, dwType;
2357
2358     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2359           lpcbData?*lpcbData:0);
2360
2361     if (lpszSubKey && *lpszSubKey) {
2362         ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2363         if( ret != ERROR_SUCCESS )
2364             return ret;
2365     } else
2366         xhkey = hkey;
2367
2368     dwType = REG_SZ;
2369     ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2370                               lpcbData );
2371     if( xhkey != hkey )
2372         RegCloseKey( xhkey );
2373     return ret;
2374 }
2375
2376
2377 /******************************************************************************
2378  * RegQueryValue16 [SHELL.6] [KERNEL.224]
2379  *
2380  * NOTES
2381  *    Is this HACK still applicable?
2382  *
2383  * HACK
2384  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2385  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
2386  *    Aldus FH4)
2387  */
2388 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2389                               LPDWORD lpcbData )
2390 {
2391     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2392           lpcbData?*lpcbData:0);
2393
2394     if (lpcbData)
2395         *lpcbData &= 0xFFFF;
2396     return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2397 }
2398
2399
2400 /*
2401  * Setting values of Registry keys
2402  *
2403  * Callpath:
2404  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2405  *                                    RegSetValue32W   -> RegSetValueEx32W
2406  */
2407
2408
2409 /******************************************************************************
2410  * RegSetValueEx32W [ADVAPI32.170]
2411  * Sets the data and type of a value under a register key
2412  *
2413  * PARAMS
2414  *    hkey          [I] Handle of key to set value for
2415  *    lpszValueName [I] Name of value to set
2416  *    dwReserved    [I] Reserved - must be zero
2417  *    dwType        [I] Flag for value type
2418  *    lpbData       [I] Address of value data
2419  *    cbData        [I] Size of value data
2420  *
2421  * RETURNS
2422  *    Success: ERROR_SUCCESS
2423  *    Failure: Error code
2424  */
2425 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName, 
2426                                DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2427                                DWORD cbData)
2428 {
2429     LPKEYSTRUCT lpkey;
2430     int i;
2431
2432     TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2433           dwReserved, dwType, lpbData, cbData);
2434
2435     switch (dwType) {
2436         case REG_SZ:
2437             TRACE(reg," Data(sz)=%s\n", debugstr_w((LPCWSTR)lpbData));
2438             break;
2439         case REG_BINARY:
2440             TRACE(reg," Data(binary)\n");
2441             break;
2442         case REG_DWORD:
2443             TRACE(reg," Data(dword)=%lx\n", (DWORD)lpbData);
2444             break;
2445         default:
2446             TRACE(reg,"Unknown type: %ld\n", dwType);
2447     }
2448
2449     lpkey = lookup_hkey( hkey );
2450     if (!lpkey)
2451         return ERROR_INVALID_HANDLE;
2452
2453         lpkey->flags |= REG_OPTION_TAINTED;
2454
2455         if (lpszValueName==NULL) {
2456              /* Sets type and name for key's unnamed or default value */
2457                 for (i=0;i<lpkey->nrofvalues;i++)
2458                         if (lpkey->values[i].name==NULL)
2459                                 break;
2460         } else {
2461                 for (i=0;i<lpkey->nrofvalues;i++)
2462                         if (    lpkey->values[i].name &&
2463                                 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2464                         )
2465                                 break;
2466         }
2467         if (i==lpkey->nrofvalues) {
2468                 lpkey->values = (LPKEYVALUE)xrealloc(
2469                                         lpkey->values,
2470                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2471                                 );
2472                 lpkey->nrofvalues++;
2473                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2474         }
2475         if (lpkey->values[i].name==NULL) {
2476                 if (lpszValueName)
2477                         lpkey->values[i].name = strdupW(lpszValueName);
2478                 else
2479                         lpkey->values[i].name = NULL;
2480         }
2481         lpkey->values[i].len    = cbData;
2482         lpkey->values[i].type   = dwType;
2483         if (lpkey->values[i].data !=NULL)
2484                 free(lpkey->values[i].data);
2485         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
2486         lpkey->values[i].lastmodified = time(NULL);
2487         memcpy(lpkey->values[i].data,lpbData,cbData);
2488         return ERROR_SUCCESS;
2489 }
2490
2491
2492 /******************************************************************************
2493  * RegSetValueEx32A [ADVAPI32.169]
2494  *
2495  */
2496 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2497                                DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2498                                DWORD cbData )
2499 {
2500         LPBYTE  buf;
2501         LPWSTR  lpszValueNameW;
2502         DWORD   ret;
2503
2504     TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2505           dwReserved,dwType,lpbData,cbData);
2506
2507         if ((1<<dwType) & UNICONVMASK) {
2508                 buf=(LPBYTE)strdupA2W(lpbData);
2509                 cbData=2*strlen(lpbData)+2;
2510         } else
2511                 buf=lpbData;
2512         if (lpszValueName)
2513                 lpszValueNameW = strdupA2W(lpszValueName);
2514         else
2515                 lpszValueNameW = NULL;
2516         ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2517         if (lpszValueNameW)
2518                 free(lpszValueNameW);
2519         if (buf!=lpbData)
2520                 free(buf);
2521         return ret;
2522 }
2523
2524
2525 /******************************************************************************
2526  * RegSetValueEx16 [KERNEL.226]
2527  */
2528 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2529                               DWORD dwType, LPBYTE lpbData, DWORD cbData )
2530 {
2531     TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2532           dwReserved,dwType,lpbData,cbData);
2533     return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2534                              cbData );
2535 }
2536
2537
2538 /******************************************************************************
2539  * RegSetValue32W       [ADVAPI32.171]
2540  */
2541 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2542                              LPCWSTR lpszData, DWORD cbData )
2543 {
2544         HKEY    xhkey;
2545         DWORD   ret;
2546
2547         TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2548                 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2549         );
2550         if (lpszSubKey && *lpszSubKey) {
2551                 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2552                 if (ret!=ERROR_SUCCESS)
2553                         return ret;
2554         } else
2555                 xhkey=hkey;
2556         if (dwType!=REG_SZ) {
2557                 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2558                 dwType=REG_SZ;
2559         }
2560         if (cbData!=2*lstrlen32W(lpszData)+2) {
2561                 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2562                         cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2563                 );
2564                 cbData=2*lstrlen32W(lpszData)+2;
2565         }
2566         ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2567         if (hkey!=xhkey)
2568                 RegCloseKey(xhkey);
2569         return ret;
2570 }
2571
2572
2573 /******************************************************************************
2574  * RegSetValue32A [ADVAPI32.168]
2575  *
2576  */
2577 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2578                              LPCSTR lpszData, DWORD cbData )
2579 {
2580         DWORD   ret;
2581         HKEY    xhkey;
2582
2583         TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2584         if (lpszSubKey && *lpszSubKey) {
2585                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2586                 if (ret!=ERROR_SUCCESS)
2587                         return ret;
2588         } else
2589                 xhkey=hkey;
2590
2591         if (dwType!=REG_SZ) {
2592                 TRACE(reg,"dwType=%ld!\n",dwType);
2593                 dwType=REG_SZ;
2594         }
2595         if (cbData!=strlen(lpszData)+1)
2596                 cbData=strlen(lpszData)+1;
2597         ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2598         if (xhkey!=hkey)
2599                 RegCloseKey(xhkey);
2600         return ret;
2601 }
2602
2603
2604 /******************************************************************************
2605  * RegSetValue16 [KERNEL.221] [SHELL.5]
2606  */
2607 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2608                             LPCSTR lpszData, DWORD cbData )
2609 {
2610     TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2611           debugstr_a(lpszData),cbData);
2612     return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2613 }
2614
2615
2616 /* 
2617  * Key Enumeration
2618  *
2619  * Callpath:
2620  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2621  *                                  RegEnumKey32W   -> RegEnumKeyEx32W
2622  */
2623
2624
2625 /******************************************************************************
2626  * RegEnumKeyEx32W [ADVAPI32.139]
2627  *
2628  * PARAMS
2629  *    hkey         [I] Handle to key to enumerate
2630  *    iSubKey      [I] Index of subkey to enumerate
2631  *    lpszName     [O] Buffer for subkey name
2632  *    lpcchName    [O] Size of subkey buffer
2633  *    lpdwReserved [I] Reserved
2634  *    lpszClass    [O] Buffer for class string
2635  *    lpcchClass   [O] Size of class buffer
2636  *    ft           [O] Time key last written to
2637  */
2638 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2639                               LPDWORD lpcchName, LPDWORD lpdwReserved,
2640                               LPWSTR lpszClass, LPDWORD lpcchClass, 
2641                               FILETIME *ft )
2642 {
2643         LPKEYSTRUCT     lpkey,lpxkey;
2644
2645     TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2646           *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2647
2648     lpkey = lookup_hkey( hkey );
2649     if (!lpkey)
2650         return ERROR_INVALID_HANDLE;
2651
2652         if (!lpkey->nextsub)
2653                 return ERROR_NO_MORE_ITEMS;
2654         lpxkey=lpkey->nextsub;
2655
2656     /* Traverse the subkeys */
2657         while (iSubkey && lpxkey) {
2658                 iSubkey--;
2659                 lpxkey=lpxkey->next;
2660         }
2661
2662         if (iSubkey || !lpxkey)
2663                 return ERROR_NO_MORE_ITEMS;
2664         if (lstrlen32W(lpxkey->keyname)+1>*lpcchName)
2665                 return ERROR_MORE_DATA;
2666         memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2667
2668         if (*lpcchName)
2669             *lpcchName = lstrlen32W(lpszName);
2670
2671         if (lpszClass) {
2672                 /* FIXME: what should we write into it? */
2673                 *lpszClass      = 0;
2674                 *lpcchClass     = 2;
2675         }
2676         return ERROR_SUCCESS;
2677 }
2678
2679
2680 /******************************************************************************
2681  * RegEnumKey32W [ADVAPI32.140]
2682  */
2683 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, 
2684                             DWORD lpcchName )
2685 {
2686     FILETIME    ft;
2687
2688     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2689     return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2690 }
2691
2692
2693 /******************************************************************************
2694  * RegEnumKeyEx32A [ADVAPI32.138]
2695  */
2696 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2697                               LPDWORD lpcchName, LPDWORD lpdwReserved, 
2698                               LPSTR lpszClass, LPDWORD lpcchClass, 
2699                               FILETIME *ft )
2700 {
2701         DWORD   ret,lpcchNameW,lpcchClassW;
2702         LPWSTR  lpszNameW,lpszClassW;
2703
2704
2705         TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2706                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2707         );
2708         if (lpszName) {
2709                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
2710                 lpcchNameW      = *lpcchName;
2711         } else {
2712                 lpszNameW       = NULL;
2713                 lpcchNameW      = 0;
2714         }
2715         if (lpszClass) {
2716                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
2717                 lpcchClassW     = *lpcchClass;
2718         } else {
2719                 lpszClassW      =0;
2720                 lpcchClassW=0;
2721         }
2722         ret=RegEnumKeyEx32W(
2723                 hkey,
2724                 iSubkey,
2725                 lpszNameW,
2726                 &lpcchNameW,
2727                 lpdwReserved,
2728                 lpszClassW,
2729                 &lpcchClassW,
2730                 ft
2731         );
2732         if (ret==ERROR_SUCCESS) {
2733                 lstrcpyWtoA(lpszName,lpszNameW);
2734                 *lpcchName=strlen(lpszName);
2735                 if (lpszClassW) {
2736                         lstrcpyWtoA(lpszClass,lpszClassW);
2737                         *lpcchClass=strlen(lpszClass);
2738                 }
2739         }
2740         if (lpszNameW)
2741                 free(lpszNameW);
2742         if (lpszClassW)
2743                 free(lpszClassW);
2744         return ret;
2745 }
2746
2747
2748 /******************************************************************************
2749  * RegEnumKey32A [ADVAPI32.137]
2750  */
2751 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2752                             DWORD lpcchName )
2753 {
2754     FILETIME    ft;
2755
2756     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2757     return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL, 
2758                             NULL, &ft );
2759 }
2760
2761
2762 /******************************************************************************
2763  * RegEnumKey16 [SHELL.7] [KERNEL.216]
2764  */
2765 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2766                            DWORD lpcchName )
2767 {
2768     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2769     return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2770 }
2771
2772
2773 /* 
2774  * Enumerate Registry Values
2775  *
2776  * Callpath:
2777  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2778  */
2779
2780
2781 /******************************************************************************
2782  * RegEnumValue32W [ADVAPI32.142]
2783  *
2784  * PARAMS
2785  *    hkey        [I] Handle to key to query
2786  *    iValue      [I] Index of value to query
2787  *    lpszValue   [O] Value string
2788  *    lpcchValue  [O] Size of value buffer
2789  *    lpdReserved [I] Reserved
2790  *    lpdwType    [O] Type code
2791  *    lpbData     [O] Value data
2792  *    lpcbData    [O] Size of data buffer
2793  *
2794  * Note:  wide character functions that take and/or return "character counts"
2795  *  use TCHAR (that is unsigned short or char) not byte counts.
2796  */
2797 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2798                               LPDWORD lpcchValue, LPDWORD lpdReserved,
2799                               LPDWORD lpdwType, LPBYTE lpbData, 
2800                               LPDWORD lpcbData )
2801 {
2802         LPKEYSTRUCT     lpkey;
2803         LPKEYVALUE      val;
2804
2805     TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2806           lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2807
2808     lpkey = lookup_hkey( hkey );
2809     if (!lpkey)
2810         return ERROR_INVALID_HANDLE;
2811
2812     if (lpkey->nrofvalues <= iValue)
2813         return ERROR_NO_MORE_ITEMS;
2814
2815     /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2816     val = lpkey->values + iValue;
2817
2818         if (val->name) {
2819                 if (lstrlen32W(val->name)+1>*lpcchValue) {
2820                         *lpcchValue = lstrlen32W(val->name)+1;
2821                         return ERROR_MORE_DATA;
2822                 }
2823                 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2824                 *lpcchValue=lstrlen32W(val->name);
2825         } else {
2826                 *lpszValue      = 0;
2827                 *lpcchValue     = 0;
2828         }
2829
2830     /* Can be NULL if the type code is not required */
2831     if (lpdwType)
2832         *lpdwType = val->type;
2833
2834         if (lpbData) {
2835                 if (val->len>*lpcbData)
2836                         return ERROR_MORE_DATA;
2837                 memcpy(lpbData,val->data,val->len);
2838                 *lpcbData = val->len;
2839         }
2840         return ERROR_SUCCESS;
2841 }
2842
2843
2844 /******************************************************************************
2845  * RegEnumValue32A [ADVAPI32.141]
2846  */
2847 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2848                               LPDWORD lpcchValue, LPDWORD lpdReserved,
2849                               LPDWORD lpdwType, LPBYTE lpbData, 
2850                               LPDWORD lpcbData )
2851 {
2852         LPWSTR  lpszValueW;
2853         LPBYTE  lpbDataW;
2854         DWORD   ret,lpcbDataW;
2855         DWORD dwType;
2856
2857         TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2858                 lpdReserved,lpdwType,lpbData,lpcbData);
2859
2860         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2861         if (lpbData) {
2862                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2863                 lpcbDataW = *lpcbData;
2864         } else
2865                 lpbDataW = NULL;
2866
2867         ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue, 
2868                                 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2869
2870         if (lpdwType)
2871                 *lpdwType = dwType;
2872
2873         if (ret==ERROR_SUCCESS) {
2874                 lstrcpyWtoA(lpszValue,lpszValueW);
2875                 if (lpbData) {
2876                         if ((1<<dwType) & UNICONVMASK) {
2877                                 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2878                         } else {
2879                                 if (lpcbDataW > *lpcbData)
2880                                         ret     = ERROR_MORE_DATA;
2881                                 else
2882                                         memcpy(lpbData,lpbDataW,lpcbDataW);
2883                         }
2884                         *lpcbData = lpcbDataW;
2885                 }
2886         }
2887     if (lpbDataW) free(lpbDataW);
2888     if (lpszValueW) free(lpszValueW);
2889     return ret;
2890 }
2891
2892
2893 /******************************************************************************
2894  * RegEnumValue16 [KERNEL.223]
2895  */
2896 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue, 
2897                              LPDWORD lpcchValue, LPDWORD lpdReserved, 
2898                              LPDWORD lpdwType, LPBYTE lpbData, 
2899                              LPDWORD lpcbData )
2900 {
2901     TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2902           lpdReserved,lpdwType,lpbData,lpcbData);
2903     return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved, 
2904                             lpdwType, lpbData, lpcbData );
2905 }
2906
2907
2908 /******************************************************************************
2909  * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2910  * Releases the handle of the specified key
2911  *
2912  * PARAMS
2913  *    hkey [I] Handle of key to close
2914  *
2915  * RETURNS
2916  *    Success: ERROR_SUCCESS
2917  *    Failure: Error code
2918  */
2919 DWORD WINAPI RegCloseKey( HKEY hkey )
2920 {
2921     TRACE(reg,"(%x)\n",hkey);
2922
2923     /* The standard handles are allowed to succeed, even though they are not
2924        closed */
2925     if (is_standard_hkey(hkey))
2926         return ERROR_SUCCESS;
2927
2928     return remove_handle(hkey);
2929 }
2930
2931
2932 /* 
2933  * Delete registry key
2934  *
2935  * Callpath:
2936  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2937  */
2938
2939
2940 /******************************************************************************
2941  * RegDeleteKey32W [ADVAPI32.134]
2942  *
2943  * PARAMS
2944  *    hkey       [I] Handle to open key
2945  *    lpszSubKey [I] Name of subkey to delete
2946  *
2947  * RETURNS
2948  *    Success: ERROR_SUCCESS
2949  *    Failure: Error code
2950  */
2951 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
2952 {
2953         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
2954         LPWSTR          *wps;
2955         int             wpc,i;
2956
2957     TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
2958
2959     lpNextKey = lookup_hkey(hkey);
2960     if (!lpNextKey)
2961         return ERROR_INVALID_HANDLE;
2962
2963     /* Subkey param cannot be NULL */
2964     if (!lpszSubKey || !*lpszSubKey)
2965         return ERROR_BADKEY;
2966
2967     /* We need to know the previous key in the hier. */
2968         split_keypath(lpszSubKey,&wps,&wpc);
2969         i       = 0;
2970         lpxkey  = lpNextKey;
2971         while (i<wpc-1) {
2972                 lpxkey=lpNextKey->nextsub;
2973                 while (lpxkey) {
2974                         TRACE(reg, "  Scanning [%s]\n",
2975                                      debugstr_w(lpxkey->keyname));
2976                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2977                                 break;
2978                         lpxkey=lpxkey->next;
2979                 }
2980                 if (!lpxkey) {
2981                         FREE_KEY_PATH;
2982                         TRACE(reg, "  Not found.\n");
2983                         /* not found is success */
2984                         return ERROR_SUCCESS;
2985                 }
2986                 i++;
2987                 lpNextKey       = lpxkey;
2988         }
2989         lpxkey  = lpNextKey->nextsub;
2990         lplpPrevKey = &(lpNextKey->nextsub);
2991         while (lpxkey) {
2992                 TRACE(reg, "  Scanning [%s]\n",
2993                              debugstr_w(lpxkey->keyname));
2994                 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2995                         break;
2996                 lplpPrevKey     = &(lpxkey->next);
2997                 lpxkey          = lpxkey->next;
2998         }
2999
3000         if (!lpxkey) {
3001                 FREE_KEY_PATH;
3002                 WARN(reg , "  Not found.\n");
3003                 return ERROR_FILE_NOT_FOUND;
3004         }
3005
3006         if (lpxkey->nextsub) {
3007                 FREE_KEY_PATH;
3008                 WARN(reg , "  Not empty.\n");
3009                 return ERROR_CANTWRITE;
3010         }
3011         *lplpPrevKey    = lpxkey->next;
3012         free(lpxkey->keyname);
3013         if (lpxkey->class)
3014                 free(lpxkey->class);
3015         if (lpxkey->values)
3016                 free(lpxkey->values);
3017         free(lpxkey);
3018         FREE_KEY_PATH;
3019         TRACE(reg, "  Done.\n");
3020         return  ERROR_SUCCESS;
3021 }
3022
3023
3024 /******************************************************************************
3025  * RegDeleteKey32A [ADVAPI32.133]
3026  */
3027 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3028 {
3029     LPWSTR lpszSubKeyW;
3030     DWORD  ret;
3031
3032     TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3033     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3034     ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3035     if(lpszSubKeyW) free(lpszSubKeyW);
3036     return ret;
3037 }
3038
3039
3040 /******************************************************************************
3041  * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3042  */
3043 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3044 {
3045     TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3046     return RegDeleteKey32A( hkey, lpszSubKey );
3047 }
3048
3049
3050 /* 
3051  * Delete registry value
3052  *
3053  * Callpath:
3054  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3055  */
3056
3057
3058 /******************************************************************************
3059  * RegDeleteValue32W [ADVAPI32.136]
3060  *
3061  * PARAMS
3062  *    hkey      [I]
3063  *    lpszValue [I]
3064  *
3065  * RETURNS
3066  */
3067 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3068 {
3069         DWORD           i;
3070         LPKEYSTRUCT     lpkey;
3071         LPKEYVALUE      val;
3072
3073     TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3074
3075     lpkey = lookup_hkey( hkey );
3076     if (!lpkey)
3077         return ERROR_INVALID_HANDLE;
3078
3079         if (lpszValue) {
3080                 for (i=0;i<lpkey->nrofvalues;i++)
3081                         if (    lpkey->values[i].name &&
3082                                 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3083                         )
3084                                 break;
3085         } else {
3086                 for (i=0;i<lpkey->nrofvalues;i++)
3087                         if (lpkey->values[i].name==NULL)
3088                                 break;
3089         }
3090
3091     if (i == lpkey->nrofvalues)
3092         return ERROR_FILE_NOT_FOUND;
3093
3094         val     = lpkey->values+i;
3095         if (val->name) free(val->name);
3096         if (val->data) free(val->data);
3097         memcpy( 
3098                 lpkey->values+i,
3099                 lpkey->values+i+1,
3100                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3101         );
3102         lpkey->values   = (LPKEYVALUE)xrealloc(
3103                                 lpkey->values,
3104                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3105                         );
3106         lpkey->nrofvalues--;
3107         return ERROR_SUCCESS;
3108 }
3109
3110
3111 /******************************************************************************
3112  * RegDeleteValue32A [ADVAPI32.135]
3113  */
3114 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3115 {
3116     LPWSTR lpszValueW;
3117     DWORD  ret;
3118
3119     TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3120     lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3121     ret = RegDeleteValue32W( hkey, lpszValueW );
3122     if(lpszValueW) free(lpszValueW);
3123     return ret;
3124 }
3125
3126
3127 /******************************************************************************
3128  * RegDeleteValue16 [KERNEL.222]
3129  */
3130 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3131 {
3132     TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3133     return RegDeleteValue32A( hkey, lpszValue );
3134 }
3135
3136
3137 /******************************************************************************
3138  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3139  * Writes key to registry
3140  *
3141  * PARAMS
3142  *    hkey [I] Handle of key to write
3143  *
3144  * RETURNS
3145  *    Success: ERROR_SUCCESS
3146  *    Failure: Error code
3147  */
3148 DWORD WINAPI RegFlushKey( HKEY hkey )
3149 {
3150     LPKEYSTRUCT lpkey;
3151     BOOL32 ret;
3152
3153     TRACE(reg, "(%x)\n", hkey);
3154
3155     lpkey = lookup_hkey( hkey );
3156     if (!lpkey)
3157         return ERROR_INVALID_HANDLE;
3158
3159     ERR(reg, "What is the correct filename?\n");
3160
3161     ret = _savereg( lpkey, "foo.bar", TRUE);
3162
3163     if( ret ) {
3164         return ERROR_SUCCESS;
3165     } else
3166         return ERROR_UNKNOWN;  /* FIXME */
3167 }
3168
3169
3170 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3171
3172
3173 /******************************************************************************
3174  * RegQueryInfoKey32W [ADVAPI32.153]
3175  *
3176  * PARAMS
3177  *    hkey                   [I] Handle to key to query
3178  *    lpszClass              [O] Buffer for class string
3179  *    lpcchClass             [O] Size of class string buffer
3180  *    lpdwReserved           [I] Reserved
3181  *    lpcSubKeys             [I] Buffer for number of subkeys
3182  *    lpcchMaxSubKey         [O] Buffer for longest subkey name length
3183  *    lpcchMaxClass          [O] Buffer for longest class string length
3184  *    lpcValues              [O] Buffer for number of value entries
3185  *    lpcchMaxValueName      [O] Buffer for longest value name length
3186  *    lpccbMaxValueData      [O] Buffer for longest value data length
3187  *    lpcbSecurityDescriptor [O] Buffer for security descriptor length
3188  *    ft
3189  * - win95 allows lpszClass to be valid and lpcchClass to be NULL 
3190  * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3191  *   lpcchClass is NULL
3192  * - both allow lpszClass to be NULL and lpcchClass to be NULL 
3193  * (it's hard to test validity, so test !NULL instead)
3194  */
3195 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass, 
3196                                  LPDWORD lpcchClass, LPDWORD lpdwReserved,
3197                                  LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3198                                  LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3199                                  LPDWORD lpcchMaxValueName, 
3200                                  LPDWORD lpccbMaxValueData, 
3201                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3202 {
3203         LPKEYSTRUCT     lpkey,lpxkey;
3204         int             nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3205         int             i;
3206
3207         TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3208         lpkey = lookup_hkey(hkey);
3209         if (!lpkey)
3210                 return ERROR_INVALID_HANDLE;
3211         if (lpszClass) {
3212                 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3213                     return ERROR_INVALID_PARAMETER;
3214                 }
3215                 /* either lpcchClass is valid or this is win95 and lpcchClass
3216                    could be invalid */
3217                 if (lpkey->class) {
3218                         DWORD classLen = lstrlen32W(lpkey->class);
3219
3220                         if (lpcchClass && classLen+1>*lpcchClass) {
3221                                 *lpcchClass=classLen+1;
3222                                 return ERROR_MORE_DATA;
3223                         }
3224                         if (lpcchClass)
3225                             *lpcchClass=classLen;
3226                         memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3227                 } else {
3228                         *lpszClass      = 0;
3229                         if (lpcchClass)
3230                             *lpcchClass = 0;
3231                 }
3232         } else {
3233                 if (lpcchClass)
3234                         *lpcchClass     = lstrlen32W(lpkey->class);
3235         }
3236         lpxkey=lpkey->nextsub;
3237         nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3238         while (lpxkey) {
3239                 nrofkeys++;
3240                 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3241                         maxsubkey=lstrlen32W(lpxkey->keyname);
3242                 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3243                         maxclass=lstrlen32W(lpxkey->class);
3244                 lpxkey=lpxkey->next;
3245         }
3246         for (i=0;i<lpkey->nrofvalues;i++) {
3247                 LPKEYVALUE      val=lpkey->values+i;
3248
3249                 if (val->name && lstrlen32W(val->name)>maxvname)
3250                         maxvname=lstrlen32W(val->name);
3251                 if (val->len>maxvdata)
3252                         maxvdata=val->len;
3253         }
3254         if (!maxclass) maxclass = 1;
3255         if (!maxvname) maxvname = 1;
3256         if (lpcValues)
3257                 *lpcValues      = lpkey->nrofvalues;
3258         if (lpcSubKeys)
3259                 *lpcSubKeys     = nrofkeys;
3260         if (lpcchMaxSubkey)
3261                 *lpcchMaxSubkey = maxsubkey;
3262         if (lpcchMaxClass)
3263                 *lpcchMaxClass  = maxclass;
3264         if (lpcchMaxValueName)
3265                 *lpcchMaxValueName= maxvname;
3266         if (lpccbMaxValueData)
3267                 *lpccbMaxValueData= maxvdata;
3268         return ERROR_SUCCESS;
3269 }
3270
3271
3272 /******************************************************************************
3273  * RegQueryInfoKey32A [ADVAPI32.152]
3274  */
3275 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3276                                  LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3277                                  LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3278                                  LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3279                                  LPDWORD lpccbMaxValueData, 
3280                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3281 {
3282         LPWSTR          lpszClassW = NULL;
3283         DWORD           ret;
3284
3285         TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3286         if (lpszClass) {
3287                 if (lpcchClass) {
3288                     lpszClassW  = (LPWSTR)xmalloc((*lpcchClass) * 2);
3289                 } else if (VERSION_GetVersion() == WIN95) {
3290                     /* win95  allows lpcchClass to be null */
3291                     /* we don't know how big lpszClass is, would 
3292                        MAX_PATHNAME_LEN be the correct default? */
3293                     lpszClassW  = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2); 
3294                 }
3295
3296         } else
3297                 lpszClassW  = NULL;
3298         ret=RegQueryInfoKey32W(
3299                 hkey,
3300                 lpszClassW,
3301                 lpcchClass,
3302                 lpdwReserved,
3303                 lpcSubKeys,
3304                 lpcchMaxSubkey,
3305                 lpcchMaxClass,
3306                 lpcValues,
3307                 lpcchMaxValueName,
3308                 lpccbMaxValueData,
3309                 lpcbSecurityDescriptor,
3310                 ft
3311         );
3312         if (ret==ERROR_SUCCESS && lpszClass)
3313                 lstrcpyWtoA(lpszClass,lpszClassW);
3314         if (lpszClassW)
3315                 free(lpszClassW);
3316         return ret;
3317 }
3318
3319
3320 /******************************************************************************
3321  * RegConnectRegistry32W [ADVAPI32.128]
3322  *
3323  * PARAMS
3324  *    lpMachineName [I] Address of name of remote computer
3325  *    hHey          [I] Predefined registry handle
3326  *    phkResult     [I] Address of buffer for remote registry handle
3327  */
3328 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey, 
3329                                    LPHKEY phkResult )
3330 {
3331     TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3332
3333     if (!lpMachineName || !*lpMachineName) {
3334         /* Use the local machine name */
3335         return RegOpenKey16( hKey, "", phkResult );
3336     }
3337
3338     FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3339     return ERROR_BAD_NETPATH;
3340 }
3341
3342
3343 /******************************************************************************
3344  * RegConnectRegistry32A [ADVAPI32.127]
3345  */
3346 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3347 {
3348     DWORD ret;
3349     LPWSTR machineW = strdupA2W(machine);
3350     ret = RegConnectRegistry32W( machineW, hkey, reskey );
3351     free(machineW);
3352     return ret;
3353 }
3354
3355
3356 /******************************************************************************
3357  * RegGetKeySecurity [ADVAPI32.144]
3358  * Retrieves a copy of security descriptor protecting the registry key
3359  *
3360  * PARAMS
3361  *    hkey                   [I]   Open handle of key to set
3362  *    SecurityInformation    [I]   Descriptor contents
3363  *    pSecurityDescriptor    [O]   Address of descriptor for key
3364  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3365  *
3366  * RETURNS
3367  *    Success: ERROR_SUCCESS
3368  *    Failure: Error code
3369  */
3370 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
3371                                SECURITY_INFORMATION SecurityInformation,
3372                                LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3373                                LPDWORD lpcbSecurityDescriptor )
3374 {
3375     LPKEYSTRUCT lpkey;
3376
3377     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3378           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3379
3380     lpkey = lookup_hkey( hkey );
3381     if (!lpkey)
3382         return ERROR_INVALID_HANDLE;
3383
3384     /* FIXME: Check for valid SecurityInformation values */
3385
3386     if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3387         return ERROR_INSUFFICIENT_BUFFER;
3388
3389     FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3390           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3391
3392     return ERROR_SUCCESS;
3393 }
3394
3395
3396 /******************************************************************************
3397  * RegLoadKey32W [ADVAPI32.???]
3398  *
3399  * PARAMS
3400  *    hkey       [I] Handle of open key
3401  *    lpszSubKey [I] Address of name of subkey
3402  *    lpszFile   [I] Address of filename for registry information
3403  */
3404 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3405 {
3406     LPKEYSTRUCT lpkey;
3407     TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3408
3409     /* Do this check before the hkey check */
3410     if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3411         return ERROR_INVALID_PARAMETER;
3412
3413     lpkey = lookup_hkey( hkey );
3414     if (!lpkey)
3415         return ERROR_INVALID_HANDLE;
3416
3417     FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3418           debugstr_w(lpszFile));
3419
3420     return ERROR_SUCCESS;
3421 }
3422
3423
3424 /******************************************************************************
3425  * RegLoadKey32A [ADVAPI32.???]
3426  */
3427 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3428 {
3429     LONG ret;
3430     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3431     LPWSTR lpszFileW = strdupA2W(lpszFile);
3432     ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3433     if(lpszFileW) free(lpszFileW);
3434     if(lpszSubKeyW) free(lpszSubKeyW);
3435     return ret;
3436 }
3437
3438
3439 /******************************************************************************
3440  * RegNotifyChangeKeyValue [ADVAPI32.???]
3441  *
3442  * PARAMS
3443  *    hkey            [I] Handle of key to watch
3444  *    fWatchSubTree   [I] Flag for subkey notification
3445  *    fdwNotifyFilter [I] Changes to be reported
3446  *    hEvent          [I] Handle of signaled event
3447  *    fAsync          [I] Flag for asynchronous reporting
3448  */
3449 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree, 
3450                                      DWORD fdwNotifyFilter, HANDLE32 hEvent,
3451                                      BOOL32 fAsync )
3452 {
3453     LPKEYSTRUCT lpkey;
3454     TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3455           hEvent,fAsync);
3456
3457     lpkey = lookup_hkey( hkey );
3458     if (!lpkey)
3459         return ERROR_INVALID_HANDLE;
3460
3461     FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3462           hEvent,fAsync);
3463
3464     return ERROR_SUCCESS;
3465 }
3466
3467
3468 /******************************************************************************
3469  * RegUnLoadKey32W [ADVAPI32.173]
3470  *
3471  * PARAMS
3472  *    hkey     [I] Handle of open key
3473  *    lpSubKey [I] Address of name of subkey to unload
3474  */
3475 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3476 {
3477     FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3478     return ERROR_SUCCESS;
3479 }
3480
3481
3482 /******************************************************************************
3483  * RegUnLoadKey32A [ADVAPI32.172]
3484  */
3485 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3486 {
3487     LONG ret;
3488     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3489     ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3490     if(lpSubKeyW) free(lpSubKeyW);
3491     return ret;
3492 }
3493
3494
3495 /******************************************************************************
3496  * RegSetKeySecurity [ADVAPI32.167]
3497  *
3498  * PARAMS
3499  *    hkey          [I] Open handle of key to set
3500  *    SecurityInfo  [I] Descriptor contents
3501  *    pSecurityDesc [I] Address of descriptor for key
3502  */
3503 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3504                                LPSECURITY_DESCRIPTOR pSecurityDesc )
3505 {
3506     LPKEYSTRUCT lpkey;
3507
3508     TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3509
3510     /* It seems to perform this check before the hkey check */
3511     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3512         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3513         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3514         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3515         /* Param OK */
3516     } else
3517         return ERROR_INVALID_PARAMETER;
3518
3519     if (!pSecurityDesc)
3520         return ERROR_INVALID_PARAMETER;
3521
3522     lpkey = lookup_hkey( hkey );
3523     if (!lpkey)
3524         return ERROR_INVALID_HANDLE;
3525
3526     FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3527
3528     return ERROR_SUCCESS;
3529 }
3530
3531
3532 /******************************************************************************
3533  * RegSaveKey32W [ADVAPI32.166]
3534  *
3535  * PARAMS
3536  *    hkey   [I] Handle of key where save begins
3537  *    lpFile [I] Address of filename to save to
3538  *    sa     [I] Address of security structure
3539  */
3540 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile, 
3541                            LPSECURITY_ATTRIBUTES sa )
3542 {
3543     LPKEYSTRUCT lpkey;
3544
3545     TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3546
3547     /* It appears to do this check before the hkey check */
3548     if (!lpFile || !*lpFile)
3549         return ERROR_INVALID_PARAMETER;
3550
3551     lpkey = lookup_hkey( hkey );
3552     if (!lpkey)
3553         return ERROR_INVALID_HANDLE;
3554
3555     FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3556
3557     return ERROR_SUCCESS;
3558 }
3559
3560
3561 /******************************************************************************
3562  * RegSaveKey32A [ADVAPI32.165]
3563  */
3564 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile, 
3565                            LPSECURITY_ATTRIBUTES sa )
3566 {
3567     LONG ret;
3568     LPWSTR lpFileW = strdupA2W(lpFile);
3569     ret = RegSaveKey32W( hkey, lpFileW, sa );
3570     free(lpFileW);
3571     return ret;
3572 }
3573
3574
3575 /******************************************************************************
3576  * RegRestoreKey32W [ADVAPI32.164]
3577  *
3578  * PARAMS
3579  *    hkey    [I] Handle of key where restore begins
3580  *    lpFile  [I] Address of filename containing saved tree
3581  *    dwFlags [I] Optional flags
3582  */
3583 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3584 {
3585     LPKEYSTRUCT lpkey;
3586
3587     TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3588
3589     /* It seems to do this check before the hkey check */
3590     if (!lpFile || !*lpFile)
3591         return ERROR_INVALID_PARAMETER;
3592
3593     lpkey = lookup_hkey( hkey );
3594     if (!lpkey)
3595         return ERROR_INVALID_HANDLE;
3596
3597     FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3598
3599     /* Check for file existence */
3600
3601     return ERROR_SUCCESS;
3602 }
3603
3604
3605 /******************************************************************************
3606  * RegRestoreKey32A [ADVAPI32.163]
3607  */
3608 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3609 {
3610     LONG ret;
3611     LPWSTR lpFileW = strdupA2W(lpFile);
3612     ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3613     if(lpFileW) free(lpFileW);
3614     return ret;
3615 }
3616
3617
3618 /******************************************************************************
3619  * RegReplaceKey32W [ADVAPI32.162]
3620  *
3621  * PARAMS
3622  *    hkey      [I] Handle of open key
3623  *    lpSubKey  [I] Address of name of subkey
3624  *    lpNewFile [I] Address of filename for file with new data
3625  *    lpOldFile [I] Address of filename for backup file
3626  */
3627 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3628                               LPCWSTR lpOldFile )
3629 {
3630     LPKEYSTRUCT lpkey;
3631
3632     TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3633           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3634
3635     lpkey = lookup_hkey( hkey );
3636     if (!lpkey)
3637         return ERROR_INVALID_HANDLE;
3638
3639     FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
3640           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3641
3642     return ERROR_SUCCESS;
3643 }
3644
3645
3646 /******************************************************************************
3647  * RegReplaceKey32A [ADVAPI32.161]
3648  */
3649 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3650                               LPCSTR lpOldFile )
3651 {
3652     LONG ret;
3653     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3654     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3655     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3656     ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3657     free(lpOldFileW);
3658     free(lpNewFileW);
3659     free(lpSubKeyW);
3660     return ret;
3661 }
3662