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