Some broken games do not put the TEXTURE flags in the surface caps.
[wine/multimedia.git] / misc / registry.c
blob21ed173cd24a6dce3ffbdfb709f8bd61686d2a5e
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 /* _strdupnA [Internal] */
96 static LPSTR _strdupnA(LPCSTR str,size_t len)
98 LPSTR ret;
100 if (!str) return NULL;
101 ret = _xmalloc( len + 1 );
102 memcpy( ret, str, len );
103 ret[len] = 0x00;
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 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
702 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
703 strncat(new_key_name,dkh->name,dkh->keynamelen);
705 /* walk sibling keys */
706 if (dke->next != 0xffffffff ) {
707 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
708 free(new_key_name);
709 return FALSE;
713 /* write the key path (something like [Software\\Microsoft\\..]) only if:
714 1) key has some values
715 2) key has no values and no subkeys
717 if (dkh->values > 0) {
718 /* there are some values */
719 fprintf(f,"\n[");
720 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
721 fprintf(f,"]\n");
722 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
723 free(new_key_name);
724 return FALSE;
727 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
728 /* no subkeys and no values */
729 fprintf(f,"\n[");
730 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
731 fprintf(f,"]\n");
733 } else new_key_name = _strdupnA(key_name,strlen(key_name));
735 /* next sub key */
736 if (dke->nextsub != 0xffffffff) {
737 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
738 free(new_key_name);
739 return FALSE;
743 free(new_key_name);
744 return TRUE;
746 /* end windows 95 loader */
748 /***********************************************************************************/
749 /* windows NT registry loader */
750 /***********************************************************************************/
752 /* NT REGISTRY LOADER */
754 #ifdef HAVE_SYS_MMAN_H
755 # include <sys/mman.h>
756 #endif
758 #ifndef MAP_FAILED
759 #define MAP_FAILED ((LPVOID)-1)
760 #endif
762 #define NT_REG_BLOCK_SIZE 0x1000
764 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
765 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
766 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
767 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
769 /* subblocks of nk */
770 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
771 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
772 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
774 #define NT_REG_KEY_BLOCK_TYPE 0x20
775 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
777 typedef struct {
778 DWORD id; /* 0x66676572 'regf'*/
779 DWORD uk1; /* 0x04 */
780 DWORD uk2; /* 0x08 */
781 FILETIME DateModified; /* 0x0c */
782 DWORD uk3; /* 0x14 */
783 DWORD uk4; /* 0x18 */
784 DWORD uk5; /* 0x1c */
785 DWORD uk6; /* 0x20 */
786 DWORD RootKeyBlock; /* 0x24 */
787 DWORD BlockSize; /* 0x28 */
788 DWORD uk7[116];
789 DWORD Checksum; /* at offset 0x1FC */
790 } nt_regf;
792 typedef struct {
793 DWORD blocksize;
794 BYTE data[1];
795 } nt_hbin_sub;
797 typedef struct {
798 DWORD id; /* 0x6E696268 'hbin' */
799 DWORD off_prev;
800 DWORD off_next;
801 DWORD uk1;
802 DWORD uk2; /* 0x10 */
803 DWORD uk3; /* 0x14 */
804 DWORD uk4; /* 0x18 */
805 DWORD size; /* 0x1C */
806 nt_hbin_sub hbin_sub; /* 0x20 */
807 } nt_hbin;
810 * the value_list consists of offsets to the values (vk)
812 typedef struct {
813 WORD SubBlockId; /* 0x00 0x6B6E */
814 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
815 FILETIME writetime; /* 0x04 */
816 DWORD uk1; /* 0x0C */
817 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
818 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
819 DWORD uk8; /* 0x18 */
820 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
821 DWORD uk2; /* 0x20 */
822 DWORD nr_values; /* 0x24 number of values */
823 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
824 DWORD off_sk; /* 0x2c Offset of the sk-Record */
825 DWORD off_class; /* 0x30 Offset of the Class-Name */
826 DWORD uk3; /* 0x34 */
827 DWORD uk4; /* 0x38 */
828 DWORD uk5; /* 0x3c */
829 DWORD uk6; /* 0x40 */
830 DWORD uk7; /* 0x44 */
831 WORD name_len; /* 0x48 name-length */
832 WORD class_len; /* 0x4a class-name length */
833 char name[1]; /* 0x4c key-name */
834 } nt_nk;
836 typedef struct {
837 DWORD off_nk; /* 0x00 */
838 DWORD name; /* 0x04 */
839 } hash_rec;
841 typedef struct {
842 WORD id; /* 0x00 0x666c */
843 WORD nr_keys; /* 0x06 */
844 hash_rec hash_rec[1];
845 } nt_lf;
848 list of subkeys without hash
850 li --+-->nk
852 +-->nk
854 typedef struct {
855 WORD id; /* 0x00 0x696c */
856 WORD nr_keys;
857 DWORD off_nk[1];
858 } nt_li;
861 this is a intermediate node
863 ri --+-->li--+-->nk
865 | +-->nk
867 +-->li--+-->nk
869 +-->nk
871 typedef struct {
872 WORD id; /* 0x00 0x6972 */
873 WORD nr_li; /* 0x02 number off offsets */
874 DWORD off_li[1]; /* 0x04 points to li */
875 } nt_ri;
877 typedef struct {
878 WORD id; /* 0x00 'vk' */
879 WORD nam_len;
880 DWORD data_len;
881 DWORD data_off;
882 DWORD type;
883 WORD flag;
884 WORD uk1;
885 char name[1];
886 } nt_vk;
889 * gets a value
891 * vk->flag:
892 * 0 value is a default value
893 * 1 the value has a name
895 * vk->data_len
896 * len of the whole data block
897 * - reg_sz (unicode)
898 * bytes including the terminating \0 = 2*(number_of_chars+1)
899 * - reg_dword, reg_binary:
900 * if highest bit of data_len is set data_off contains the value
902 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
904 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
905 struct key_value value;
907 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
908 ERR("unknown block found (0x%04x), please report!\n", vk->id);
909 return FALSE;
912 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
913 value.type = vk->type;
914 value.len = (vk->data_len & 0x7fffffff);
915 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
917 _dump_value(&value,f);
918 free(value.nameW);
920 return TRUE;
923 /* it's called from _nt_dump_lf() */
924 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
927 * get the subkeys
929 * this structure contains the hash of a keyname and points to all
930 * subkeys
932 * exception: if the id is 'il' there are no hash values and every
933 * dword is a offset
935 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
937 int i;
939 if (lf->id == NT_REG_HASH_BLOCK_ID) {
940 if (subkeys != lf->nr_keys) goto error1;
942 for (i=0; i<lf->nr_keys; i++)
943 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
944 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
945 nt_li * li = (nt_li*)lf;
946 if (subkeys != li->nr_keys) goto error1;
948 for (i=0; i<li->nr_keys; i++)
949 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
950 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
951 nt_ri * ri = (nt_ri*)lf;
952 int li_subkeys = 0;
954 /* count all subkeys */
955 for (i=0; i<ri->nr_li; i++) {
956 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
957 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
958 li_subkeys += li->nr_keys;
961 /* check number */
962 if (subkeys != li_subkeys) goto error1;
964 /* loop through the keys */
965 for (i=0; i<ri->nr_li; i++) {
966 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
967 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
969 } else goto error2;
971 return TRUE;
973 error2:
974 if (lf->id == 0x686c)
975 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
976 else
977 ERR("unknown node id 0x%04x, please report!\n", lf->id);
978 return TRUE;
980 error1:
981 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
982 return FALSE;
984 error:
985 ERR("error reading lf block\n");
986 return FALSE;
989 /* _nt_dump_nk [Internal] */
990 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
992 unsigned int n;
993 DWORD *vl;
994 LPSTR new_key_name = NULL;
996 TRACE("%s\n", key_name);
998 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
999 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
1000 return FALSE;
1003 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1004 ERR("registry file corrupt!\n");
1005 return FALSE;
1008 /* create the new key */
1009 if (level <= 0) {
1010 /* create new subkey name */
1011 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
1012 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
1013 strncat(new_key_name,nk->name,nk->name_len);
1015 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1016 1) key has some values
1017 2) key has no values and no subkeys
1019 if (nk->nr_values > 0) {
1020 /* there are some values */
1021 fprintf(f,"\n[");
1022 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1023 fprintf(f,"]\n");
1025 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1026 /* no subkeys and no values */
1027 fprintf(f,"\n[");
1028 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1029 fprintf(f,"]\n");
1032 /* loop trough the value list */
1033 vl = (DWORD *)(base+nk->valuelist_off+4);
1034 for (n=0; n<nk->nr_values; n++) {
1035 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1036 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1037 free(new_key_name);
1038 return FALSE;
1041 } else new_key_name = _strdupnA(key_name,strlen(key_name));
1043 /* loop through the subkeys */
1044 if (nk->nr_subkeys) {
1045 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1046 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1047 free(new_key_name);
1048 return FALSE;
1052 free(new_key_name);
1053 return TRUE;
1056 /* end nt loader */
1058 /**********************************************************************************
1059 * _set_registry_levels [Internal]
1061 * set level to 0 for loading system files
1062 * set level to 1 for loading user files
1064 static void _set_registry_levels(int level,int saving,int period)
1066 SERVER_START_REQ( set_registry_levels )
1068 req->current = level;
1069 req->saving = saving;
1070 req->period = period;
1071 wine_server_call( req );
1073 SERVER_END_REQ;
1076 /* _save_at_exit [Internal] */
1077 static void _save_at_exit(HKEY hkey,LPCSTR path)
1079 LPCSTR confdir = wine_get_config_dir();
1081 SERVER_START_REQ( save_registry_atexit )
1083 req->hkey = hkey;
1084 wine_server_add_data( req, confdir, strlen(confdir) );
1085 wine_server_add_data( req, path, strlen(path)+1 );
1086 wine_server_call( req );
1088 SERVER_END_REQ;
1091 /******************************************************************************
1092 * _allocate_default_keys [Internal]
1093 * Registry initialisation, allocates some default keys.
1095 static void _allocate_default_keys(void)
1097 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1098 'P','e','r','f','S','t','a','t','s','\\',
1099 'S','t','a','t','D','a','t','a',0};
1100 HKEY hkey;
1101 OBJECT_ATTRIBUTES attr;
1102 UNICODE_STRING nameW;
1104 TRACE("(void)\n");
1106 attr.Length = sizeof(attr);
1107 attr.RootDirectory = 0;
1108 attr.ObjectName = &nameW;
1109 attr.Attributes = 0;
1110 attr.SecurityDescriptor = NULL;
1111 attr.SecurityQualityOfService = NULL;
1113 RtlInitUnicodeString( &nameW, StatDataW );
1114 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1117 #define REG_DONTLOAD -1
1118 #define REG_WIN31 0
1119 #define REG_WIN95 1
1120 #define REG_WINNT 2
1122 /* return the type of native registry [Internal] */
1123 static int _get_reg_type(void)
1125 WCHAR windir[MAX_PATHNAME_LEN];
1126 WCHAR tmp[MAX_PATHNAME_LEN];
1127 int ret = REG_WIN31;
1128 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};
1129 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1131 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1133 /* test %windir%/system32/config/system --> winnt */
1134 strcpyW(tmp, windir);
1135 strcatW(tmp, nt_reg_pathW);
1136 if(GetFileAttributesW(tmp) != (DWORD)-1)
1137 ret = REG_WINNT;
1138 else
1140 /* test %windir%/system.dat --> win95 */
1141 strcpyW(tmp, windir);
1142 strcatW(tmp, win9x_reg_pathW);
1143 if(GetFileAttributesW(tmp) != (DWORD)-1)
1144 ret = REG_WIN95;
1147 return ret;
1150 /* load the registry file in wine format [Internal] */
1151 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1153 HANDLE file;
1154 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1155 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1157 SERVER_START_REQ( load_registry )
1159 req->hkey = hkey;
1160 req->file = file;
1161 wine_server_call( req );
1163 SERVER_END_REQ;
1164 CloseHandle( file );
1168 /* generate and return the name of the tmp file and associated stream [Internal] */
1169 static LPSTR _get_tmp_fn(FILE **f)
1171 LPSTR ret;
1172 int tmp_fd,count;
1174 ret = _xmalloc(50);
1175 for (count = 0;;) {
1176 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1177 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1178 if (errno != EEXIST) {
1179 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1180 free(ret);
1181 *f = NULL;
1182 return NULL;
1186 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1187 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1188 close(tmp_fd);
1189 free(ret);
1190 return NULL;
1193 return ret;
1196 /* convert win95 native registry file to wine format [Internal] */
1197 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1199 int fd;
1200 FILE *f;
1201 DOS_FULL_NAME full_name;
1202 void *base;
1203 LPSTR ret = NULL;
1204 struct stat st;
1206 _w95creg *creg;
1207 _w95rgkn *rgkn;
1208 _w95dke *dke, *root_dke;
1210 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1212 /* map the registry into the memory */
1213 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1214 if ((fstat(fd, &st) == -1)) goto error1;
1215 if (!st.st_size) goto error1;
1216 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1218 /* control signature */
1219 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1220 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1221 debugstr_w(fn));
1222 goto error;
1225 creg = base;
1226 /* load the header (rgkn) */
1227 rgkn = (_w95rgkn*)(creg + 1);
1228 if (rgkn->id != W95_REG_RGKN_ID) {
1229 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1230 goto error;
1232 if (rgkn->root_off != 0x20) {
1233 ERR("rgkn->root_off not 0x20, please report !\n");
1234 goto error;
1236 if (rgkn->last_dke > rgkn->size)
1238 ERR("registry file corrupt! last_dke > size!\n");
1239 goto error;
1241 /* verify last dke */
1242 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1243 if (dke->x1 != 0x80000000)
1244 { /* wrong magic */
1245 ERR("last dke invalid !\n");
1246 goto error;
1248 if (rgkn->size > creg->rgdb_off)
1250 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1251 goto error;
1253 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1254 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1256 ERR("registry file corrupt! invalid root dke !\n");
1257 goto error;
1260 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1261 fprintf(f,"WINE REGISTRY Version 2");
1262 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1263 fclose(f);
1265 error:
1266 if(ret == NULL) {
1267 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1268 ERR("Please report this.\n");
1269 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1272 munmap(base, st.st_size);
1273 error1:
1274 close(fd);
1275 return ret;
1278 /* convert winnt native registry file to wine format [Internal] */
1279 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1281 FILE *f;
1282 void *base;
1283 LPSTR ret = NULL;
1284 HANDLE hFile;
1285 HANDLE hMapping;
1286 OBJECT_ATTRIBUTES attr;
1287 LARGE_INTEGER lg_int;
1288 NTSTATUS nts;
1289 SIZE_T len;
1291 nt_regf *regf;
1292 nt_hbin *hbin;
1293 nt_hbin_sub *hbin_sub;
1294 nt_nk *nk;
1296 TRACE("%s\n", debugstr_w(fn));
1298 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1299 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1300 attr.Length = sizeof(attr);
1301 attr.RootDirectory = 0;
1302 attr.ObjectName = NULL;
1303 attr.Attributes = 0;
1304 attr.SecurityDescriptor = NULL;
1305 attr.SecurityQualityOfService = NULL;
1307 lg_int.QuadPart = 0;
1308 nts = NtCreateSection( &hMapping,
1309 STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|SECTION_MAP_READ,
1310 &attr, &lg_int, PAGE_READONLY, SEC_COMMIT, hFile );
1311 if (nts != STATUS_SUCCESS) goto error1;
1313 base = NULL; len = 0;
1314 nts = NtMapViewOfSection( hMapping, GetCurrentProcess(),
1315 &base, 0, 0, &lg_int, &len, ViewShare, 0,
1316 PAGE_READONLY);
1317 NtClose( hMapping );
1318 if (nts != STATUS_SUCCESS) goto error1;
1320 /* control signature */
1321 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1322 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1323 debugstr_w(fn));
1324 goto error;
1327 /* start block */
1328 regf = base;
1330 /* hbin block */
1331 hbin = (nt_hbin*)((char*) base + 0x1000);
1332 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1333 ERR( "hbin block invalid\n");
1334 goto error;
1337 /* hbin_sub block */
1338 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1339 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1340 ERR( "hbin_sub block invalid\n");
1341 goto error;
1344 /* nk block */
1345 nk = (nt_nk*)&(hbin_sub->data[0]);
1346 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1347 ERR( "special nk block not found\n");
1348 goto error;
1351 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1352 fprintf(f,"WINE REGISTRY Version 2");
1353 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1354 fclose(f);
1356 error:
1357 NtUnmapViewOfSection( GetCurrentProcess(), base );
1358 error1:
1359 NtClose(hFile);
1360 return ret;
1363 /* convert native registry to wine format and load it via server call [Internal] */
1364 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1366 LPSTR tmp = NULL;
1368 switch (reg_type) {
1369 case REG_WINNT:
1370 /* FIXME: following function doesn't really convert yet */
1371 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1372 break;
1373 case REG_WIN95:
1374 tmp = _convert_win95_registry_to_wine_format(fn,level);
1375 break;
1376 case REG_WIN31:
1377 ERR("Don't know how to convert native 3.1 registry yet.\n");
1378 break;
1379 default:
1380 ERR("Unknown registry format parameter (%d)\n",reg_type);
1381 break;
1384 if (tmp != NULL) {
1385 load_wine_registry(hkey,tmp);
1386 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1387 debugstr_w(fn), tmp);
1388 unlink(tmp);
1390 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1391 free(tmp);
1394 /* load all native windows registry files [Internal] */
1395 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1396 HKEY hkey_users_default )
1398 int reg_type;
1399 WCHAR windir[MAX_PATHNAME_LEN];
1400 WCHAR path[MAX_PATHNAME_LEN];
1401 OBJECT_ATTRIBUTES attr;
1402 UNICODE_STRING nameW;
1403 HKEY hkey;
1405 static const WCHAR WineW[] = {'W','i','n','e',0};
1406 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1407 static const WCHAR empty_strW[] = { 0 };
1408 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1409 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1410 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1411 'S','y','s','t','e','m','\\',
1412 'C','l','o','n','e',0};
1414 attr.Length = sizeof(attr);
1415 attr.RootDirectory = 0;
1416 attr.ObjectName = &nameW;
1417 attr.Attributes = 0;
1418 attr.SecurityDescriptor = NULL;
1419 attr.SecurityQualityOfService = NULL;
1421 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1423 reg_type = _get_reg_type();
1424 switch (reg_type) {
1425 case REG_WINNT: {
1426 HKEY hkey;
1427 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1428 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};
1429 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};
1430 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};
1431 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1432 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};
1434 /* user specific ntuser.dat */
1435 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1436 strcatW(path, ntuser_datW);
1437 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1439 else
1441 MESSAGE("When you are running with a native NT directory specify\n");
1442 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1443 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1444 break;
1447 /* default user.dat */
1448 if (hkey_users_default) {
1449 strcpyW(path, windir);
1450 strcatW(path, defaultW);
1451 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1455 * FIXME
1456 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1458 RtlInitUnicodeString( &nameW, System );
1459 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1461 strcpyW(path, windir);
1462 strcatW(path, systemW);
1463 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1464 NtClose( hkey );
1466 RtlInitUnicodeString( &nameW, Software );
1467 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1469 strcpyW(path, windir);
1470 strcatW(path, softwareW);
1471 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1472 NtClose( hkey );
1475 strcpyW(path, windir);
1476 strcatW(path, samW);
1477 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1479 strcpyW(path,windir);
1480 strcatW(path, securityW);
1481 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1483 /* this key is generated when the nt-core booted successfully */
1484 RtlInitUnicodeString( &nameW, Clone );
1485 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1486 break;
1489 case REG_WIN95:
1491 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1492 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1493 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1494 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1496 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1498 strcpyW(path, windir);
1499 strcatW(path, system_datW);
1500 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1502 RtlInitUnicodeString( &nameW, ClassesRootW );
1503 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1505 strcpyW(path, windir);
1506 strcatW(path, classes_datW);
1507 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1508 NtClose( hkey );
1511 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1512 /* user specific user.dat */
1513 strcatW(path, user_datW);
1514 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1516 /* default user.dat */
1517 if (hkey_users_default) {
1518 strcpyW(path, windir);
1519 strcatW(path, user_datW);
1520 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1522 } else {
1523 strcpyW(path, windir);
1524 strcatW(path, user_datW);
1525 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1527 break;
1530 case REG_WIN31:
1531 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1532 _w31_loadreg();
1533 break;
1535 case REG_DONTLOAD:
1536 TRACE("REG_DONTLOAD\n");
1537 break;
1539 default:
1540 ERR("switch: no match (%d)\n",reg_type);
1541 break;
1546 /* load home registry files (stored in ~/.wine) [Internal] */
1547 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1548 HKEY hkey_users_default )
1550 LPCSTR confdir = wine_get_config_dir();
1551 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1553 strcpy(tmp,confdir);
1554 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1555 load_wine_registry(hkey_users_default,tmp);
1557 strcpy(tmp,confdir);
1558 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1559 load_wine_registry(hkey_current_user,tmp);
1561 strcpy(tmp,confdir);
1562 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1563 load_wine_registry(hkey_local_machine,tmp);
1565 free(tmp);
1569 /* load all registry (native and global and home) */
1570 void SHELL_LoadRegistry( void )
1572 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
1573 OBJECT_ATTRIBUTES attr;
1574 UNICODE_STRING nameW;
1575 DWORD count;
1576 BOOL res;
1577 int all, period;
1578 char tmp[1024];
1580 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1581 static const WCHAR UserW[] = {'U','s','e','r',0};
1582 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1583 static const WCHAR RegistryW[] = {'M','a','c','h','i','n','e','\\',
1584 'S','o','f','t','w','a','r','e','\\',
1585 'W','i','n','e','\\',
1586 'W','i','n','e','\\',
1587 'C','o','n','f','i','g','\\',
1588 'R','e','g','i','s','t','r','y',0};
1589 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};
1590 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};
1591 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};
1592 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1593 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1594 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};
1595 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1597 TRACE("(void)\n");
1599 if (!CLIENT_IsBootThread()) return; /* already loaded */
1601 attr.Length = sizeof(attr);
1602 attr.RootDirectory = 0;
1603 attr.ObjectName = &nameW;
1604 attr.Attributes = 0;
1605 attr.SecurityDescriptor = NULL;
1606 attr.SecurityQualityOfService = NULL;
1608 RtlInitUnicodeString( &nameW, MachineW );
1609 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1610 RtlInitUnicodeString( &nameW, UserW );
1611 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1613 attr.RootDirectory = hkey_users;
1614 RtlInitUnicodeString( &nameW, DefaultW );
1615 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1617 ERR("Cannot create HKEY_USERS/.Default\n" );
1618 ExitProcess(1);
1620 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1622 _set_registry_levels(0,0,0);
1623 _allocate_default_keys();
1625 attr.RootDirectory = 0;
1626 RtlInitUnicodeString( &nameW, RegistryW );
1627 if (NtOpenKey( &hkey_config, KEY_ALL_ACCESS, &attr )) hkey_config = 0;
1629 /* load windows registry if required */
1631 res = TRUE;
1632 attr.RootDirectory = hkey_config;
1633 RtlInitUnicodeString( &nameW, load_win_reg_filesW );
1634 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1636 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1637 res = !IS_OPTION_FALSE(str[0]);
1639 if (res) _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1641 /* load global registry if required */
1643 res = TRUE;
1644 RtlInitUnicodeString( &nameW, load_global_reg_filesW );
1645 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1647 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1648 res = !IS_OPTION_FALSE(str[0]);
1650 if (res)
1652 /* load global registry files (stored in /etc/wine) */
1653 char *p, configfile[MAX_PATHNAME_LEN];
1655 /* Override ETCDIR? */
1656 configfile[0] = 0;
1657 RtlInitUnicodeString( &nameW, GlobalRegistryDirW );
1658 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1660 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1661 WideCharToMultiByte(CP_ACP, 0, str, -1, configfile, sizeof(configfile), NULL, NULL);
1663 if (configfile[0] != '/') strcpy(configfile, ETCDIR);
1665 TRACE("GlobalRegistryDir is '%s'.\n", configfile);
1667 /* Load the global HKU hive directly from sysconfdir */
1668 p = configfile + strlen(configfile);
1669 strcpy(p, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1670 load_wine_registry( hkey_users, configfile );
1672 /* Load the global machine defaults directly from sysconfdir */
1673 strcpy(p, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1674 load_wine_registry( hkey_local_machine, configfile );
1677 _set_registry_levels(1,0,0);
1679 /* load home registry if required */
1681 res = TRUE;
1682 RtlInitUnicodeString( &nameW, load_home_reg_filesW );
1683 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1685 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1686 res = !IS_OPTION_FALSE(str[0]);
1688 if (res) _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1690 /* setup registry saving */
1692 all = FALSE;
1693 RtlInitUnicodeString( &nameW, SaveOnlyUpdatedKeysW );
1694 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1696 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1697 all = IS_OPTION_FALSE(str[0]);
1700 period = 0;
1701 RtlInitUnicodeString( &nameW, PeriodicSaveW );
1702 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1704 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1705 period = (int)strtolW(str, NULL, 10);
1708 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1709 _set_registry_levels(1,!all,period*1000);
1711 /* setup keys to save */
1713 res = TRUE;
1714 RtlInitUnicodeString( &nameW, WritetoHomeRegistryFilesW );
1715 if (!NtQueryValueKey( hkey_config, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
1717 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1718 res = !IS_OPTION_FALSE(str[0]);
1720 if (res)
1722 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1723 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1724 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1727 NtClose(hkey_users_default);
1728 NtClose(hkey_current_user);
1729 NtClose(hkey_users);
1730 NtClose(hkey_local_machine);
1731 NtClose(hkey_config);