Install notepad.exe in c:\windows too.
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  * Copyright 1998 Matthew Becker
6  * Copyright 1999 Sylvain St-Germain
7  *
8  * December 21, 1997 - Kevin Cozens
9  * Fixed bugs in the _w95_loadreg() function. Added extra information
10  * regarding the format of the Windows '95 registry files.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  *
26  * NOTES
27  *    When changing this file, please re-run the regtest program to ensure
28  *    the conditions are handled properly.
29  *
30  * TODO
31  *    Security access
32  *    Option handling
33  *    Time for RegEnumKey*, RegQueryInfoKey*
34  */
35
36 #include "config.h"
37 #include "wine/port.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
51 #endif
52
53 #include "winerror.h"
54 #include "winnt.h"
55 #include "winreg.h"
56
57 #include "wine/winbase16.h"
58 #include "wine/library.h"
59 #include "wine/server.h"
60 #include "wine/unicode.h"
61 #include "file.h"
62
63 #include "wine/debug.h"
64
65 WINE_DEFAULT_DEBUG_CHANNEL(reg);
66
67 /* FIXME: following defines should be configured global */
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT  ETCDIR"/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
70
71 /* relative in ~user/.wine/ : */
72 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER  "user.reg"
73 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT  "userdef.reg"
74 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
75
76 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
77                                      'S','o','f','t','w','a','r','e','\\',
78                                      'C','l','a','s','s','e','s',0};
79
80 /* _xmalloc [Internal] */
81 static void *_xmalloc( size_t size )
82 {
83     void *res;
84
85     res = malloc (size ? size : 1);
86     if (res == NULL) {
87         WARN("Virtual memory exhausted.\n");
88         exit (1);
89     }
90     return res;
91 }
92
93 /* _strdupnA [Internal] */
94 static LPSTR _strdupnA(LPCSTR str,size_t len)
95 {
96     LPSTR ret;
97
98     if (!str) return NULL;
99     ret = _xmalloc( len + 1 );
100     memcpy( ret, str, len );
101     ret[len] = 0x00;
102     return ret;
103 }
104
105 /* convert ansi string to unicode [Internal] */
106 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
107 {
108     LPWSTR ret;
109     size_t lenW;
110
111     if (!strA) return NULL;
112     lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
113     ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
114     MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
115     ret[lenW] = 0;
116     return ret;
117 }
118
119 /* dump a Unicode string with proper escaping [Internal] */
120 /* FIXME: this code duplicates server/unicode.c */
121 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
122 {
123     static const char escapes[32] = ".......abtnvfr.............e....";
124     char buffer[256];
125     LPSTR pos = buffer;
126     int count = 0;
127
128     for (; len; str++, len--)
129     {
130         if (pos > buffer + sizeof(buffer) - 8)
131         {
132             fwrite( buffer, pos - buffer, 1, f );
133             count += pos - buffer;
134             pos = buffer;
135         }
136         if (*str > 127)  /* hex escape */
137         {
138             if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
139                 pos += sprintf( pos, "\\x%04x", *str );
140             else
141                 pos += sprintf( pos, "\\x%x", *str );
142             continue;
143         }
144         if (*str < 32)  /* octal or C escape */
145         {
146             if (!*str && len == 1) continue;  /* do not output terminating NULL */
147             if (escapes[*str] != '.')
148                 pos += sprintf( pos, "\\%c", escapes[*str] );
149             else if (len > 1 && str[1] >= '0' && str[1] <= '7')
150                 pos += sprintf( pos, "\\%03o", *str );
151             else
152                 pos += sprintf( pos, "\\%o", *str );
153             continue;
154         }
155         if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
156         *pos++ = *str;
157     }
158     fwrite( buffer, pos - buffer, 1, f );
159     count += pos - buffer;
160     return count;
161 }
162
163 /* convert ansi string to unicode and dump with proper escaping [Internal] */
164 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
165 {
166     WCHAR *strW;
167     int ret;
168
169     if (strA == NULL) return 0;
170     strW = _strdupnAtoW(strA,len);
171     ret = _dump_strW(strW,len,f,escape);
172     free(strW);
173     return ret;
174 }
175
176 /* a key value */
177 /* FIXME: this code duplicates server/registry.c */
178 struct key_value {
179     WCHAR            *nameW;   /* value name */
180     int               type;    /* value type */
181     size_t            len;     /* value data length in bytes */
182     void             *data;    /* pointer to value data */
183 };
184
185 /* dump a value to a text file */
186 /* FIXME: this code duplicates server/registry.c */
187 static void _dump_value(struct key_value *value,FILE *f)
188 {
189     int i, count;
190
191     if (value->nameW[0]) {
192         fputc( '\"', f );
193         count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
194         count += fprintf( f, "\"=" );
195     }
196     else count = fprintf( f, "@=" );
197
198     switch(value->type) {
199         case REG_SZ:
200         case REG_EXPAND_SZ:
201         case REG_MULTI_SZ:
202             if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
203             fputc( '\"', f );
204             if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
205             fputc( '\"', f );
206             break;
207         case REG_DWORD:
208             if (value->len == sizeof(DWORD)) {
209                 DWORD dw;
210                 memcpy( &dw, value->data, sizeof(DWORD) );
211                 fprintf( f, "dword:%08lx", dw );
212                 break;
213             }
214             /* else fall through */
215         default:
216             if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
217             else count += fprintf( f, "hex(%x):", value->type );
218             for (i = 0; i < value->len; i++) {
219                 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
220                 if (i < value->len-1) {
221                     fputc( ',', f );
222                     if (++count > 76) {
223                         fprintf( f, "\\\n  " );
224                         count = 2;
225                     }
226                 }
227             }
228             break;
229     }
230     fputc( '\n', f );
231 }
232
233 /******************************************************************/
234 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
235 /*
236     reghack - windows 3.11 registry data format demo program.
237
238     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
239     a combined hash table and tree description, and finally a text table.
240
241     The header is obvious from the struct header. The taboff1 and taboff2
242     fields are always 0x20, and their usage is unknown.
243
244     The 8-byte entry table has various entry types.
245
246     tabent[0] is a root index. The second word has the index of the root of
247             the directory.
248     tabent[1..hashsize] is a hash table. The first word in the hash entry is
249             the index of the key/value that has that hash. Data with the same
250             hash value are on a circular list. The other three words in the
251             hash entry are always zero.
252     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
253             entry: dirent and keyent/valent. They are identified by context.
254     tabent[freeidx] is the first free entry. The first word in a free entry
255             is the index of the next free entry. The last has 0 as a link.
256             The other three words in the free list are probably irrelevant.
257
258     Entries in text table are preceded by a word at offset-2. This word
259     has the value (2*index)+1, where index is the referring keyent/valent
260     entry in the table. I have no suggestion for the 2* and the +1.
261     Following the word, there are N bytes of data, as per the keyent/valent
262     entry length. The offset of the keyent/valent entry is from the start
263     of the text table to the first data byte.
264
265     This information is not available from Microsoft. The data format is
266     deduced from the reg.dat file by me. Mistakes may
267     have been made. I claim no rights and give no guarantees for this program.
268
269     Tor Sjøwall, tor@sn.no
270 */
271
272 /* reg.dat header format */
273 struct _w31_header {
274     char                cookie[8];      /* 'SHCC3.10' */
275     unsigned long       taboff1;        /* offset of hash table (??) = 0x20 */
276     unsigned long       taboff2;        /* offset of index table (??) = 0x20 */
277     unsigned long       tabcnt;         /* number of entries in index table */
278     unsigned long       textoff;        /* offset of text part */
279     unsigned long       textsize;       /* byte size of text part */
280     unsigned short      hashsize;       /* hash size */
281     unsigned short      freeidx;        /* free index */
282 };
283
284 /* generic format of table entries */
285 struct _w31_tabent {
286     unsigned short w0, w1, w2, w3;
287 };
288
289 /* directory tabent: */
290 struct _w31_dirent {
291     unsigned short      sibling_idx;    /* table index of sibling dirent */
292     unsigned short      child_idx;      /* table index of child dirent */
293     unsigned short      key_idx;        /* table index of key keyent */
294     unsigned short      value_idx;      /* table index of value valent */
295 };
296
297 /* key tabent: */
298 struct _w31_keyent {
299     unsigned short      hash_idx;       /* hash chain index for string */
300     unsigned short      refcnt;         /* reference count */
301     unsigned short      length;         /* length of string */
302     unsigned short      string_off;     /* offset of string in text table */
303 };
304
305 /* value tabent: */
306 struct _w31_valent {
307     unsigned short      hash_idx;       /* hash chain index for string */
308     unsigned short      refcnt;         /* reference count */
309     unsigned short      length;         /* length of string */
310     unsigned short      string_off;     /* offset of string in text table */
311 };
312
313 /* recursive helper function to display a directory tree  [Internal] */
314 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
315 {
316     static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
317     struct _w31_dirent *dir;
318     struct _w31_keyent *key;
319     struct _w31_valent *val;
320     HKEY subkey = 0;
321     OBJECT_ATTRIBUTES attr;
322     UNICODE_STRING nameW, valueW;
323     static WCHAR tail[400];
324
325     attr.Length = sizeof(attr);
326     attr.RootDirectory = hkey;
327     attr.ObjectName = &nameW;
328     attr.Attributes = 0;
329     attr.SecurityDescriptor = NULL;
330     attr.SecurityQualityOfService = NULL;
331     RtlInitUnicodeString( &valueW, NULL );
332
333     while (idx!=0) {
334         dir=(struct _w31_dirent*)&tab[idx];
335
336         if (dir->key_idx) {
337             DWORD len;
338             key = (struct _w31_keyent*)&tab[dir->key_idx];
339
340             RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
341                                     &txt[key->string_off], key->length);
342             tail[len/sizeof(WCHAR)] = 0;
343
344             /* all toplevel entries AND the entries in the
345              * toplevel subdirectory belong to \SOFTWARE\Classes
346              */
347             if (!level && !strcmpW(tail,classesW))
348             {
349                 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
350                 idx=dir->sibling_idx;
351                 continue;
352             }
353
354             if (subkey) NtClose( subkey );
355             RtlInitUnicodeString( &nameW, tail );
356             if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
357
358             /* only add if leaf node or valued node */
359             if (dir->value_idx!=0||dir->child_idx==0) {
360                 if (dir->value_idx) {
361                     DWORD len;
362                     val=(struct _w31_valent*)&tab[dir->value_idx];
363                     RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
364                                             &txt[val->string_off], val->length);
365                     tail[len/sizeof(WCHAR)] = 0;
366                     NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
367                 }
368             }
369         } else TRACE("strange: no directory key name, idx=%04x\n", idx);
370         _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
371         idx=dir->sibling_idx;
372     }
373     if (subkey) NtClose( subkey );
374 }
375
376
377 /******************************************************************************
378  * _w31_loadreg [Internal]
379  */
380 void _w31_loadreg(void)
381 {
382     HFILE hf;
383     HKEY root;
384     OBJECT_ATTRIBUTES attr;
385     UNICODE_STRING nameW;
386     struct _w31_header  head;
387     struct _w31_tabent  *tab;
388     unsigned char               *txt;
389     unsigned int                len;
390     OFSTRUCT            ofs;
391     BY_HANDLE_FILE_INFORMATION hfinfo;
392     time_t                      lastmodified;
393
394     TRACE("(void)\n");
395
396     hf = OpenFile("reg.dat",&ofs,OF_READ);
397     if (hf==HFILE_ERROR) return;
398
399     /* read & dump header */
400     if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
401         ERR("reg.dat is too short.\n");
402         _lclose(hf);
403         return;
404     }
405     if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
406         ERR("reg.dat has bad signature.\n");
407         _lclose(hf);
408         return;
409     }
410
411     len = head.tabcnt * sizeof(struct _w31_tabent);
412     /* read and dump index table */
413     tab = _xmalloc(len);
414     if (len!=_lread(hf,tab,len)) {
415         ERR("couldn't read %d bytes.\n",len);
416         free(tab);
417         _lclose(hf);
418         return;
419     }
420
421     /* read text */
422     txt = _xmalloc(head.textsize);
423     if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
424         ERR("couldn't seek to textblock.\n");
425         free(tab);
426         free(txt);
427         _lclose(hf);
428         return;
429     }
430     if (head.textsize!=_lread(hf,txt,head.textsize)) {
431         ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
432         free(tab);
433         free(txt);
434         _lclose(hf);
435         return;
436     }
437
438     if (!GetFileInformationByHandle(hf,&hfinfo)) {
439         ERR("GetFileInformationByHandle failed?.\n");
440         free(tab);
441         free(txt);
442         _lclose(hf);
443         return;
444     }
445     lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
446
447     attr.Length = sizeof(attr);
448     attr.RootDirectory = 0;
449     attr.ObjectName = &nameW;
450     attr.Attributes = 0;
451     attr.SecurityDescriptor = NULL;
452     attr.SecurityQualityOfService = NULL;
453     RtlInitUnicodeString( &nameW, ClassesRootW );
454
455     if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
456     {
457         _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
458         NtClose( root );
459     }
460     free(tab);
461     free(txt);
462     _lclose(hf);
463     return;
464 }
465
466 /***********************************************************************************/
467 /*                        windows 95 registry loader                               */
468 /***********************************************************************************/
469
470 /* SECTION 1: main header
471  *
472  * once at offset 0
473  */
474 #define W95_REG_CREG_ID 0x47455243
475
476 typedef struct {
477     DWORD       id;             /* "CREG" = W95_REG_CREG_ID */
478     DWORD       version;        /* ???? 0x00010000 */
479     DWORD       rgdb_off;       /* 0x08 Offset of 1st RGDB-block */
480     DWORD       uk2;            /* 0x0c */
481     WORD        rgdb_num;       /* 0x10 # of RGDB-blocks */
482     WORD        uk3;
483     DWORD       uk[3];
484     /* rgkn */
485 } _w95creg;
486
487 /* SECTION 2: Directory information (tree structure)
488  *
489  * once on offset 0x20
490  *
491  * structure: [rgkn][dke]*      (repeat till last_dke is reached)
492  */
493 #define W95_REG_RGKN_ID 0x4e4b4752
494
495 typedef struct {
496     DWORD       id;             /*"RGKN" = W95_REG_RGKN_ID */
497     DWORD       size;           /* Size of the RGKN-block */
498     DWORD       root_off;       /* Rel. Offset of the root-record */
499     DWORD   last_dke;       /* Offset to last DKE ? */
500     DWORD       uk[4];
501 } _w95rgkn;
502
503 /* Disk Key Entry Structure
504  *
505  * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
506  * hive itself. It looks the same like other keys. Even the ID-number can
507  * be any value.
508  *
509  * The "hash"-value is a value representing the key's name. Windows will not
510  * search for the name, but for a matching hash-value. if it finds one, it
511  * will compare the actual string info, otherwise continue with the next key.
512  * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
513  * of the string which are smaller than 0x80 (128) to this D-Word.
514  *
515  * If you want to modify key names, also modify the hash-values, since they
516  * cannot be found again (although they would be displayed in REGEDIT)
517  * End of list-pointers are filled with 0xFFFFFFFF
518  *
519  * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
520  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
521  * structure) and reading another RGDB_section.
522  *
523  * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
524  * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
525  * The remaining space between last_dke and the offset calculated from
526  * rgkn->size seems to be free for use for more dke:s.
527  * So it seems if more dke:s are added, they are added to that space and
528  * last_dke is grown, and in case that "free" space is out, the space
529  * gets grown and rgkn->size gets adjusted.
530  *
531  * there is a one to one relationship between dke and dkh
532  */
533  /* key struct, once per key */
534 typedef struct {
535     DWORD       x1;             /* Free entry indicator(?) */
536     DWORD       hash;           /* sum of bytes of keyname */
537     DWORD       x3;             /* Root key indicator? usually 0xFFFFFFFF */
538     DWORD       prevlvl;        /* offset of previous key */
539     DWORD       nextsub;        /* offset of child key */
540     DWORD       next;           /* offset of sibling key */
541     WORD        nrLS;           /* id inside the rgdb block */
542     WORD        nrMS;           /* number of the rgdb block */
543 } _w95dke;
544
545 /* SECTION 3: key information, values and data
546  *
547  * structure:
548  *  section:    [blocks]*               (repeat creg->rgdb_num times)
549  *  blocks:     [rgdb] [subblocks]*     (repeat till block size reached )
550  *  subblocks:  [dkh] [dkv]*            (repeat dkh->values times )
551  *
552  * An interesting relationship exists in RGDB_section. The DWORD value
553  * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
554  * I have no idea at the moment what this means.  (Kevin Cozens)
555  */
556
557 /* block header, once per block */
558 #define W95_REG_RGDB_ID 0x42444752
559
560 typedef struct {
561     DWORD       id;     /* 0x00 'RGDB' = W95_REG_RGDB_ID */
562     DWORD       size;   /* 0x04 */
563     DWORD       uk1;    /* 0x08 */
564     DWORD       uk2;    /* 0x0c */
565     DWORD       uk3;    /* 0x10 */
566     DWORD       uk4;    /* 0x14 */
567     DWORD       uk5;    /* 0x18 */
568     DWORD       uk6;    /* 0x1c */
569     /* dkh */
570 } _w95rgdb;
571
572 /* Disk Key Header structure (RGDB part), once per key */
573 typedef struct {
574     DWORD       nextkeyoff;     /* 0x00 offset to next dkh */
575     WORD        nrLS;           /* 0x04 id inside the rgdb block */
576     WORD        nrMS;           /* 0x06 number of the rgdb block */
577     DWORD       bytesused;      /* 0x08 */
578     WORD        keynamelen;     /* 0x0c len of name */
579     WORD        values;         /* 0x0e number of values */
580     DWORD       xx1;            /* 0x10 */
581     char        name[1];        /* 0x14 */
582     /* dkv */           /* 0x14 + keynamelen */
583 } _w95dkh;
584
585 /* Disk Key Value structure, once per value */
586 typedef struct {
587     DWORD       type;           /* 0x00 */
588     DWORD       x1;             /* 0x04 */
589     WORD        valnamelen;     /* 0x08 length of name, 0 is default key */
590     WORD        valdatalen;     /* 0x0A length of data */
591     char        name[1];        /* 0x0c */
592     /* raw data */              /* 0x0c + valnamelen */
593 } _w95dkv;
594
595 /******************************************************************************
596  * _w95_lookup_dkh [Internal]
597  *
598  * seeks the dkh belonging to a dke
599  */
600 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
601 {
602     _w95rgdb * rgdb;
603     _w95dkh * dkh;
604     int i;
605
606     /* get the beginning of the rgdb datastore */
607     rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
608
609     /* check: requested block < last_block) */
610     if (creg->rgdb_num <= nrMS) {
611         ERR("registry file corrupt! requested block no. beyond end.\n");
612         goto error;
613     }
614
615     /* find the right block */
616     for(i=0; i<nrMS ;i++) {
617         if(rgdb->id != W95_REG_RGDB_ID) {  /* check the magic */
618             ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
619             goto error;
620         }
621         rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size);            /* find next block */
622     }
623
624     dkh = (_w95dkh*)(rgdb + 1);                         /* first sub block within the rgdb */
625
626     do {
627         if(nrLS==dkh->nrLS ) return dkh;
628         dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
629     } while ((char *)dkh < ((char*)rgdb+rgdb->size));
630
631 error:
632     return NULL;
633 }
634
635 /******************************************************************************
636  * _w95_dump_dkv [Internal]
637  */
638 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
639 {
640     _w95dkv * dkv;
641     int i;
642
643     /* first value block */
644     dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
645
646     /* loop through the values */
647     for (i=0; i< dkh->values; i++) {
648         struct key_value value;
649         WCHAR *pdata;
650
651         value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
652         value.type = dkv->type;
653         value.len = dkv->valdatalen;
654
655         value.data = &(dkv->name[dkv->valnamelen]);
656         pdata = NULL;
657         if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
658             pdata = _strdupnAtoW(value.data,value.len);
659             value.len *= 2;
660         }
661         if (pdata != NULL) value.data = pdata;
662
663         _dump_value(&value,f);
664         free(value.nameW);
665         if (pdata != NULL) free(pdata);
666
667         /* next value */
668         dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
669     }
670     return TRUE;
671 }
672
673 /******************************************************************************
674  * _w95_dump_dke [Internal]
675  */
676 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
677 {
678     _w95dkh * dkh;
679     LPSTR new_key_name = NULL;
680
681     /* special root key */
682     if (dke->nrLS == 0xffff || dke->nrMS==0xffff)               /* eg. the root key has no name */
683     {
684         /* parse the one subkey */
685         if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
686         /* has no sibling keys */
687         return FALSE;
688     }
689
690     /* search subblock */
691     if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
692         ERR("dke pointing to missing dkh !\n");
693         return FALSE;
694     }
695
696     if (level <= 0) {
697         /* create new subkey name */
698         new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
699         if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
700         strncat(new_key_name,dkh->name,dkh->keynamelen);
701
702         /* walk sibling keys */
703         if (dke->next != 0xffffffff ) {
704             if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
705                 free(new_key_name);
706                 return FALSE;
707             }
708         }
709
710         /* write the key path (something like [Software\\Microsoft\\..]) only if:
711            1) key has some values
712            2) key has no values and no subkeys
713         */
714         if (dkh->values > 0) {
715             /* there are some values */
716             fprintf(f,"\n[");
717             _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
718             fprintf(f,"]\n");
719             if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
720               free(new_key_name);
721               return FALSE;
722             }
723         }
724         if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
725             /* no subkeys and no values */
726             fprintf(f,"\n[");
727             _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
728             fprintf(f,"]\n");
729         }
730     } else new_key_name = _strdupnA(key_name,strlen(key_name));
731
732     /* next sub key */
733     if (dke->nextsub != 0xffffffff) {
734         if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
735           free(new_key_name);
736           return FALSE;
737         }
738     }
739
740     free(new_key_name);
741     return TRUE;
742 }
743 /* end windows 95 loader */
744
745 /***********************************************************************************/
746 /*                        windows NT registry loader                               */
747 /***********************************************************************************/
748
749 /* NT REGISTRY LOADER */
750
751 #ifdef HAVE_SYS_MMAN_H
752 # include <sys/mman.h>
753 #endif
754
755 #ifndef MAP_FAILED
756 #define MAP_FAILED ((LPVOID)-1)
757 #endif
758
759 #define NT_REG_BLOCK_SIZE            0x1000
760
761 #define NT_REG_HEADER_BLOCK_ID       0x66676572 /* regf */
762 #define NT_REG_POOL_BLOCK_ID         0x6E696268 /* hbin */
763 #define NT_REG_KEY_BLOCK_ID          0x6b6e /* nk */
764 #define NT_REG_VALUE_BLOCK_ID        0x6b76 /* vk */
765
766 /* subblocks of nk */
767 #define NT_REG_HASH_BLOCK_ID         0x666c /* lf */
768 #define NT_REG_NOHASH_BLOCK_ID       0x696c /* li */
769 #define NT_REG_RI_BLOCK_ID           0x6972 /* ri */
770
771 #define NT_REG_KEY_BLOCK_TYPE        0x20
772 #define NT_REG_ROOT_KEY_BLOCK_TYPE   0x2c
773
774 typedef struct {
775     DWORD       id;             /* 0x66676572 'regf'*/
776     DWORD       uk1;            /* 0x04 */
777     DWORD       uk2;            /* 0x08 */
778     FILETIME    DateModified;   /* 0x0c */
779     DWORD       uk3;            /* 0x14 */
780     DWORD       uk4;            /* 0x18 */
781     DWORD       uk5;            /* 0x1c */
782     DWORD       uk6;            /* 0x20 */
783     DWORD       RootKeyBlock;   /* 0x24 */
784     DWORD       BlockSize;      /* 0x28 */
785     DWORD   uk7[116];
786     DWORD       Checksum; /* at offset 0x1FC */
787 } nt_regf;
788
789 typedef struct {
790     DWORD       blocksize;
791     BYTE        data[1];
792 } nt_hbin_sub;
793
794 typedef struct {
795     DWORD       id;             /* 0x6E696268 'hbin' */
796     DWORD       off_prev;
797     DWORD       off_next;
798     DWORD       uk1;
799     DWORD       uk2;            /* 0x10 */
800     DWORD       uk3;            /* 0x14 */
801     DWORD       uk4;            /* 0x18 */
802     DWORD       size;           /* 0x1C */
803     nt_hbin_sub hbin_sub;       /* 0x20 */
804 } nt_hbin;
805
806 /*
807  * the value_list consists of offsets to the values (vk)
808  */
809 typedef struct {
810     WORD        SubBlockId;             /* 0x00 0x6B6E */
811     WORD        Type;                   /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
812     FILETIME    writetime;      /* 0x04 */
813     DWORD       uk1;                    /* 0x0C */
814     DWORD       parent_off;             /* 0x10 Offset of Owner/Parent key */
815     DWORD       nr_subkeys;             /* 0x14 number of sub-Keys */
816     DWORD       uk8;                    /* 0x18 */
817     DWORD       lf_off;                 /* 0x1C Offset of the sub-key lf-Records */
818     DWORD       uk2;                    /* 0x20 */
819     DWORD       nr_values;              /* 0x24 number of values */
820     DWORD       valuelist_off;          /* 0x28 Offset of the Value-List */
821     DWORD       off_sk;                 /* 0x2c Offset of the sk-Record */
822     DWORD       off_class;              /* 0x30 Offset of the Class-Name */
823     DWORD       uk3;                    /* 0x34 */
824     DWORD       uk4;                    /* 0x38 */
825     DWORD       uk5;                    /* 0x3c */
826     DWORD       uk6;                    /* 0x40 */
827     DWORD       uk7;                    /* 0x44 */
828     WORD        name_len;               /* 0x48 name-length */
829     WORD        class_len;              /* 0x4a class-name length */
830     char        name[1];                /* 0x4c key-name */
831 } nt_nk;
832
833 typedef struct {
834     DWORD       off_nk; /* 0x00 */
835     DWORD       name;   /* 0x04 */
836 } hash_rec;
837
838 typedef struct {
839     WORD        id;             /* 0x00 0x666c */
840     WORD        nr_keys;        /* 0x06 */
841     hash_rec    hash_rec[1];
842 } nt_lf;
843
844 /*
845  list of subkeys without hash
846
847  li --+-->nk
848       |
849       +-->nk
850  */
851 typedef struct {
852     WORD        id;             /* 0x00 0x696c */
853     WORD        nr_keys;
854     DWORD       off_nk[1];
855 } nt_li;
856
857 /*
858  this is a intermediate node
859
860  ri --+-->li--+-->nk
861       |       +
862       |       +-->nk
863       |
864       +-->li--+-->nk
865               +
866               +-->nk
867  */
868 typedef struct {
869     WORD        id;             /* 0x00 0x6972 */
870     WORD        nr_li;          /* 0x02 number off offsets */
871     DWORD       off_li[1];      /* 0x04 points to li */
872 } nt_ri;
873
874 typedef struct {
875     WORD        id;             /* 0x00 'vk' */
876     WORD        nam_len;
877     DWORD       data_len;
878     DWORD       data_off;
879     DWORD       type;
880     WORD        flag;
881     WORD        uk1;
882     char        name[1];
883 } nt_vk;
884
885 /*
886  * gets a value
887  *
888  * vk->flag:
889  *  0 value is a default value
890  *  1 the value has a name
891  *
892  * vk->data_len
893  *  len of the whole data block
894  *  - reg_sz (unicode)
895  *    bytes including the terminating \0 = 2*(number_of_chars+1)
896  *  - reg_dword, reg_binary:
897  *    if highest bit of data_len is set data_off contains the value
898  */
899 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
900 {
901     BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
902     struct key_value value;
903
904     if (vk->id != NT_REG_VALUE_BLOCK_ID) {
905         ERR("unknown block found (0x%04x), please report!\n", vk->id);
906         return FALSE;
907     }
908
909     value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
910     value.type = vk->type;
911     value.len = (vk->data_len & 0x7fffffff);
912     value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
913
914     _dump_value(&value,f);
915     free(value.nameW);
916
917     return TRUE;
918 }
919
920 /* it's called from _nt_dump_lf() */
921 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
922
923 /*
924  * get the subkeys
925  *
926  * this structure contains the hash of a keyname and points to all
927  * subkeys
928  *
929  * exception: if the id is 'il' there are no hash values and every
930  * dword is a offset
931  */
932 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
933 {
934     int i;
935
936     if (lf->id == NT_REG_HASH_BLOCK_ID) {
937         if (subkeys != lf->nr_keys) goto error1;
938
939         for (i=0; i<lf->nr_keys; i++)
940             if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
941     } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
942         nt_li * li = (nt_li*)lf;
943         if (subkeys != li->nr_keys) goto error1;
944
945         for (i=0; i<li->nr_keys; i++)
946             if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
947     } else if (lf->id == NT_REG_RI_BLOCK_ID) {  /* ri */
948         nt_ri * ri = (nt_ri*)lf;
949         int li_subkeys = 0;
950
951         /* count all subkeys */
952         for (i=0; i<ri->nr_li; i++) {
953             nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
954             if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
955             li_subkeys += li->nr_keys;
956         }
957
958         /* check number */
959         if (subkeys != li_subkeys) goto error1;
960
961         /* loop through the keys */
962         for (i=0; i<ri->nr_li; i++) {
963             nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
964             if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
965         }
966     } else goto error2;
967
968     return TRUE;
969
970 error2:
971     if (lf->id == 0x686c)
972         FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
973     else
974         ERR("unknown node id 0x%04x, please report!\n", lf->id);
975     return TRUE;
976
977 error1:
978     ERR("registry file corrupt! (inconsistent number of subkeys)\n");
979     return FALSE;
980
981 error:
982     ERR("error reading lf block\n");
983     return FALSE;
984 }
985
986 /* _nt_dump_nk [Internal] */
987 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
988 {
989     unsigned int n;
990     DWORD *vl;
991     LPSTR new_key_name = NULL;
992
993     TRACE("%s\n", key_name);
994
995     if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
996         ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
997         return FALSE;
998     }
999
1000     if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1001         ERR("registry file corrupt!\n");
1002         return FALSE;
1003     }
1004
1005     /* create the new key */
1006     if (level <= 0) {
1007         /* create new subkey name */
1008         new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
1009         if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
1010         strncat(new_key_name,nk->name,nk->name_len);
1011
1012         /* write the key path (something like [Software\\Microsoft\\..]) only if:
1013            1) key has some values
1014            2) key has no values and no subkeys
1015         */
1016         if (nk->nr_values > 0) {
1017             /* there are some values */
1018             fprintf(f,"\n[");
1019             _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1020             fprintf(f,"]\n");
1021         }
1022         if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1023             /* no subkeys and no values */
1024             fprintf(f,"\n[");
1025             _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1026             fprintf(f,"]\n");
1027         }
1028
1029         /* loop trough the value list */
1030         vl = (DWORD *)(base+nk->valuelist_off+4);
1031         for (n=0; n<nk->nr_values; n++) {
1032             nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1033             if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1034                 free(new_key_name);
1035                 return FALSE;
1036             }
1037         }
1038     } else new_key_name = _strdupnA(key_name,strlen(key_name));
1039
1040     /* loop through the subkeys */
1041     if (nk->nr_subkeys) {
1042         nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1043         if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1044             free(new_key_name);
1045             return FALSE;
1046         }
1047     }
1048
1049     free(new_key_name);
1050     return TRUE;
1051 }
1052
1053 /* end nt loader */
1054
1055 /**********************************************************************************
1056  * _set_registry_levels [Internal]
1057  *
1058  * set level to 0 for loading system files
1059  * set level to 1 for loading user files
1060  */
1061 static void _set_registry_levels(int level,int saving,int period)
1062 {
1063     SERVER_START_REQ( set_registry_levels )
1064     {
1065         req->current = level;
1066         req->saving  = saving;
1067         req->period  = period;
1068         wine_server_call( req );
1069     }
1070     SERVER_END_REQ;
1071 }
1072
1073 /* _save_at_exit [Internal] */
1074 static void _save_at_exit(HKEY hkey,LPCSTR path)
1075 {
1076     LPCSTR confdir = wine_get_config_dir();
1077
1078     SERVER_START_REQ( save_registry_atexit )
1079     {
1080         req->hkey = hkey;
1081         wine_server_add_data( req, confdir, strlen(confdir) );
1082         wine_server_add_data( req, path, strlen(path)+1 );
1083         wine_server_call( req );
1084     }
1085     SERVER_END_REQ;
1086 }
1087
1088 /* configure save files and start the periodic saving timer [Internal] */
1089 static void _init_registry_saving( HKEY hkey_local_machine, HKEY hkey_current_user,
1090                                    HKEY hkey_users_default )
1091 {
1092     int all;
1093     int period = 0;
1094     WCHAR buffer[20];
1095     static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0};
1096     static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1097     static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1098     static const WCHAR WritetoHomeRegistryFilesW[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1099     static const WCHAR empty_strW[] = { 0 };
1100
1101     all  = !PROFILE_GetWineIniBool(registryW, SaveOnlyUpdatedKeysW, 1);
1102     PROFILE_GetWineIniString( registryW, PeriodicSaveW, empty_strW, buffer, 20 );
1103     if (buffer[0]) period = (int)strtolW(buffer, NULL, 10);
1104
1105     /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1106     _set_registry_levels(1,!all,period*1000);
1107
1108     if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1))
1109     {
1110         _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1111         _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1112         _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1113     }
1114
1115 }
1116
1117 /******************************************************************************
1118  * _allocate_default_keys [Internal]
1119  * Registry initialisation, allocates some default keys.
1120  */
1121 static void _allocate_default_keys(void)
1122 {
1123     HKEY hkey;
1124     OBJECT_ATTRIBUTES attr;
1125     UNICODE_STRING nameW, valueW;
1126     WCHAR computer_name[200];
1127     DWORD size = sizeof(computer_name)/sizeof(WCHAR);
1128
1129     static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1130                                       'P','e','r','f','S','t','a','t','s','\\',
1131                                       'S','t','a','t','D','a','t','a',0};
1132     static const WCHAR ComputerW[] = {'M','a','c','h','i','n','e','\\',
1133                                       'S','y','s','t','e','m','\\',
1134                                       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1135                                       'C','o','n','t','r','o','l','\\',
1136                                       'C','o','m','p','u','t','e','r','N','a','m','e','\\',
1137                                       'C','o','m','p','u','t','e','r','N','a','m','e',0};
1138     static const WCHAR ComputerNameW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
1139
1140     TRACE("(void)\n");
1141
1142     attr.Length = sizeof(attr);
1143     attr.RootDirectory = 0;
1144     attr.ObjectName = &nameW;
1145     attr.Attributes = 0;
1146     attr.SecurityDescriptor = NULL;
1147     attr.SecurityQualityOfService = NULL;
1148
1149     RtlInitUnicodeString( &nameW, StatDataW );
1150     if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1151
1152     /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1153      *                                          CurrentVersion
1154      *                                          CurrentBuildNumber
1155      *                                          CurrentType
1156      *                                  string  RegisteredOwner
1157      *                                  string  RegisteredOrganization
1158      *
1159      */
1160     /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1161      *                                  string  SysContact
1162      *                                  string  SysLocation
1163      *                                          SysServices
1164      */
1165     if (GetComputerNameW( computer_name, &size ))
1166     {
1167         RtlInitUnicodeString( &nameW, ComputerW );
1168         if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1169         {
1170             RtlInitUnicodeString( &valueW, ComputerNameW );
1171             NtSetValueKey( hkey, &valueW, 0, REG_SZ, computer_name,
1172                            (strlenW(computer_name) + 1) * sizeof(WCHAR) );
1173             NtClose(hkey);
1174         }
1175     }
1176 }
1177
1178 #define REG_DONTLOAD -1
1179 #define REG_WIN31     0
1180 #define REG_WIN95     1
1181 #define REG_WINNT     2
1182
1183 /* return the type of native registry [Internal] */
1184 static int _get_reg_type(void)
1185 {
1186     WCHAR windir[MAX_PATHNAME_LEN];
1187     WCHAR tmp[MAX_PATHNAME_LEN];
1188     int ret = REG_WIN31;
1189     static const WCHAR nt_reg_pathW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1190     static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1191     static const WCHAR WineW[] = {'W','i','n','e',0};
1192     static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1193     static const WCHAR empty_strW[] = { 0 };
1194
1195     GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1196
1197     /* test %windir%/system32/config/system --> winnt */
1198     strcpyW(tmp, windir);
1199     strcatW(tmp, nt_reg_pathW);
1200     if(GetFileAttributesW(tmp) != (DWORD)-1)
1201       ret = REG_WINNT;
1202     else
1203     {
1204        /* test %windir%/system.dat --> win95 */
1205       strcpyW(tmp, windir);
1206       strcatW(tmp, win9x_reg_pathW);
1207       if(GetFileAttributesW(tmp) != (DWORD)-1)
1208         ret = REG_WIN95;
1209     }
1210
1211     if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, tmp, MAX_PATHNAME_LEN )))
1212     {
1213        MESSAGE("When you are running with a native NT directory specify\n");
1214        MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1215        MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1216        ret = REG_DONTLOAD;
1217     }
1218
1219     return ret;
1220 }
1221
1222 #define WINE_REG_VER_ERROR  -1
1223 #define WINE_REG_VER_1       0
1224 #define WINE_REG_VER_2       1
1225 #define WINE_REG_VER_OLD     2
1226 #define WINE_REG_VER_UNKNOWN 3
1227
1228 /* return the version of wine registry file [Internal] */
1229 static int _get_wine_registry_file_format_version(LPCSTR fn)
1230 {
1231     FILE *f;
1232     char tmp[50];
1233     int ver;
1234
1235     if ((f=fopen(fn,"rt")) == NULL) {
1236         WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1237         return WINE_REG_VER_ERROR;
1238     }
1239
1240     if (fgets(tmp,50,f) == NULL) {
1241         WARN("Error reading %s: %s\n",fn,strerror(errno));
1242         fclose(f);
1243         return WINE_REG_VER_ERROR;
1244     }
1245     fclose(f);
1246
1247     if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1248     switch (ver) {
1249         case 1:
1250             return WINE_REG_VER_1;
1251             break;
1252         case 2:
1253             return WINE_REG_VER_2;
1254             break;
1255         default:
1256             return WINE_REG_VER_UNKNOWN;
1257     }
1258 }
1259
1260 /* load the registry file in wine format [Internal] */
1261 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1262 {
1263     int file_format;
1264
1265     file_format = _get_wine_registry_file_format_version(fn);
1266     switch (file_format) {
1267
1268         case WINE_REG_VER_1:
1269             WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1270             break;
1271
1272         case WINE_REG_VER_2: {
1273             HANDLE file;
1274             if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1275                                               FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1276             {
1277                 SERVER_START_REQ( load_registry )
1278                 {
1279                     req->hkey    = hkey;
1280                     req->file    = file;
1281                     wine_server_call( req );
1282                 }
1283                 SERVER_END_REQ;
1284                 CloseHandle( file );
1285             }
1286             break;
1287         }
1288
1289         case WINE_REG_VER_UNKNOWN:
1290             WARN("Unable to load registry file %s: unknown format.\n",fn);
1291             break;
1292
1293         case WINE_REG_VER_ERROR:
1294             break;
1295     }
1296 }
1297
1298 /* generate and return the name of the tmp file and associated stream [Internal] */
1299 static LPSTR _get_tmp_fn(FILE **f)
1300 {
1301     LPSTR ret;
1302     int tmp_fd,count;
1303
1304     ret = _xmalloc(50);
1305     for (count = 0;;) {
1306         sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1307         if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1308         if (errno != EEXIST) {
1309             ERR("Unexpected error while open() call: %s\n",strerror(errno));
1310             free(ret);
1311             *f = NULL;
1312             return NULL;
1313         }
1314     }
1315
1316     if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1317         ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1318         close(tmp_fd);
1319         free(ret);
1320         return NULL;
1321     }
1322
1323     return ret;
1324 }
1325
1326 /* convert win95 native registry file to wine format [Internal] */
1327 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1328 {
1329     int fd;
1330     FILE *f;
1331     DOS_FULL_NAME full_name;
1332     void *base;
1333     LPSTR ret = NULL;
1334     struct stat st;
1335
1336     _w95creg *creg;
1337     _w95rgkn *rgkn;
1338     _w95dke *dke, *root_dke;
1339
1340     if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1341
1342     /* map the registry into the memory */
1343     if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1344     if ((fstat(fd, &st) == -1)) goto error1;
1345     if (!st.st_size) goto error1;
1346     if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1347
1348     /* control signature */
1349     if (*(LPDWORD)base != W95_REG_CREG_ID) {
1350         ERR("unable to load native win95 registry file %s: unknown signature.\n",
1351             debugstr_w(fn));
1352         goto error;
1353     }
1354
1355     creg = base;
1356     /* load the header (rgkn) */
1357     rgkn = (_w95rgkn*)(creg + 1);
1358     if (rgkn->id != W95_REG_RGKN_ID) {
1359         ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1360         goto error;
1361     }
1362     if (rgkn->root_off != 0x20) {
1363         ERR("rgkn->root_off not 0x20, please report !\n");
1364         goto error;
1365     }
1366     if (rgkn->last_dke > rgkn->size)
1367     {
1368       ERR("registry file corrupt! last_dke > size!\n");
1369       goto error;
1370     }
1371     /* verify last dke */
1372     dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1373     if (dke->x1 != 0x80000000)
1374     { /* wrong magic */
1375       ERR("last dke invalid !\n");
1376       goto error;
1377     }
1378     if (rgkn->size > creg->rgdb_off)
1379     {
1380       ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1381       goto error;
1382     }
1383     root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1384     if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1385     {
1386         ERR("registry file corrupt! invalid root dke !\n");
1387         goto error;
1388     }
1389
1390     if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1391     fprintf(f,"WINE REGISTRY Version 2");
1392     _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1393     fclose(f);
1394
1395 error:
1396     if(ret == NULL) {
1397         ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1398         ERR("Please report this.\n");
1399         ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1400     }
1401
1402     munmap(base, st.st_size);
1403 error1:
1404     close(fd);
1405     return ret;
1406 }
1407
1408 /* convert winnt native registry file to wine format [Internal] */
1409 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1410 {
1411     FILE *f;
1412     void *base;
1413     LPSTR ret = NULL;
1414     HANDLE hFile;
1415     HANDLE hMapping;
1416
1417     nt_regf *regf;
1418     nt_hbin *hbin;
1419     nt_hbin_sub *hbin_sub;
1420     nt_nk *nk;
1421
1422     TRACE("%s\n", debugstr_w(fn));
1423
1424     hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1425     if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1426     hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1427     if (!hMapping) goto error1;
1428     base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1429     CloseHandle( hMapping );
1430     if (!base) goto error1;
1431
1432     /* control signature */
1433     if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1434         ERR("unable to load native winnt registry file %s: unknown signature.\n",
1435             debugstr_w(fn));
1436         goto error;
1437     }
1438
1439     /* start block */
1440     regf = base;
1441
1442     /* hbin block */
1443     hbin = (nt_hbin*)((char*) base + 0x1000);
1444     if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1445       ERR( "hbin block invalid\n");
1446       goto error;
1447     }
1448
1449     /* hbin_sub block */
1450     hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1451     if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1452       ERR( "hbin_sub block invalid\n");
1453       goto error;
1454     }
1455
1456     /* nk block */
1457     nk = (nt_nk*)&(hbin_sub->data[0]);
1458     if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1459       ERR( "special nk block not found\n");
1460       goto error;
1461     }
1462
1463     if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1464     fprintf(f,"WINE REGISTRY Version 2");
1465     _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1466     fclose(f);
1467
1468 error:
1469     UnmapViewOfFile( base );
1470 error1:
1471     CloseHandle(hFile);
1472     return ret;
1473 }
1474
1475 /* convert native registry to wine format and load it via server call [Internal] */
1476 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1477 {
1478     LPSTR tmp = NULL;
1479
1480     switch (reg_type) {
1481         case REG_WINNT:
1482             /* FIXME: following function doesn't really convert yet */
1483             tmp = _convert_winnt_registry_to_wine_format(fn,level);
1484             break;
1485         case REG_WIN95:
1486             tmp = _convert_win95_registry_to_wine_format(fn,level);
1487             break;
1488         case REG_WIN31:
1489             ERR("Don't know how to convert native 3.1 registry yet.\n");
1490             break;
1491         default:
1492             ERR("Unknown registry format parameter (%d)\n",reg_type);
1493             break;
1494     }
1495
1496     if (tmp != NULL) {
1497         load_wine_registry(hkey,tmp);
1498         TRACE("File %s successfully converted to %s and loaded to registry.\n",
1499               debugstr_w(fn), tmp);
1500         unlink(tmp);
1501     }
1502     else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1503     free(tmp);
1504 }
1505
1506 /* load all native windows registry files [Internal] */
1507 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1508                                     HKEY hkey_users_default )
1509 {
1510     int reg_type;
1511     WCHAR windir[MAX_PATHNAME_LEN];
1512     WCHAR path[MAX_PATHNAME_LEN];
1513     OBJECT_ATTRIBUTES attr;
1514     UNICODE_STRING nameW;
1515     HKEY hkey;
1516
1517     static const WCHAR WineW[] = {'W','i','n','e',0};
1518     static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1519     static const WCHAR empty_strW[] = { 0 };
1520     static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1521     static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1522     static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1523                                   'S','y','s','t','e','m','\\',
1524                                   'C','l','o','n','e',0};
1525
1526     attr.Length = sizeof(attr);
1527     attr.RootDirectory = 0;
1528     attr.ObjectName = &nameW;
1529     attr.Attributes = 0;
1530     attr.SecurityDescriptor = NULL;
1531     attr.SecurityQualityOfService = NULL;
1532
1533     GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1534
1535     reg_type = _get_reg_type();
1536     switch (reg_type) {
1537         case REG_WINNT: {
1538             HKEY hkey;
1539             static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1540             static const WCHAR defaultW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','d','e','f','a','u','l','t',0};
1541             static const WCHAR systemW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1542             static const WCHAR softwareW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','o','f','t','w','a','r','e',0};
1543             static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1544             static const WCHAR securityW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','e','c','u','r','i','t','y',0};
1545
1546             /* user specific ntuser.dat */
1547             if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1548                 strcatW(path, ntuser_datW);
1549                 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1550             }
1551
1552             /* default user.dat */
1553             if (hkey_users_default) {
1554                 strcpyW(path, windir);
1555                 strcatW(path, defaultW);
1556                 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1557             }
1558
1559             /*
1560             * FIXME
1561             *  map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1562             */
1563             RtlInitUnicodeString( &nameW, System );
1564             if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1565             {
1566                 strcpyW(path, windir);
1567                 strcatW(path, systemW);
1568                 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1569                 NtClose( hkey );
1570             }
1571             RtlInitUnicodeString( &nameW, Software );
1572             if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1573             {
1574                 strcpyW(path, windir);
1575                 strcatW(path, softwareW);
1576                 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1577                 NtClose( hkey );
1578             }
1579
1580             strcpyW(path, windir);
1581             strcatW(path, samW);
1582             _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1583
1584             strcpyW(path,windir);
1585             strcatW(path, securityW);
1586             _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1587
1588             /* this key is generated when the nt-core booted successfully */
1589             RtlInitUnicodeString( &nameW, Clone );
1590             if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1591             break;
1592         }
1593
1594         case REG_WIN95:
1595         {
1596             static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1597             static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1598             static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1599             static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1600
1601             _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1602
1603             strcpyW(path, windir);
1604             strcatW(path, system_datW);
1605             _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1606
1607             RtlInitUnicodeString( &nameW, ClassesRootW );
1608             if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1609             {
1610                 strcpyW(path, windir);
1611                 strcatW(path, classes_datW);
1612                 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1613                 NtClose( hkey );
1614             }
1615
1616             if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1617                 /* user specific user.dat */
1618                 strcatW(path, user_datW);
1619                 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1620
1621                 /* default user.dat */
1622                 if (hkey_users_default) {
1623                     strcpyW(path, windir);
1624                     strcatW(path, user_datW);
1625                     _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1626                 }
1627             } else {
1628                 strcpyW(path, windir);
1629                 strcatW(path, user_datW);
1630                 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1631             }
1632             break;
1633         }
1634
1635         case REG_WIN31:
1636             /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1637             _w31_loadreg();
1638             break;
1639
1640         case REG_DONTLOAD:
1641             TRACE("REG_DONTLOAD\n");
1642             break;
1643
1644         default:
1645             ERR("switch: no match (%d)\n",reg_type);
1646             break;
1647
1648     }
1649 }
1650
1651 /* load global registry files (stored in /etc/wine) [Internal] */
1652 static void _load_global_registry( HKEY hkey_local_machine, HKEY hkey_users )
1653 {
1654     TRACE("(void)\n");
1655
1656     /* Load the global HKU hive directly from sysconfdir */
1657     load_wine_registry( hkey_users, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1658
1659     /* Load the global machine defaults directly from sysconfdir */
1660     load_wine_registry( hkey_local_machine, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1661 }
1662
1663 /* load home registry files (stored in ~/.wine) [Internal] */
1664 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1665                                  HKEY hkey_users_default )
1666 {
1667     LPCSTR confdir = wine_get_config_dir();
1668     LPSTR tmp = _xmalloc(strlen(confdir)+20);
1669
1670     strcpy(tmp,confdir);
1671     strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1672     load_wine_registry(hkey_users_default,tmp);
1673
1674     strcpy(tmp,confdir);
1675     strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1676     load_wine_registry(hkey_current_user,tmp);
1677
1678     strcpy(tmp,confdir);
1679     strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1680     load_wine_registry(hkey_local_machine,tmp);
1681
1682     free(tmp);
1683 }
1684
1685 /* load all registry (native and global and home) */
1686 void SHELL_LoadRegistry( void )
1687 {
1688     HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user;
1689     OBJECT_ATTRIBUTES attr;
1690     UNICODE_STRING nameW;
1691
1692     static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1693     static const WCHAR UserW[] = {'U','s','e','r',0};
1694     static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1695     static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0};
1696     static const WCHAR load_win_reg_filesW[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1697     static const WCHAR load_global_reg_filesW[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1698     static const WCHAR load_home_reg_filesW[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1699
1700     TRACE("(void)\n");
1701
1702     if (!CLIENT_IsBootThread()) return;  /* already loaded */
1703
1704     attr.Length = sizeof(attr);
1705     attr.RootDirectory = 0;
1706     attr.ObjectName = &nameW;
1707     attr.Attributes = 0;
1708     attr.SecurityDescriptor = NULL;
1709     attr.SecurityQualityOfService = NULL;
1710
1711     RtlInitUnicodeString( &nameW, MachineW );
1712     NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1713     RtlInitUnicodeString( &nameW, UserW );
1714     NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1715
1716     attr.RootDirectory = hkey_users;
1717     RtlInitUnicodeString( &nameW, DefaultW );
1718     if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1719     {
1720         ERR("Cannot create HKEY_USERS/.Default\n" );
1721         ExitProcess(1);
1722     }
1723     RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1724
1725     _set_registry_levels(0,0,0);
1726     _allocate_default_keys();
1727     if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1))
1728         _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1729     if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1))
1730         _load_global_registry( hkey_local_machine, hkey_users );
1731     _set_registry_levels(1,0,0);
1732     if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1))
1733         _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1734     _init_registry_saving( hkey_local_machine, hkey_current_user, hkey_users_default );
1735     NtClose(hkey_users_default);
1736     NtClose(hkey_current_user);
1737     NtClose(hkey_users);
1738     NtClose(hkey_local_machine);
1739 }