Remove from docs / config tool useless / obsoleted options.
[wine/wine64.git] / misc / registry.c
blob438376a595da0c529b14b29d6c135c61029e1c4a
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
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.
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.
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.
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
26 * NOTES
27 * When changing this file, please re-run the regtest program to ensure
28 * the conditions are handled properly.
30 * TODO
31 * Security access
32 * Option handling
33 * Time for RegEnumKey*, RegQueryInfoKey*
36 #include "config.h"
37 #include "wine/port.h"
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
51 #endif
53 #include "windef.h"
54 #include "winerror.h"
55 #include "winreg.h"
57 #include "wine/winbase16.h"
58 #include "wine/library.h"
59 #include "wine/server.h"
60 #include "wine/unicode.h"
61 #include "file.h"
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(reg);
67 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
68 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
70 /* relative in ~user/.wine/ : */
71 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
72 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
73 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
75 static const WCHAR ClassesRootW[] = {'M','a','c','h','i','n','e','\\',
76 'S','o','f','t','w','a','r','e','\\',
77 'C','l','a','s','s','e','s',0};
79 #define IS_OPTION_FALSE(ch) \
80 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
82 /* _xmalloc [Internal] */
83 static void *_xmalloc( size_t size )
85 void *res;
87 res = malloc (size ? size : 1);
88 if (res == NULL) {
89 WARN("Virtual memory exhausted.\n");
90 exit (1);
92 return res;
95 /* _xstrdup [Internal] */
96 static LPSTR _xstrdup(LPCSTR str)
98 LPSTR ret;
99 size_t len = strlen(str) + 1;
101 if (!str) return NULL;
102 ret = _xmalloc( len );
103 memcpy( ret, str, len );
104 return ret;
107 /* convert ansi string to unicode [Internal] */
108 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
110 LPWSTR ret;
111 size_t lenW;
113 if (!strA) return NULL;
114 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
115 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
116 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
117 ret[lenW] = 0;
118 return ret;
121 /* dump a Unicode string with proper escaping [Internal] */
122 /* FIXME: this code duplicates server/unicode.c */
123 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
125 static const char escapes[32] = ".......abtnvfr.............e....";
126 char buffer[256];
127 LPSTR pos = buffer;
128 int count = 0;
130 for (; len; str++, len--)
132 if (pos > buffer + sizeof(buffer) - 8)
134 fwrite( buffer, pos - buffer, 1, f );
135 count += pos - buffer;
136 pos = buffer;
138 if (*str > 127) /* hex escape */
140 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
141 pos += sprintf( pos, "\\x%04x", *str );
142 else
143 pos += sprintf( pos, "\\x%x", *str );
144 continue;
146 if (*str < 32) /* octal or C escape */
148 if (!*str && len == 1) continue; /* do not output terminating NULL */
149 if (escapes[*str] != '.')
150 pos += sprintf( pos, "\\%c", escapes[*str] );
151 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
152 pos += sprintf( pos, "\\%03o", *str );
153 else
154 pos += sprintf( pos, "\\%o", *str );
155 continue;
157 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
158 *pos++ = *str;
160 fwrite( buffer, pos - buffer, 1, f );
161 count += pos - buffer;
162 return count;
165 /* convert ansi string to unicode and dump with proper escaping [Internal] */
166 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
168 WCHAR *strW;
169 int ret;
171 if (strA == NULL) return 0;
172 strW = _strdupnAtoW(strA,len);
173 ret = _dump_strW(strW,len,f,escape);
174 free(strW);
175 return ret;
178 /* a key value */
179 /* FIXME: this code duplicates server/registry.c */
180 struct key_value {
181 WCHAR *nameW; /* value name */
182 int type; /* value type */
183 size_t len; /* value data length in bytes */
184 void *data; /* pointer to value data */
187 /* dump a value to a text file */
188 /* FIXME: this code duplicates server/registry.c */
189 static void _dump_value(struct key_value *value,FILE *f)
191 int i, count;
193 if (value->nameW[0]) {
194 fputc( '\"', f );
195 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
196 count += fprintf( f, "\"=" );
198 else count = fprintf( f, "@=" );
200 switch(value->type) {
201 case REG_SZ:
202 case REG_EXPAND_SZ:
203 case REG_MULTI_SZ:
204 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
205 fputc( '\"', f );
206 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
207 fputc( '\"', f );
208 break;
209 case REG_DWORD:
210 if (value->len == sizeof(DWORD)) {
211 DWORD dw;
212 memcpy( &dw, value->data, sizeof(DWORD) );
213 fprintf( f, "dword:%08lx", dw );
214 break;
216 /* else fall through */
217 default:
218 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
219 else count += fprintf( f, "hex(%x):", value->type );
220 for (i = 0; i < value->len; i++) {
221 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
222 if (i < value->len-1) {
223 fputc( ',', f );
224 if (++count > 76) {
225 fprintf( f, "\\\n " );
226 count = 2;
230 break;
232 fputc( '\n', f );
235 /******************************************************************/
236 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
238 reghack - windows 3.11 registry data format demo program.
240 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
241 a combined hash table and tree description, and finally a text table.
243 The header is obvious from the struct header. The taboff1 and taboff2
244 fields are always 0x20, and their usage is unknown.
246 The 8-byte entry table has various entry types.
248 tabent[0] is a root index. The second word has the index of the root of
249 the directory.
250 tabent[1..hashsize] is a hash table. The first word in the hash entry is
251 the index of the key/value that has that hash. Data with the same
252 hash value are on a circular list. The other three words in the
253 hash entry are always zero.
254 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
255 entry: dirent and keyent/valent. They are identified by context.
256 tabent[freeidx] is the first free entry. The first word in a free entry
257 is the index of the next free entry. The last has 0 as a link.
258 The other three words in the free list are probably irrelevant.
260 Entries in text table are preceded by a word at offset-2. This word
261 has the value (2*index)+1, where index is the referring keyent/valent
262 entry in the table. I have no suggestion for the 2* and the +1.
263 Following the word, there are N bytes of data, as per the keyent/valent
264 entry length. The offset of the keyent/valent entry is from the start
265 of the text table to the first data byte.
267 This information is not available from Microsoft. The data format is
268 deduced from the reg.dat file by me. Mistakes may
269 have been made. I claim no rights and give no guarantees for this program.
271 Tor Sjøwall, tor@sn.no
274 /* reg.dat header format */
275 struct _w31_header {
276 char cookie[8]; /* 'SHCC3.10' */
277 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
278 unsigned long taboff2; /* offset of index table (??) = 0x20 */
279 unsigned long tabcnt; /* number of entries in index table */
280 unsigned long textoff; /* offset of text part */
281 unsigned long textsize; /* byte size of text part */
282 unsigned short hashsize; /* hash size */
283 unsigned short freeidx; /* free index */
286 /* generic format of table entries */
287 struct _w31_tabent {
288 unsigned short w0, w1, w2, w3;
291 /* directory tabent: */
292 struct _w31_dirent {
293 unsigned short sibling_idx; /* table index of sibling dirent */
294 unsigned short child_idx; /* table index of child dirent */
295 unsigned short key_idx; /* table index of key keyent */
296 unsigned short value_idx; /* table index of value valent */
299 /* key tabent: */
300 struct _w31_keyent {
301 unsigned short hash_idx; /* hash chain index for string */
302 unsigned short refcnt; /* reference count */
303 unsigned short length; /* length of string */
304 unsigned short string_off; /* offset of string in text table */
307 /* value tabent: */
308 struct _w31_valent {
309 unsigned short hash_idx; /* hash chain index for string */
310 unsigned short refcnt; /* reference count */
311 unsigned short length; /* length of string */
312 unsigned short string_off; /* offset of string in text table */
315 /* recursive helper function to display a directory tree [Internal] */
316 static void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
318 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
319 struct _w31_dirent *dir;
320 struct _w31_keyent *key;
321 struct _w31_valent *val;
322 HKEY subkey = 0;
323 OBJECT_ATTRIBUTES attr;
324 UNICODE_STRING nameW, valueW;
325 static WCHAR tail[400];
327 attr.Length = sizeof(attr);
328 attr.RootDirectory = hkey;
329 attr.ObjectName = &nameW;
330 attr.Attributes = 0;
331 attr.SecurityDescriptor = NULL;
332 attr.SecurityQualityOfService = NULL;
333 RtlInitUnicodeString( &valueW, NULL );
335 while (idx!=0) {
336 dir=(struct _w31_dirent*)&tab[idx];
338 if (dir->key_idx) {
339 DWORD len;
340 key = (struct _w31_keyent*)&tab[dir->key_idx];
342 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
343 &txt[key->string_off], key->length);
344 tail[len/sizeof(WCHAR)] = 0;
346 /* all toplevel entries AND the entries in the
347 * toplevel subdirectory belong to \SOFTWARE\Classes
349 if (!level && !strcmpW(tail,classesW))
351 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
352 idx=dir->sibling_idx;
353 continue;
356 if (subkey) NtClose( subkey );
357 RtlInitUnicodeString( &nameW, tail );
358 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
360 /* only add if leaf node or valued node */
361 if (dir->value_idx!=0||dir->child_idx==0) {
362 if (dir->value_idx) {
363 DWORD len;
364 val=(struct _w31_valent*)&tab[dir->value_idx];
365 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
366 &txt[val->string_off], val->length);
367 tail[len/sizeof(WCHAR)] = 0;
368 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
371 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
372 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
373 idx=dir->sibling_idx;
375 if (subkey) NtClose( subkey );
379 /******************************************************************************
380 * _w31_loadreg [Internal]
382 static void _w31_loadreg(void)
384 HANDLE hf;
385 HKEY root;
386 OBJECT_ATTRIBUTES attr;
387 UNICODE_STRING nameW;
388 struct _w31_header head;
389 struct _w31_tabent *tab;
390 unsigned char *txt;
391 unsigned int len;
392 OFSTRUCT ofs;
393 BY_HANDLE_FILE_INFORMATION hfinfo;
394 time_t lastmodified;
395 DWORD r;
397 TRACE("(void)\n");
399 hf = (HANDLE)OpenFile("reg.dat",&ofs,OF_READ);
400 if (hf==(HANDLE)HFILE_ERROR) return;
402 /* read & dump header */
403 if (!ReadFile(hf,&head,sizeof(head),&r,NULL) || r!=sizeof(head)) {
404 ERR("reg.dat is too short.\n");
405 CloseHandle(hf);
406 return;
408 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
409 ERR("reg.dat has bad signature.\n");
410 CloseHandle(hf);
411 return;
414 len = head.tabcnt * sizeof(struct _w31_tabent);
415 /* read and dump index table */
416 tab = _xmalloc(len);
417 if (!ReadFile(hf,tab,len,&r,NULL) || r!=len) {
418 ERR("couldn't read %d bytes.\n",len);
419 free(tab);
420 CloseHandle(hf);
421 return;
424 /* read text */
425 txt = _xmalloc(head.textsize);
426 if (-1==SetFilePointer(hf,head.textoff,NULL,SEEK_SET)) {
427 ERR("couldn't seek to textblock.\n");
428 free(tab);
429 free(txt);
430 CloseHandle(hf);
431 return;
433 if (!ReadFile(hf,txt,head.textsize,&r,NULL) || r!=head.textsize) {
434 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
435 free(tab);
436 free(txt);
437 CloseHandle(hf);
438 return;
441 if (!GetFileInformationByHandle(hf,&hfinfo)) {
442 ERR("GetFileInformationByHandle failed?.\n");
443 free(tab);
444 free(txt);
445 CloseHandle(hf);
446 return;
448 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
450 attr.Length = sizeof(attr);
451 attr.RootDirectory = 0;
452 attr.ObjectName = &nameW;
453 attr.Attributes = 0;
454 attr.SecurityDescriptor = NULL;
455 attr.SecurityQualityOfService = NULL;
456 RtlInitUnicodeString( &nameW, ClassesRootW );
458 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
460 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
461 NtClose( root );
463 free(tab);
464 free(txt);
465 CloseHandle(hf);
466 return;
469 /***********************************************************************************/
470 /* windows 95 registry loader */
471 /***********************************************************************************/
473 /* SECTION 1: main header
475 * once at offset 0
477 #define W95_REG_CREG_ID 0x47455243
479 typedef struct {
480 DWORD id; /* "CREG" = W95_REG_CREG_ID */
481 DWORD version; /* ???? 0x00010000 */
482 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
483 DWORD uk2; /* 0x0c */
484 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
485 WORD uk3;
486 DWORD uk[3];
487 /* rgkn */
488 } _w95creg;
490 /* SECTION 2: Directory information (tree structure)
492 * once on offset 0x20
494 * structure: [rgkn][dke]* (repeat till last_dke is reached)
496 #define W95_REG_RGKN_ID 0x4e4b4752
498 typedef struct {
499 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
500 DWORD size; /* Size of the RGKN-block */
501 DWORD root_off; /* Rel. Offset of the root-record */
502 DWORD last_dke; /* Offset to last DKE ? */
503 DWORD uk[4];
504 } _w95rgkn;
506 /* Disk Key Entry Structure
508 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
509 * hive itself. It looks the same like other keys. Even the ID-number can
510 * be any value.
512 * The "hash"-value is a value representing the key's name. Windows will not
513 * search for the name, but for a matching hash-value. if it finds one, it
514 * will compare the actual string info, otherwise continue with the next key.
515 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
516 * of the string which are smaller than 0x80 (128) to this D-Word.
518 * If you want to modify key names, also modify the hash-values, since they
519 * cannot be found again (although they would be displayed in REGEDIT)
520 * End of list-pointers are filled with 0xFFFFFFFF
522 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
523 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
524 * structure) and reading another RGDB_section.
526 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
527 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
528 * The remaining space between last_dke and the offset calculated from
529 * rgkn->size seems to be free for use for more dke:s.
530 * So it seems if more dke:s are added, they are added to that space and
531 * last_dke is grown, and in case that "free" space is out, the space
532 * gets grown and rgkn->size gets adjusted.
534 * there is a one to one relationship between dke and dkh
536 /* key struct, once per key */
537 typedef struct {
538 DWORD x1; /* Free entry indicator(?) */
539 DWORD hash; /* sum of bytes of keyname */
540 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
541 DWORD prevlvl; /* offset of previous key */
542 DWORD nextsub; /* offset of child key */
543 DWORD next; /* offset of sibling key */
544 WORD nrLS; /* id inside the rgdb block */
545 WORD nrMS; /* number of the rgdb block */
546 } _w95dke;
548 /* SECTION 3: key information, values and data
550 * structure:
551 * section: [blocks]* (repeat creg->rgdb_num times)
552 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
553 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
555 * An interesting relationship exists in RGDB_section. The DWORD value
556 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
557 * I have no idea at the moment what this means. (Kevin Cozens)
560 /* block header, once per block */
561 #define W95_REG_RGDB_ID 0x42444752
563 typedef struct {
564 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
565 DWORD size; /* 0x04 */
566 DWORD uk1; /* 0x08 */
567 DWORD uk2; /* 0x0c */
568 DWORD uk3; /* 0x10 */
569 DWORD uk4; /* 0x14 */
570 DWORD uk5; /* 0x18 */
571 DWORD uk6; /* 0x1c */
572 /* dkh */
573 } _w95rgdb;
575 /* Disk Key Header structure (RGDB part), once per key */
576 typedef struct {
577 DWORD nextkeyoff; /* 0x00 offset to next dkh */
578 WORD nrLS; /* 0x04 id inside the rgdb block */
579 WORD nrMS; /* 0x06 number of the rgdb block */
580 DWORD bytesused; /* 0x08 */
581 WORD keynamelen; /* 0x0c len of name */
582 WORD values; /* 0x0e number of values */
583 DWORD xx1; /* 0x10 */
584 char name[1]; /* 0x14 */
585 /* dkv */ /* 0x14 + keynamelen */
586 } _w95dkh;
588 /* Disk Key Value structure, once per value */
589 typedef struct {
590 DWORD type; /* 0x00 */
591 DWORD x1; /* 0x04 */
592 WORD valnamelen; /* 0x08 length of name, 0 is default key */
593 WORD valdatalen; /* 0x0A length of data */
594 char name[1]; /* 0x0c */
595 /* raw data */ /* 0x0c + valnamelen */
596 } _w95dkv;
598 /******************************************************************************
599 * _w95_lookup_dkh [Internal]
601 * seeks the dkh belonging to a dke
603 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
605 _w95rgdb * rgdb;
606 _w95dkh * dkh;
607 int i;
609 /* get the beginning of the rgdb datastore */
610 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
612 /* check: requested block < last_block) */
613 if (creg->rgdb_num <= nrMS) {
614 ERR("registry file corrupt! requested block no. beyond end.\n");
615 goto error;
618 /* find the right block */
619 for(i=0; i<nrMS ;i++) {
620 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
621 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
622 goto error;
624 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
627 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
629 do {
630 if(nrLS==dkh->nrLS ) return dkh;
631 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
632 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
634 error:
635 return NULL;
638 /******************************************************************************
639 * _w95_dump_dkv [Internal]
641 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
643 _w95dkv * dkv;
644 int i;
646 /* first value block */
647 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
649 /* loop through the values */
650 for (i=0; i< dkh->values; i++) {
651 struct key_value value;
652 WCHAR *pdata;
654 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
655 value.type = dkv->type;
656 value.len = dkv->valdatalen;
658 value.data = &(dkv->name[dkv->valnamelen]);
659 pdata = NULL;
660 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
661 pdata = _strdupnAtoW(value.data,value.len);
662 value.len *= 2;
664 if (pdata != NULL) value.data = pdata;
666 _dump_value(&value,f);
667 free(value.nameW);
668 if (pdata != NULL) free(pdata);
670 /* next value */
671 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
673 return TRUE;
676 /******************************************************************************
677 * _w95_dump_dke [Internal]
679 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
681 _w95dkh * dkh;
682 LPSTR new_key_name = NULL;
684 /* special root key */
685 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
687 /* parse the one subkey */
688 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
689 /* has no sibling keys */
690 return FALSE;
693 /* search subblock */
694 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
695 ERR("dke pointing to missing dkh !\n");
696 return FALSE;
699 if (level <= 0) {
700 /* create new subkey name */
701 size_t len = strlen(key_name);
702 new_key_name = _xmalloc(len+dkh->keynamelen+2);
703 memcpy( new_key_name, key_name, len );
704 if (len) new_key_name[len++] = '\\';
705 memcpy( new_key_name + len, dkh->name, dkh->keynamelen );
706 new_key_name[len + dkh->keynamelen] = 0;
708 /* walk sibling keys */
709 if (dke->next != 0xffffffff ) {
710 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
711 free(new_key_name);
712 return FALSE;
716 /* write the key path (something like [Software\\Microsoft\\..]) only if:
717 1) key has some values
718 2) key has no values and no subkeys
720 if (dkh->values > 0) {
721 /* there are some values */
722 fprintf(f,"\n[");
723 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
724 fprintf(f,"]\n");
725 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
726 free(new_key_name);
727 return FALSE;
730 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
731 /* no subkeys and no values */
732 fprintf(f,"\n[");
733 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
734 fprintf(f,"]\n");
736 } else new_key_name = _xstrdup(key_name);
738 /* next sub key */
739 if (dke->nextsub != 0xffffffff) {
740 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
741 free(new_key_name);
742 return FALSE;
746 free(new_key_name);
747 return TRUE;
749 /* end windows 95 loader */
751 /***********************************************************************************/
752 /* windows NT registry loader */
753 /***********************************************************************************/
755 /* NT REGISTRY LOADER */
757 #ifdef HAVE_SYS_MMAN_H
758 # include <sys/mman.h>
759 #endif
761 #ifndef MAP_FAILED
762 #define MAP_FAILED ((LPVOID)-1)
763 #endif
765 #define NT_REG_BLOCK_SIZE 0x1000
767 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
768 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
769 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
770 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
772 /* subblocks of nk */
773 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
774 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
775 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
777 #define NT_REG_KEY_BLOCK_TYPE 0x20
778 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
780 typedef struct {
781 DWORD id; /* 0x66676572 'regf'*/
782 DWORD uk1; /* 0x04 */
783 DWORD uk2; /* 0x08 */
784 FILETIME DateModified; /* 0x0c */
785 DWORD uk3; /* 0x14 */
786 DWORD uk4; /* 0x18 */
787 DWORD uk5; /* 0x1c */
788 DWORD uk6; /* 0x20 */
789 DWORD RootKeyBlock; /* 0x24 */
790 DWORD BlockSize; /* 0x28 */
791 DWORD uk7[116];
792 DWORD Checksum; /* at offset 0x1FC */
793 } nt_regf;
795 typedef struct {
796 DWORD blocksize;
797 BYTE data[1];
798 } nt_hbin_sub;
800 typedef struct {
801 DWORD id; /* 0x6E696268 'hbin' */
802 DWORD off_prev;
803 DWORD off_next;
804 DWORD uk1;
805 DWORD uk2; /* 0x10 */
806 DWORD uk3; /* 0x14 */
807 DWORD uk4; /* 0x18 */
808 DWORD size; /* 0x1C */
809 nt_hbin_sub hbin_sub; /* 0x20 */
810 } nt_hbin;
813 * the value_list consists of offsets to the values (vk)
815 typedef struct {
816 WORD SubBlockId; /* 0x00 0x6B6E */
817 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
818 FILETIME writetime; /* 0x04 */
819 DWORD uk1; /* 0x0C */
820 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
821 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
822 DWORD uk8; /* 0x18 */
823 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
824 DWORD uk2; /* 0x20 */
825 DWORD nr_values; /* 0x24 number of values */
826 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
827 DWORD off_sk; /* 0x2c Offset of the sk-Record */
828 DWORD off_class; /* 0x30 Offset of the Class-Name */
829 DWORD uk3; /* 0x34 */
830 DWORD uk4; /* 0x38 */
831 DWORD uk5; /* 0x3c */
832 DWORD uk6; /* 0x40 */
833 DWORD uk7; /* 0x44 */
834 WORD name_len; /* 0x48 name-length */
835 WORD class_len; /* 0x4a class-name length */
836 char name[1]; /* 0x4c key-name */
837 } nt_nk;
839 typedef struct {
840 DWORD off_nk; /* 0x00 */
841 DWORD name; /* 0x04 */
842 } hash_rec;
844 typedef struct {
845 WORD id; /* 0x00 0x666c */
846 WORD nr_keys; /* 0x06 */
847 hash_rec hash_rec[1];
848 } nt_lf;
851 list of subkeys without hash
853 li --+-->nk
855 +-->nk
857 typedef struct {
858 WORD id; /* 0x00 0x696c */
859 WORD nr_keys;
860 DWORD off_nk[1];
861 } nt_li;
864 this is a intermediate node
866 ri --+-->li--+-->nk
868 | +-->nk
870 +-->li--+-->nk
872 +-->nk
874 typedef struct {
875 WORD id; /* 0x00 0x6972 */
876 WORD nr_li; /* 0x02 number off offsets */
877 DWORD off_li[1]; /* 0x04 points to li */
878 } nt_ri;
880 typedef struct {
881 WORD id; /* 0x00 'vk' */
882 WORD nam_len;
883 DWORD data_len;
884 DWORD data_off;
885 DWORD type;
886 WORD flag;
887 WORD uk1;
888 char name[1];
889 } nt_vk;
892 * gets a value
894 * vk->flag:
895 * 0 value is a default value
896 * 1 the value has a name
898 * vk->data_len
899 * len of the whole data block
900 * - reg_sz (unicode)
901 * bytes including the terminating \0 = 2*(number_of_chars+1)
902 * - reg_dword, reg_binary:
903 * if highest bit of data_len is set data_off contains the value
905 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
907 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
908 struct key_value value;
910 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
911 ERR("unknown block found (0x%04x), please report!\n", vk->id);
912 return FALSE;
915 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
916 value.type = vk->type;
917 value.len = (vk->data_len & 0x7fffffff);
918 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
920 _dump_value(&value,f);
921 free(value.nameW);
923 return TRUE;
926 /* it's called from _nt_dump_lf() */
927 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
930 * get the subkeys
932 * this structure contains the hash of a keyname and points to all
933 * subkeys
935 * exception: if the id is 'il' there are no hash values and every
936 * dword is a offset
938 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
940 int i;
942 if (lf->id == NT_REG_HASH_BLOCK_ID) {
943 if (subkeys != lf->nr_keys) goto error1;
945 for (i=0; i<lf->nr_keys; i++)
946 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
947 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
948 nt_li * li = (nt_li*)lf;
949 if (subkeys != li->nr_keys) goto error1;
951 for (i=0; i<li->nr_keys; i++)
952 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
953 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
954 nt_ri * ri = (nt_ri*)lf;
955 int li_subkeys = 0;
957 /* count all subkeys */
958 for (i=0; i<ri->nr_li; i++) {
959 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
960 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
961 li_subkeys += li->nr_keys;
964 /* check number */
965 if (subkeys != li_subkeys) goto error1;
967 /* loop through the keys */
968 for (i=0; i<ri->nr_li; i++) {
969 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
970 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
972 } else goto error2;
974 return TRUE;
976 error2:
977 if (lf->id == 0x686c)
978 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
979 else
980 ERR("unknown node id 0x%04x, please report!\n", lf->id);
981 return TRUE;
983 error1:
984 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
985 return FALSE;
987 error:
988 ERR("error reading lf block\n");
989 return FALSE;
992 /* _nt_dump_nk [Internal] */
993 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
995 unsigned int n;
996 DWORD *vl;
997 LPSTR new_key_name = NULL;
999 TRACE("%s\n", key_name);
1001 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
1002 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1003 return FALSE;
1006 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1007 ERR("registry file corrupt!\n");
1008 return FALSE;
1011 /* create the new key */
1012 if (level <= 0) {
1013 /* create new subkey name */
1014 size_t len = strlen(key_name);
1015 new_key_name = _xmalloc( len+nk->name_len+2 );
1016 memcpy( new_key_name, key_name, len );
1017 if (len) new_key_name[len++] = '\\';
1018 memcpy( new_key_name + len, nk->name, nk->name_len );
1019 new_key_name[len + nk->name_len] = 0;
1021 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1022 1) key has some values
1023 2) key has no values and no subkeys
1025 if (nk->nr_values > 0) {
1026 /* there are some values */
1027 fprintf(f,"\n[");
1028 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1029 fprintf(f,"]\n");
1031 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1032 /* no subkeys and no values */
1033 fprintf(f,"\n[");
1034 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1035 fprintf(f,"]\n");
1038 /* loop trough the value list */
1039 vl = (DWORD *)(base+nk->valuelist_off+4);
1040 for (n=0; n<nk->nr_values; n++) {
1041 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1042 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1043 free(new_key_name);
1044 return FALSE;
1047 } else new_key_name = _xstrdup(key_name);
1049 /* loop through the subkeys */
1050 if (nk->nr_subkeys) {
1051 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1052 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1053 free(new_key_name);
1054 return FALSE;
1058 free(new_key_name);
1059 return TRUE;
1062 /* end nt loader */
1064 /**********************************************************************************
1065 * _set_registry_levels [Internal]
1067 * set level to 0 for loading system files
1068 * set level to 1 for loading user files
1070 static void _set_registry_levels(int level,int saving,int period)
1072 SERVER_START_REQ( set_registry_levels )
1074 req->current = level;
1075 req->saving = saving;
1076 req->period = period;
1077 wine_server_call( req );
1079 SERVER_END_REQ;
1082 /* _save_at_exit [Internal] */
1083 static void _save_at_exit(HKEY hkey,LPCSTR path)
1085 LPCSTR confdir = wine_get_config_dir();
1087 SERVER_START_REQ( save_registry_atexit )
1089 req->hkey = hkey;
1090 wine_server_add_data( req, confdir, strlen(confdir) );
1091 wine_server_add_data( req, path, strlen(path)+1 );
1092 wine_server_call( req );
1094 SERVER_END_REQ;
1097 /******************************************************************************
1098 * _allocate_default_keys [Internal]
1099 * Registry initialisation, allocates some default keys.
1101 static void _allocate_default_keys(void)
1103 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1104 'P','e','r','f','S','t','a','t','s','\\',
1105 'S','t','a','t','D','a','t','a',0};
1106 HKEY hkey;
1107 OBJECT_ATTRIBUTES attr;
1108 UNICODE_STRING nameW;
1110 TRACE("(void)\n");
1112 attr.Length = sizeof(attr);
1113 attr.RootDirectory = 0;
1114 attr.ObjectName = &nameW;
1115 attr.Attributes = 0;
1116 attr.SecurityDescriptor = NULL;
1117 attr.SecurityQualityOfService = NULL;
1119 RtlInitUnicodeString( &nameW, StatDataW );
1120 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1123 #define REG_DONTLOAD -1
1124 #define REG_WIN31 0
1125 #define REG_WIN95 1
1126 #define REG_WINNT 2
1128 /* return the type of native registry [Internal] */
1129 static int _get_reg_type(void)
1131 WCHAR windir[MAX_PATHNAME_LEN];
1132 WCHAR tmp[MAX_PATHNAME_LEN];
1133 int ret = REG_WIN31;
1134 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};
1135 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1137 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1139 /* test %windir%/system32/config/system --> winnt */
1140 strcpyW(tmp, windir);
1141 strcatW(tmp, nt_reg_pathW);
1142 if(GetFileAttributesW(tmp) != (DWORD)-1)
1143 ret = REG_WINNT;
1144 else
1146 /* test %windir%/system.dat --> win95 */
1147 strcpyW(tmp, windir);
1148 strcatW(tmp, win9x_reg_pathW);
1149 if(GetFileAttributesW(tmp) != (DWORD)-1)
1150 ret = REG_WIN95;
1153 return ret;
1156 /* load the registry file in wine format [Internal] */
1157 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1159 HANDLE file;
1160 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1161 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1163 SERVER_START_REQ( load_registry )
1165 req->hkey = hkey;
1166 req->file = file;
1167 wine_server_call( req );
1169 SERVER_END_REQ;
1170 CloseHandle( file );
1174 /* generate and return the name of the tmp file and associated stream [Internal] */
1175 static LPSTR _get_tmp_fn(FILE **f)
1177 LPSTR ret;
1178 int tmp_fd,count;
1180 ret = _xmalloc(50);
1181 for (count = 0;;) {
1182 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1183 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1184 if (errno != EEXIST) {
1185 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1186 free(ret);
1187 *f = NULL;
1188 return NULL;
1192 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1193 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1194 close(tmp_fd);
1195 free(ret);
1196 return NULL;
1199 return ret;
1202 /* convert win95 native registry file to wine format [Internal] */
1203 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1205 int fd;
1206 FILE *f;
1207 DOS_FULL_NAME full_name;
1208 void *base;
1209 LPSTR ret = NULL;
1210 struct stat st;
1212 _w95creg *creg;
1213 _w95rgkn *rgkn;
1214 _w95dke *dke, *root_dke;
1216 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1218 /* map the registry into the memory */
1219 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1220 if ((fstat(fd, &st) == -1)) goto error1;
1221 if (!st.st_size) goto error1;
1222 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1224 /* control signature */
1225 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1226 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1227 debugstr_w(fn));
1228 goto error;
1231 creg = base;
1232 /* load the header (rgkn) */
1233 rgkn = (_w95rgkn*)(creg + 1);
1234 if (rgkn->id != W95_REG_RGKN_ID) {
1235 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1236 goto error;
1238 if (rgkn->root_off != 0x20) {
1239 ERR("rgkn->root_off not 0x20, please report !\n");
1240 goto error;
1242 if (rgkn->last_dke > rgkn->size)
1244 ERR("registry file corrupt! last_dke > size!\n");
1245 goto error;
1247 /* verify last dke */
1248 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1249 if (dke->x1 != 0x80000000)
1250 { /* wrong magic */
1251 ERR("last dke invalid !\n");
1252 goto error;
1254 if (rgkn->size > creg->rgdb_off)
1256 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1257 goto error;
1259 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1260 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1262 ERR("registry file corrupt! invalid root dke !\n");
1263 goto error;
1266 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1267 fprintf(f,"WINE REGISTRY Version 2");
1268 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1269 fclose(f);
1271 error:
1272 if(ret == NULL) {
1273 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1274 ERR("Please report this.\n");
1275 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1278 munmap(base, st.st_size);
1279 error1:
1280 close(fd);
1281 return ret;
1284 /* convert winnt native registry file to wine format [Internal] */
1285 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1287 FILE *f;
1288 void *base;
1289 LPSTR ret = NULL;
1290 HANDLE hFile;
1291 HANDLE hMapping;
1292 OBJECT_ATTRIBUTES attr;
1293 LARGE_INTEGER lg_int;
1294 NTSTATUS nts;
1295 SIZE_T len;
1297 nt_regf *regf;
1298 nt_hbin *hbin;
1299 nt_hbin_sub *hbin_sub;
1300 nt_nk *nk;
1302 TRACE("%s\n", debugstr_w(fn));
1304 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1305 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1306 attr.Length = sizeof(attr);
1307 attr.RootDirectory = 0;
1308 attr.ObjectName = NULL;
1309 attr.Attributes = 0;
1310 attr.SecurityDescriptor = NULL;
1311 attr.SecurityQualityOfService = NULL;
1313 lg_int.QuadPart = 0;
1314 nts = NtCreateSection( &hMapping,
1315 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1316 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1317 if (nts != STATUS_SUCCESS) goto error1;
1319 base = NULL; len = 0;
1320 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1321 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1322 PAGE_READONLY);
1323 NtClose( hMapping );
1324 if (nts != STATUS_SUCCESS) goto error1;
1326 /* control signature */
1327 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1328 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1329 debugstr_w(fn));
1330 goto error;
1333 /* start block */
1334 regf = base;
1336 /* hbin block */
1337 hbin = (nt_hbin*)((char*) base + 0x1000);
1338 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1339 ERR( "hbin block invalid\n");
1340 goto error;
1343 /* hbin_sub block */
1344 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1345 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1346 ERR( "hbin_sub block invalid\n");
1347 goto error;
1350 /* nk block */
1351 nk = (nt_nk*)&(hbin_sub->data[0]);
1352 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1353 ERR( "special nk block not found\n");
1354 goto error;
1357 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1358 fprintf(f,"WINE REGISTRY Version 2");
1359 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1360 fclose(f);
1362 error:
1363 NtUnmapViewOfSection( GetCurrentProcess(), base );
1364 error1:
1365 NtClose(hFile);
1366 return ret;
1369 /* convert native registry to wine format and load it via server call [Internal] */
1370 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1372 LPSTR tmp = NULL;
1374 switch (reg_type) {
1375 case REG_WINNT:
1376 /* FIXME: following function doesn't really convert yet */
1377 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1378 break;
1379 case REG_WIN95:
1380 tmp = _convert_win95_registry_to_wine_format(fn,level);
1381 break;
1382 case REG_WIN31:
1383 ERR("Don't know how to convert native 3.1 registry yet.\n");
1384 break;
1385 default:
1386 ERR("Unknown registry format parameter (%d)\n",reg_type);
1387 break;
1390 if (tmp != NULL) {
1391 load_wine_registry(hkey,tmp);
1392 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1393 debugstr_w(fn), tmp);
1394 unlink(tmp);
1396 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1397 free(tmp);
1400 /* load all native windows registry files [Internal] */
1401 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1402 HKEY hkey_users_default )
1404 int reg_type;
1405 WCHAR windir[MAX_PATHNAME_LEN];
1406 WCHAR path[MAX_PATHNAME_LEN];
1407 OBJECT_ATTRIBUTES attr;
1408 UNICODE_STRING nameW;
1409 HKEY hkey;
1411 static const WCHAR WineW[] = {'W','i','n','e',0};
1412 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1413 static const WCHAR empty_strW[] = { 0 };
1414 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1415 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1416 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1417 'S','y','s','t','e','m','\\',
1418 'C','l','o','n','e',0};
1420 attr.Length = sizeof(attr);
1421 attr.RootDirectory = 0;
1422 attr.ObjectName = &nameW;
1423 attr.Attributes = 0;
1424 attr.SecurityDescriptor = NULL;
1425 attr.SecurityQualityOfService = NULL;
1427 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1429 reg_type = _get_reg_type();
1430 switch (reg_type) {
1431 case REG_WINNT: {
1432 HKEY hkey;
1433 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1434 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};
1435 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};
1436 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};
1437 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1438 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};
1440 /* user specific ntuser.dat */
1441 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1442 strcatW(path, ntuser_datW);
1443 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1445 else
1447 MESSAGE("When you are running with a native NT directory specify\n");
1448 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1449 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1450 break;
1453 /* default user.dat */
1454 if (hkey_users_default) {
1455 strcpyW(path, windir);
1456 strcatW(path, defaultW);
1457 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1461 * FIXME
1462 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1464 RtlInitUnicodeString( &nameW, System );
1465 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1467 strcpyW(path, windir);
1468 strcatW(path, systemW);
1469 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1470 NtClose( hkey );
1472 RtlInitUnicodeString( &nameW, Software );
1473 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1475 strcpyW(path, windir);
1476 strcatW(path, softwareW);
1477 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1478 NtClose( hkey );
1481 strcpyW(path, windir);
1482 strcatW(path, samW);
1483 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1485 strcpyW(path,windir);
1486 strcatW(path, securityW);
1487 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1489 /* this key is generated when the nt-core booted successfully */
1490 RtlInitUnicodeString( &nameW, Clone );
1491 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1492 break;
1495 case REG_WIN95:
1497 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1498 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1499 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1500 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1502 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1504 strcpyW(path, windir);
1505 strcatW(path, system_datW);
1506 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1508 RtlInitUnicodeString( &nameW, ClassesRootW );
1509 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1511 strcpyW(path, windir);
1512 strcatW(path, classes_datW);
1513 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1514 NtClose( hkey );
1517 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1518 /* user specific user.dat */
1519 strcatW(path, user_datW);
1520 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1522 /* default user.dat */
1523 if (hkey_users_default) {
1524 strcpyW(path, windir);
1525 strcatW(path, user_datW);
1526 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1528 } else {
1529 strcpyW(path, windir);
1530 strcatW(path, user_datW);
1531 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1533 break;
1536 case REG_WIN31:
1537 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1538 _w31_loadreg();
1539 break;
1541 case REG_DONTLOAD:
1542 TRACE("REG_DONTLOAD\n");
1543 break;
1545 default:
1546 ERR("switch: no match (%d)\n",reg_type);
1547 break;
1552 /* load home registry files (stored in ~/.wine) [Internal] */
1553 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1554 HKEY hkey_users_default )
1556 LPCSTR confdir = wine_get_config_dir();
1557 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1559 strcpy(tmp,confdir);
1560 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1561 load_wine_registry(hkey_users_default,tmp);
1563 strcpy(tmp,confdir);
1564 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1565 load_wine_registry(hkey_current_user,tmp);
1567 strcpy(tmp,confdir);
1568 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1569 load_wine_registry(hkey_local_machine,tmp);
1571 free(tmp);
1575 /* load all registry (native and global and home) */
1576 void SHELL_LoadRegistry( void )
1578 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1579 OBJECT_ATTRIBUTES attr;
1580 UNICODE_STRING nameW;
1581 DWORD count;
1582 BOOL res;
1583 int all, period;
1584 char tmp[1024];
1586 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1587 static const WCHAR UserW[] = {'U','s','e','r',0};
1588 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1589 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1590 'S','o','f','t','w','a','r','e','\\',
1591 'W','i','n','e','\\',
1592 'W','i','n','e','\\',
1593 'C','o','n','f','i','g','\\',
1594 'R','e','g','i','s','t','r','y',0};
1595 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};
1596 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};
1597 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};
1598 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1599 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1600 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};
1601 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1603 TRACE("(void)\n");
1605 if (!CLIENT_IsBootThread()) return; /* already loaded */
1607 attr.Length = sizeof(attr);
1608 attr.RootDirectory = 0;
1609 attr.ObjectName = &nameW;
1610 attr.Attributes = 0;
1611 attr.SecurityDescriptor = NULL;
1612 attr.SecurityQualityOfService = NULL;
1614 RtlInitUnicodeString( &nameW, MachineW );
1615 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1616 RtlInitUnicodeString( &nameW, UserW );
1617 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1619 attr.RootDirectory = hkey_users;
1620 RtlInitUnicodeString( &nameW, DefaultW );
1621 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1623 ERR("Cannot create HKEY_USERS/.Default\n" );
1624 ExitProcess(1);
1626 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1628 _set_registry_levels(0,0,0);
1629 _allocate_default_keys();
1631 attr.RootDirectory = 0;
1632 RtlInitUnicodeString( &nameW, RegistryW );
1633 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1635 /* load windows registry if required */
1637 res = TRUE;
1638 attr.RootDirectory = hkey_config;
1639 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1640 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1642 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1643 res = !IS_OPTION_FALSE(str[0]);
1645 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1647 /* load global registry if required */
1649 res = TRUE;
1650 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1651 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1653 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1654 res = !IS_OPTION_FALSE(str[0]);
1656 if (res)
1658 /* load global registry files (stored in /etc/wine) */
1659 char *p, configfile[MAX_PATHNAME_LEN];
1661 /* Override ETCDIR? */
1662 configfile[0] = 0;
1663 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1664 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1666 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1667 WideCharToMultiByte(CP_ACP, 0, str, -1, configfile, sizeof(configfile), NULL, NULL);
1669 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1671 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1673 /* Load the global HKU hive directly from sysconfdir */
1674 p = configfile + strlen(configfile);
1675 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1676 load_wine_registry( hkey_users, configfile );
1678 /* Load the global machine defaults directly from sysconfdir */
1679 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1680 load_wine_registry( hkey_local_machine, configfile );
1683 _set_registry_levels(1,0,0);
1685 /* load home registry if required */
1687 res = TRUE;
1688 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
1689 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1691 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1692 res = !IS_OPTION_FALSE(str[0]);
1694 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1696 /* setup registry saving */
1698 all = FALSE;
1699 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
1700 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1702 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1703 all = IS_OPTION_FALSE(str[0]);
1706 period = 0;
1707 RtlInitUnicodeString( &nameW, PeriodicSaveW );
1708 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1710 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1711 period = (int)strtolW(str, NULL, 10);
1714 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1715 _set_registry_levels(1,!all,period*1000);
1717 /* setup keys to save */
1719 res = TRUE;
1720 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
1721 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1723 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1724 res = !IS_OPTION_FALSE(str[0]);
1726 if (res)
1728 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1729 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1730 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1733 NtClose(hkey_users_default);
1734 NtClose(hkey_current_user);
1735 NtClose(hkey_users);
1736 NtClose(hkey_local_machine);
1737 NtClose(hkey_config);