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