No longer using explicit values for resource identification.
[wine/wine-kai.git] / misc / registry.c
blob8eae5438711c0822f34c5ee62fdd56a286da68cb
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 "winerror.h"
54 #include "winnt.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 /* _xmalloc [Internal] */
80 static void *_xmalloc( size_t size )
82 void *res;
84 res = malloc (size ? size : 1);
85 if (res == NULL) {
86 WARN("Virtual memory exhausted.\n");
87 exit (1);
89 return res;
92 /* _strdupnA [Internal] */
93 static LPSTR _strdupnA(LPCSTR str,size_t len)
95 LPSTR ret;
97 if (!str) return NULL;
98 ret = _xmalloc( len + 1 );
99 memcpy( ret, str, len );
100 ret[len] = 0x00;
101 return ret;
104 /* convert ansi string to unicode [Internal] */
105 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
107 LPWSTR ret;
108 size_t lenW;
110 if (!strA) return NULL;
111 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
112 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
113 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
114 ret[lenW] = 0;
115 return ret;
118 /* dump a Unicode string with proper escaping [Internal] */
119 /* FIXME: this code duplicates server/unicode.c */
120 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
122 static const char escapes[32] = ".......abtnvfr.............e....";
123 char buffer[256];
124 LPSTR pos = buffer;
125 int count = 0;
127 for (; len; str++, len--)
129 if (pos > buffer + sizeof(buffer) - 8)
131 fwrite( buffer, pos - buffer, 1, f );
132 count += pos - buffer;
133 pos = buffer;
135 if (*str > 127) /* hex escape */
137 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
138 pos += sprintf( pos, "\\x%04x", *str );
139 else
140 pos += sprintf( pos, "\\x%x", *str );
141 continue;
143 if (*str < 32) /* octal or C escape */
145 if (!*str && len == 1) continue; /* do not output terminating NULL */
146 if (escapes[*str] != '.')
147 pos += sprintf( pos, "\\%c", escapes[*str] );
148 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
149 pos += sprintf( pos, "\\%03o", *str );
150 else
151 pos += sprintf( pos, "\\%o", *str );
152 continue;
154 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
155 *pos++ = *str;
157 fwrite( buffer, pos - buffer, 1, f );
158 count += pos - buffer;
159 return count;
162 /* convert ansi string to unicode and dump with proper escaping [Internal] */
163 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
165 WCHAR *strW;
166 int ret;
168 if (strA == NULL) return 0;
169 strW = _strdupnAtoW(strA,len);
170 ret = _dump_strW(strW,len,f,escape);
171 free(strW);
172 return ret;
175 /* a key value */
176 /* FIXME: this code duplicates server/registry.c */
177 struct key_value {
178 WCHAR *nameW; /* value name */
179 int type; /* value type */
180 size_t len; /* value data length in bytes */
181 void *data; /* pointer to value data */
184 /* dump a value to a text file */
185 /* FIXME: this code duplicates server/registry.c */
186 static void _dump_value(struct key_value *value,FILE *f)
188 int i, count;
190 if (value->nameW[0]) {
191 fputc( '\"', f );
192 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
193 count += fprintf( f, "\"=" );
195 else count = fprintf( f, "@=" );
197 switch(value->type) {
198 case REG_SZ:
199 case REG_EXPAND_SZ:
200 case REG_MULTI_SZ:
201 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
202 fputc( '\"', f );
203 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
204 fputc( '\"', f );
205 break;
206 case REG_DWORD:
207 if (value->len == sizeof(DWORD)) {
208 DWORD dw;
209 memcpy( &dw, value->data, sizeof(DWORD) );
210 fprintf( f, "dword:%08lx", dw );
211 break;
213 /* else fall through */
214 default:
215 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
216 else count += fprintf( f, "hex(%x):", value->type );
217 for (i = 0; i < value->len; i++) {
218 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
219 if (i < value->len-1) {
220 fputc( ',', f );
221 if (++count > 76) {
222 fprintf( f, "\\\n " );
223 count = 2;
227 break;
229 fputc( '\n', f );
232 /******************************************************************/
233 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
235 reghack - windows 3.11 registry data format demo program.
237 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
238 a combined hash table and tree description, and finally a text table.
240 The header is obvious from the struct header. The taboff1 and taboff2
241 fields are always 0x20, and their usage is unknown.
243 The 8-byte entry table has various entry types.
245 tabent[0] is a root index. The second word has the index of the root of
246 the directory.
247 tabent[1..hashsize] is a hash table. The first word in the hash entry is
248 the index of the key/value that has that hash. Data with the same
249 hash value are on a circular list. The other three words in the
250 hash entry are always zero.
251 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
252 entry: dirent and keyent/valent. They are identified by context.
253 tabent[freeidx] is the first free entry. The first word in a free entry
254 is the index of the next free entry. The last has 0 as a link.
255 The other three words in the free list are probably irrelevant.
257 Entries in text table are preceded by a word at offset-2. This word
258 has the value (2*index)+1, where index is the referring keyent/valent
259 entry in the table. I have no suggestion for the 2* and the +1.
260 Following the word, there are N bytes of data, as per the keyent/valent
261 entry length. The offset of the keyent/valent entry is from the start
262 of the text table to the first data byte.
264 This information is not available from Microsoft. The data format is
265 deduced from the reg.dat file by me. Mistakes may
266 have been made. I claim no rights and give no guarantees for this program.
268 Tor Sjøwall, tor@sn.no
271 /* reg.dat header format */
272 struct _w31_header {
273 char cookie[8]; /* 'SHCC3.10' */
274 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
275 unsigned long taboff2; /* offset of index table (??) = 0x20 */
276 unsigned long tabcnt; /* number of entries in index table */
277 unsigned long textoff; /* offset of text part */
278 unsigned long textsize; /* byte size of text part */
279 unsigned short hashsize; /* hash size */
280 unsigned short freeidx; /* free index */
283 /* generic format of table entries */
284 struct _w31_tabent {
285 unsigned short w0, w1, w2, w3;
288 /* directory tabent: */
289 struct _w31_dirent {
290 unsigned short sibling_idx; /* table index of sibling dirent */
291 unsigned short child_idx; /* table index of child dirent */
292 unsigned short key_idx; /* table index of key keyent */
293 unsigned short value_idx; /* table index of value valent */
296 /* key tabent: */
297 struct _w31_keyent {
298 unsigned short hash_idx; /* hash chain index for string */
299 unsigned short refcnt; /* reference count */
300 unsigned short length; /* length of string */
301 unsigned short string_off; /* offset of string in text table */
304 /* value tabent: */
305 struct _w31_valent {
306 unsigned short hash_idx; /* hash chain index for string */
307 unsigned short refcnt; /* reference count */
308 unsigned short length; /* length of string */
309 unsigned short string_off; /* offset of string in text table */
312 /* recursive helper function to display a directory tree [Internal] */
313 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
315 static const WCHAR classesW[] = {'.','c','l','a','s','s','e','s',0};
316 struct _w31_dirent *dir;
317 struct _w31_keyent *key;
318 struct _w31_valent *val;
319 HKEY subkey = 0;
320 OBJECT_ATTRIBUTES attr;
321 UNICODE_STRING nameW, valueW;
322 static WCHAR tail[400];
324 attr.Length = sizeof(attr);
325 attr.RootDirectory = hkey;
326 attr.ObjectName = &nameW;
327 attr.Attributes = 0;
328 attr.SecurityDescriptor = NULL;
329 attr.SecurityQualityOfService = NULL;
330 RtlInitUnicodeString( &valueW, NULL );
332 while (idx!=0) {
333 dir=(struct _w31_dirent*)&tab[idx];
335 if (dir->key_idx) {
336 DWORD len;
337 key = (struct _w31_keyent*)&tab[dir->key_idx];
339 RtlMultiByteToUnicodeN( tail, sizeof(tail)-sizeof(WCHAR), &len,
340 &txt[key->string_off], key->length);
341 tail[len/sizeof(WCHAR)] = 0;
343 /* all toplevel entries AND the entries in the
344 * toplevel subdirectory belong to \SOFTWARE\Classes
346 if (!level && !strcmpW(tail,classesW))
348 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
349 idx=dir->sibling_idx;
350 continue;
353 if (subkey) NtClose( subkey );
354 RtlInitUnicodeString( &nameW, tail );
355 if (NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) subkey = 0;
357 /* only add if leaf node or valued node */
358 if (dir->value_idx!=0||dir->child_idx==0) {
359 if (dir->value_idx) {
360 DWORD len;
361 val=(struct _w31_valent*)&tab[dir->value_idx];
362 RtlMultiByteToUnicodeN( tail, sizeof(tail) - sizeof(WCHAR), &len,
363 &txt[val->string_off], val->length);
364 tail[len/sizeof(WCHAR)] = 0;
365 NtSetValueKey( subkey, &valueW, 0, REG_SZ, tail, len + sizeof(WCHAR) );
368 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
369 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
370 idx=dir->sibling_idx;
372 if (subkey) NtClose( subkey );
376 /******************************************************************************
377 * _w31_loadreg [Internal]
379 void _w31_loadreg(void)
381 HFILE hf;
382 HKEY root;
383 OBJECT_ATTRIBUTES attr;
384 UNICODE_STRING nameW;
385 struct _w31_header head;
386 struct _w31_tabent *tab;
387 unsigned char *txt;
388 unsigned int len;
389 OFSTRUCT ofs;
390 BY_HANDLE_FILE_INFORMATION hfinfo;
391 time_t lastmodified;
393 TRACE("(void)\n");
395 hf = OpenFile("reg.dat",&ofs,OF_READ);
396 if (hf==HFILE_ERROR) return;
398 /* read & dump header */
399 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
400 ERR("reg.dat is too short.\n");
401 _lclose(hf);
402 return;
404 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
405 ERR("reg.dat has bad signature.\n");
406 _lclose(hf);
407 return;
410 len = head.tabcnt * sizeof(struct _w31_tabent);
411 /* read and dump index table */
412 tab = _xmalloc(len);
413 if (len!=_lread(hf,tab,len)) {
414 ERR("couldn't read %d bytes.\n",len);
415 free(tab);
416 _lclose(hf);
417 return;
420 /* read text */
421 txt = _xmalloc(head.textsize);
422 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
423 ERR("couldn't seek to textblock.\n");
424 free(tab);
425 free(txt);
426 _lclose(hf);
427 return;
429 if (head.textsize!=_lread(hf,txt,head.textsize)) {
430 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
431 free(tab);
432 free(txt);
433 _lclose(hf);
434 return;
437 if (!GetFileInformationByHandle(hf,&hfinfo)) {
438 ERR("GetFileInformationByHandle failed?.\n");
439 free(tab);
440 free(txt);
441 _lclose(hf);
442 return;
444 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
446 attr.Length = sizeof(attr);
447 attr.RootDirectory = 0;
448 attr.ObjectName = &nameW;
449 attr.Attributes = 0;
450 attr.SecurityDescriptor = NULL;
451 attr.SecurityQualityOfService = NULL;
452 RtlInitUnicodeString( &nameW, ClassesRootW );
454 if (!NtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
456 _w31_dumptree(tab[0].w1,txt,tab,&head,root,lastmodified,0);
457 NtClose( root );
459 free(tab);
460 free(txt);
461 _lclose(hf);
462 return;
465 /***********************************************************************************/
466 /* windows 95 registry loader */
467 /***********************************************************************************/
469 /* SECTION 1: main header
471 * once at offset 0
473 #define W95_REG_CREG_ID 0x47455243
475 typedef struct {
476 DWORD id; /* "CREG" = W95_REG_CREG_ID */
477 DWORD version; /* ???? 0x00010000 */
478 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
479 DWORD uk2; /* 0x0c */
480 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
481 WORD uk3;
482 DWORD uk[3];
483 /* rgkn */
484 } _w95creg;
486 /* SECTION 2: Directory information (tree structure)
488 * once on offset 0x20
490 * structure: [rgkn][dke]* (repeat till last_dke is reached)
492 #define W95_REG_RGKN_ID 0x4e4b4752
494 typedef struct {
495 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
496 DWORD size; /* Size of the RGKN-block */
497 DWORD root_off; /* Rel. Offset of the root-record */
498 DWORD last_dke; /* Offset to last DKE ? */
499 DWORD uk[4];
500 } _w95rgkn;
502 /* Disk Key Entry Structure
504 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
505 * hive itself. It looks the same like other keys. Even the ID-number can
506 * be any value.
508 * The "hash"-value is a value representing the key's name. Windows will not
509 * search for the name, but for a matching hash-value. if it finds one, it
510 * will compare the actual string info, otherwise continue with the next key.
511 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
512 * of the string which are smaller than 0x80 (128) to this D-Word.
514 * If you want to modify key names, also modify the hash-values, since they
515 * cannot be found again (although they would be displayed in REGEDIT)
516 * End of list-pointers are filled with 0xFFFFFFFF
518 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
519 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
520 * structure) and reading another RGDB_section.
522 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
523 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
524 * The remaining space between last_dke and the offset calculated from
525 * rgkn->size seems to be free for use for more dke:s.
526 * So it seems if more dke:s are added, they are added to that space and
527 * last_dke is grown, and in case that "free" space is out, the space
528 * gets grown and rgkn->size gets adjusted.
530 * there is a one to one relationship between dke and dkh
532 /* key struct, once per key */
533 typedef struct {
534 DWORD x1; /* Free entry indicator(?) */
535 DWORD hash; /* sum of bytes of keyname */
536 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
537 DWORD prevlvl; /* offset of previous key */
538 DWORD nextsub; /* offset of child key */
539 DWORD next; /* offset of sibling key */
540 WORD nrLS; /* id inside the rgdb block */
541 WORD nrMS; /* number of the rgdb block */
542 } _w95dke;
544 /* SECTION 3: key information, values and data
546 * structure:
547 * section: [blocks]* (repeat creg->rgdb_num times)
548 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
549 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
551 * An interesting relationship exists in RGDB_section. The DWORD value
552 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
553 * I have no idea at the moment what this means. (Kevin Cozens)
556 /* block header, once per block */
557 #define W95_REG_RGDB_ID 0x42444752
559 typedef struct {
560 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
561 DWORD size; /* 0x04 */
562 DWORD uk1; /* 0x08 */
563 DWORD uk2; /* 0x0c */
564 DWORD uk3; /* 0x10 */
565 DWORD uk4; /* 0x14 */
566 DWORD uk5; /* 0x18 */
567 DWORD uk6; /* 0x1c */
568 /* dkh */
569 } _w95rgdb;
571 /* Disk Key Header structure (RGDB part), once per key */
572 typedef struct {
573 DWORD nextkeyoff; /* 0x00 offset to next dkh */
574 WORD nrLS; /* 0x04 id inside the rgdb block */
575 WORD nrMS; /* 0x06 number of the rgdb block */
576 DWORD bytesused; /* 0x08 */
577 WORD keynamelen; /* 0x0c len of name */
578 WORD values; /* 0x0e number of values */
579 DWORD xx1; /* 0x10 */
580 char name[1]; /* 0x14 */
581 /* dkv */ /* 0x14 + keynamelen */
582 } _w95dkh;
584 /* Disk Key Value structure, once per value */
585 typedef struct {
586 DWORD type; /* 0x00 */
587 DWORD x1; /* 0x04 */
588 WORD valnamelen; /* 0x08 length of name, 0 is default key */
589 WORD valdatalen; /* 0x0A length of data */
590 char name[1]; /* 0x0c */
591 /* raw data */ /* 0x0c + valnamelen */
592 } _w95dkv;
594 /******************************************************************************
595 * _w95_lookup_dkh [Internal]
597 * seeks the dkh belonging to a dke
599 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
601 _w95rgdb * rgdb;
602 _w95dkh * dkh;
603 int i;
605 /* get the beginning of the rgdb datastore */
606 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
608 /* check: requested block < last_block) */
609 if (creg->rgdb_num <= nrMS) {
610 ERR("registry file corrupt! requested block no. beyond end.\n");
611 goto error;
614 /* find the right block */
615 for(i=0; i<nrMS ;i++) {
616 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
617 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
618 goto error;
620 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
623 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
625 do {
626 if(nrLS==dkh->nrLS ) return dkh;
627 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
628 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
630 error:
631 return NULL;
634 /******************************************************************************
635 * _w95_dump_dkv [Internal]
637 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
639 _w95dkv * dkv;
640 int i;
642 /* first value block */
643 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
645 /* loop through the values */
646 for (i=0; i< dkh->values; i++) {
647 struct key_value value;
648 WCHAR *pdata;
650 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
651 value.type = dkv->type;
652 value.len = dkv->valdatalen;
654 value.data = &(dkv->name[dkv->valnamelen]);
655 pdata = NULL;
656 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
657 pdata = _strdupnAtoW(value.data,value.len);
658 value.len *= 2;
660 if (pdata != NULL) value.data = pdata;
662 _dump_value(&value,f);
663 free(value.nameW);
664 if (pdata != NULL) free(pdata);
666 /* next value */
667 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
669 return TRUE;
672 /******************************************************************************
673 * _w95_dump_dke [Internal]
675 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
677 _w95dkh * dkh;
678 LPSTR new_key_name = NULL;
680 /* special root key */
681 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
683 /* parse the one subkey */
684 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
685 /* has no sibling keys */
686 return FALSE;
689 /* search subblock */
690 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
691 ERR("dke pointing to missing dkh !\n");
692 return FALSE;
695 if (level <= 0) {
696 /* create new subkey name */
697 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
698 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
699 strncat(new_key_name,dkh->name,dkh->keynamelen);
701 /* walk sibling keys */
702 if (dke->next != 0xffffffff ) {
703 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
704 free(new_key_name);
705 return FALSE;
709 /* write the key path (something like [Software\\Microsoft\\..]) only if:
710 1) key has some values
711 2) key has no values and no subkeys
713 if (dkh->values > 0) {
714 /* there are some values */
715 fprintf(f,"\n[");
716 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
717 fprintf(f,"]\n");
718 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
719 free(new_key_name);
720 return FALSE;
723 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
724 /* no subkeys and no values */
725 fprintf(f,"\n[");
726 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
727 fprintf(f,"]\n");
729 } else new_key_name = _strdupnA(key_name,strlen(key_name));
731 /* next sub key */
732 if (dke->nextsub != 0xffffffff) {
733 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
734 free(new_key_name);
735 return FALSE;
739 free(new_key_name);
740 return TRUE;
742 /* end windows 95 loader */
744 /***********************************************************************************/
745 /* windows NT registry loader */
746 /***********************************************************************************/
748 /* NT REGISTRY LOADER */
750 #ifdef HAVE_SYS_MMAN_H
751 # include <sys/mman.h>
752 #endif
754 #ifndef MAP_FAILED
755 #define MAP_FAILED ((LPVOID)-1)
756 #endif
758 #define NT_REG_BLOCK_SIZE 0x1000
760 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
761 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
762 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
763 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
765 /* subblocks of nk */
766 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
767 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
768 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
770 #define NT_REG_KEY_BLOCK_TYPE 0x20
771 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
773 typedef struct {
774 DWORD id; /* 0x66676572 'regf'*/
775 DWORD uk1; /* 0x04 */
776 DWORD uk2; /* 0x08 */
777 FILETIME DateModified; /* 0x0c */
778 DWORD uk3; /* 0x14 */
779 DWORD uk4; /* 0x18 */
780 DWORD uk5; /* 0x1c */
781 DWORD uk6; /* 0x20 */
782 DWORD RootKeyBlock; /* 0x24 */
783 DWORD BlockSize; /* 0x28 */
784 DWORD uk7[116];
785 DWORD Checksum; /* at offset 0x1FC */
786 } nt_regf;
788 typedef struct {
789 DWORD blocksize;
790 BYTE data[1];
791 } nt_hbin_sub;
793 typedef struct {
794 DWORD id; /* 0x6E696268 'hbin' */
795 DWORD off_prev;
796 DWORD off_next;
797 DWORD uk1;
798 DWORD uk2; /* 0x10 */
799 DWORD uk3; /* 0x14 */
800 DWORD uk4; /* 0x18 */
801 DWORD size; /* 0x1C */
802 nt_hbin_sub hbin_sub; /* 0x20 */
803 } nt_hbin;
806 * the value_list consists of offsets to the values (vk)
808 typedef struct {
809 WORD SubBlockId; /* 0x00 0x6B6E */
810 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
811 FILETIME writetime; /* 0x04 */
812 DWORD uk1; /* 0x0C */
813 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
814 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
815 DWORD uk8; /* 0x18 */
816 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
817 DWORD uk2; /* 0x20 */
818 DWORD nr_values; /* 0x24 number of values */
819 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
820 DWORD off_sk; /* 0x2c Offset of the sk-Record */
821 DWORD off_class; /* 0x30 Offset of the Class-Name */
822 DWORD uk3; /* 0x34 */
823 DWORD uk4; /* 0x38 */
824 DWORD uk5; /* 0x3c */
825 DWORD uk6; /* 0x40 */
826 DWORD uk7; /* 0x44 */
827 WORD name_len; /* 0x48 name-length */
828 WORD class_len; /* 0x4a class-name length */
829 char name[1]; /* 0x4c key-name */
830 } nt_nk;
832 typedef struct {
833 DWORD off_nk; /* 0x00 */
834 DWORD name; /* 0x04 */
835 } hash_rec;
837 typedef struct {
838 WORD id; /* 0x00 0x666c */
839 WORD nr_keys; /* 0x06 */
840 hash_rec hash_rec[1];
841 } nt_lf;
844 list of subkeys without hash
846 li --+-->nk
848 +-->nk
850 typedef struct {
851 WORD id; /* 0x00 0x696c */
852 WORD nr_keys;
853 DWORD off_nk[1];
854 } nt_li;
857 this is a intermediate node
859 ri --+-->li--+-->nk
861 | +-->nk
863 +-->li--+-->nk
865 +-->nk
867 typedef struct {
868 WORD id; /* 0x00 0x6972 */
869 WORD nr_li; /* 0x02 number off offsets */
870 DWORD off_li[1]; /* 0x04 points to li */
871 } nt_ri;
873 typedef struct {
874 WORD id; /* 0x00 'vk' */
875 WORD nam_len;
876 DWORD data_len;
877 DWORD data_off;
878 DWORD type;
879 WORD flag;
880 WORD uk1;
881 char name[1];
882 } nt_vk;
885 * gets a value
887 * vk->flag:
888 * 0 value is a default value
889 * 1 the value has a name
891 * vk->data_len
892 * len of the whole data block
893 * - reg_sz (unicode)
894 * bytes including the terminating \0 = 2*(number_of_chars+1)
895 * - reg_dword, reg_binary:
896 * if highest bit of data_len is set data_off contains the value
898 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
900 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
901 struct key_value value;
903 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
904 ERR("unknown block found (0x%04x), please report!\n", vk->id);
905 return FALSE;
908 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
909 value.type = vk->type;
910 value.len = (vk->data_len & 0x7fffffff);
911 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
913 _dump_value(&value,f);
914 free(value.nameW);
916 return TRUE;
919 /* it's called from _nt_dump_lf() */
920 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
923 * get the subkeys
925 * this structure contains the hash of a keyname and points to all
926 * subkeys
928 * exception: if the id is 'il' there are no hash values and every
929 * dword is a offset
931 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
933 int i;
935 if (lf->id == NT_REG_HASH_BLOCK_ID) {
936 if (subkeys != lf->nr_keys) goto error1;
938 for (i=0; i<lf->nr_keys; i++)
939 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
940 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
941 nt_li * li = (nt_li*)lf;
942 if (subkeys != li->nr_keys) goto error1;
944 for (i=0; i<li->nr_keys; i++)
945 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
946 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
947 nt_ri * ri = (nt_ri*)lf;
948 int li_subkeys = 0;
950 /* count all subkeys */
951 for (i=0; i<ri->nr_li; i++) {
952 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
953 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
954 li_subkeys += li->nr_keys;
957 /* check number */
958 if (subkeys != li_subkeys) goto error1;
960 /* loop through the keys */
961 for (i=0; i<ri->nr_li; i++) {
962 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
963 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
965 } else goto error2;
967 return TRUE;
969 error2:
970 if (lf->id == 0x686c)
971 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
972 else
973 ERR("unknown node id 0x%04x, please report!\n", lf->id);
974 return TRUE;
976 error1:
977 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
978 return FALSE;
980 error:
981 ERR("error reading lf block\n");
982 return FALSE;
985 /* _nt_dump_nk [Internal] */
986 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
988 unsigned int n;
989 DWORD *vl;
990 LPSTR new_key_name = NULL;
992 TRACE("%s\n", key_name);
994 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
995 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
996 return FALSE;
999 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
1000 ERR("registry file corrupt!\n");
1001 return FALSE;
1004 /* create the new key */
1005 if (level <= 0) {
1006 /* create new subkey name */
1007 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
1008 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
1009 strncat(new_key_name,nk->name,nk->name_len);
1011 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1012 1) key has some values
1013 2) key has no values and no subkeys
1015 if (nk->nr_values > 0) {
1016 /* there are some values */
1017 fprintf(f,"\n[");
1018 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1019 fprintf(f,"]\n");
1021 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
1022 /* no subkeys and no values */
1023 fprintf(f,"\n[");
1024 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
1025 fprintf(f,"]\n");
1028 /* loop trough the value list */
1029 vl = (DWORD *)(base+nk->valuelist_off+4);
1030 for (n=0; n<nk->nr_values; n++) {
1031 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
1032 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
1033 free(new_key_name);
1034 return FALSE;
1037 } else new_key_name = _strdupnA(key_name,strlen(key_name));
1039 /* loop through the subkeys */
1040 if (nk->nr_subkeys) {
1041 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1042 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1043 free(new_key_name);
1044 return FALSE;
1048 free(new_key_name);
1049 return TRUE;
1052 /* end nt loader */
1054 /**********************************************************************************
1055 * _set_registry_levels [Internal]
1057 * set level to 0 for loading system files
1058 * set level to 1 for loading user files
1060 static void _set_registry_levels(int level,int saving,int period)
1062 SERVER_START_REQ( set_registry_levels )
1064 req->current = level;
1065 req->saving = saving;
1066 req->period = period;
1067 wine_server_call( req );
1069 SERVER_END_REQ;
1072 /* _save_at_exit [Internal] */
1073 static void _save_at_exit(HKEY hkey,LPCSTR path)
1075 LPCSTR confdir = wine_get_config_dir();
1077 SERVER_START_REQ( save_registry_atexit )
1079 req->hkey = hkey;
1080 wine_server_add_data( req, confdir, strlen(confdir) );
1081 wine_server_add_data( req, path, strlen(path)+1 );
1082 wine_server_call( req );
1084 SERVER_END_REQ;
1087 /* configure save files and start the periodic saving timer [Internal] */
1088 static void _init_registry_saving( HKEY hkey_local_machine, HKEY hkey_current_user,
1089 HKEY hkey_users_default )
1091 int all;
1092 int period = 0;
1093 WCHAR buffer[20];
1094 static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0};
1095 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1096 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1097 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};
1098 static const WCHAR empty_strW[] = { 0 };
1100 all = !PROFILE_GetWineIniBool(registryW, SaveOnlyUpdatedKeysW, 1);
1101 PROFILE_GetWineIniString( registryW, PeriodicSaveW, empty_strW, buffer, 20 );
1102 if (buffer[0]) period = (int)strtolW(buffer, NULL, 10);
1104 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1105 _set_registry_levels(1,!all,period*1000);
1107 if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1))
1109 _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1110 _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1111 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1116 /******************************************************************************
1117 * _allocate_default_keys [Internal]
1118 * Registry initialisation, allocates some default keys.
1120 static void _allocate_default_keys(void)
1122 HKEY hkey;
1123 OBJECT_ATTRIBUTES attr;
1124 UNICODE_STRING nameW, valueW;
1125 WCHAR computer_name[200];
1126 DWORD size = sizeof(computer_name)/sizeof(WCHAR);
1128 static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
1129 'P','e','r','f','S','t','a','t','s','\\',
1130 'S','t','a','t','D','a','t','a',0};
1131 static const WCHAR ComputerW[] = {'M','a','c','h','i','n','e','\\',
1132 'S','y','s','t','e','m','\\',
1133 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1134 'C','o','n','t','r','o','l','\\',
1135 'C','o','m','p','u','t','e','r','N','a','m','e','\\',
1136 'C','o','m','p','u','t','e','r','N','a','m','e',0};
1137 static const WCHAR ComputerNameW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
1139 TRACE("(void)\n");
1141 attr.Length = sizeof(attr);
1142 attr.RootDirectory = 0;
1143 attr.ObjectName = &nameW;
1144 attr.Attributes = 0;
1145 attr.SecurityDescriptor = NULL;
1146 attr.SecurityQualityOfService = NULL;
1148 RtlInitUnicodeString( &nameW, StatDataW );
1149 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1151 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1152 * CurrentVersion
1153 * CurrentBuildNumber
1154 * CurrentType
1155 * string RegisteredOwner
1156 * string RegisteredOrganization
1159 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1160 * string SysContact
1161 * string SysLocation
1162 * SysServices
1164 if (GetComputerNameW( computer_name, &size ))
1166 RtlInitUnicodeString( &nameW, ComputerW );
1167 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1169 RtlInitUnicodeString( &valueW, ComputerNameW );
1170 NtSetValueKey( hkey, &valueW, 0, REG_SZ, computer_name,
1171 (strlenW(computer_name) + 1) * sizeof(WCHAR) );
1172 NtClose(hkey);
1177 #define REG_DONTLOAD -1
1178 #define REG_WIN31 0
1179 #define REG_WIN95 1
1180 #define REG_WINNT 2
1182 /* return the type of native registry [Internal] */
1183 static int _get_reg_type(void)
1185 WCHAR windir[MAX_PATHNAME_LEN];
1186 WCHAR tmp[MAX_PATHNAME_LEN];
1187 int ret = REG_WIN31;
1188 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};
1189 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1190 static const WCHAR WineW[] = {'W','i','n','e',0};
1191 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1192 static const WCHAR empty_strW[] = { 0 };
1194 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1196 /* test %windir%/system32/config/system --> winnt */
1197 strcpyW(tmp, windir);
1198 strcatW(tmp, nt_reg_pathW);
1199 if(GetFileAttributesW(tmp) != (DWORD)-1)
1200 ret = REG_WINNT;
1201 else
1203 /* test %windir%/system.dat --> win95 */
1204 strcpyW(tmp, windir);
1205 strcatW(tmp, win9x_reg_pathW);
1206 if(GetFileAttributesW(tmp) != (DWORD)-1)
1207 ret = REG_WIN95;
1210 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, tmp, MAX_PATHNAME_LEN )))
1212 MESSAGE("When you are running with a native NT directory specify\n");
1213 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1214 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1215 ret = REG_DONTLOAD;
1218 return ret;
1221 #define WINE_REG_VER_ERROR -1
1222 #define WINE_REG_VER_1 0
1223 #define WINE_REG_VER_2 1
1224 #define WINE_REG_VER_OLD 2
1225 #define WINE_REG_VER_UNKNOWN 3
1227 /* return the version of wine registry file [Internal] */
1228 static int _get_wine_registry_file_format_version(LPCSTR fn)
1230 FILE *f;
1231 char tmp[50];
1232 int ver;
1234 if ((f=fopen(fn,"rt")) == NULL) {
1235 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1236 return WINE_REG_VER_ERROR;
1239 if (fgets(tmp,50,f) == NULL) {
1240 WARN("Error reading %s: %s\n",fn,strerror(errno));
1241 fclose(f);
1242 return WINE_REG_VER_ERROR;
1244 fclose(f);
1246 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1247 switch (ver) {
1248 case 1:
1249 return WINE_REG_VER_1;
1250 break;
1251 case 2:
1252 return WINE_REG_VER_2;
1253 break;
1254 default:
1255 return WINE_REG_VER_UNKNOWN;
1259 /* load the registry file in wine format [Internal] */
1260 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1262 int file_format;
1264 file_format = _get_wine_registry_file_format_version(fn);
1265 switch (file_format) {
1267 case WINE_REG_VER_1:
1268 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1269 break;
1271 case WINE_REG_VER_2: {
1272 HANDLE file;
1273 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1274 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1276 SERVER_START_REQ( load_registry )
1278 req->hkey = hkey;
1279 req->file = file;
1280 wine_server_call( req );
1282 SERVER_END_REQ;
1283 CloseHandle( file );
1285 break;
1288 case WINE_REG_VER_UNKNOWN:
1289 WARN("Unable to load registry file %s: unknown format.\n",fn);
1290 break;
1292 case WINE_REG_VER_ERROR:
1293 break;
1297 /* generate and return the name of the tmp file and associated stream [Internal] */
1298 static LPSTR _get_tmp_fn(FILE **f)
1300 LPSTR ret;
1301 int tmp_fd,count;
1303 ret = _xmalloc(50);
1304 for (count = 0;;) {
1305 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1306 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1307 if (errno != EEXIST) {
1308 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1309 free(ret);
1310 *f = NULL;
1311 return NULL;
1315 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1316 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1317 close(tmp_fd);
1318 free(ret);
1319 return NULL;
1322 return ret;
1325 /* convert win95 native registry file to wine format [Internal] */
1326 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1328 int fd;
1329 FILE *f;
1330 DOS_FULL_NAME full_name;
1331 void *base;
1332 LPSTR ret = NULL;
1333 struct stat st;
1335 _w95creg *creg;
1336 _w95rgkn *rgkn;
1337 _w95dke *dke, *root_dke;
1339 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1341 /* map the registry into the memory */
1342 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1343 if ((fstat(fd, &st) == -1)) goto error1;
1344 if (!st.st_size) goto error1;
1345 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1347 /* control signature */
1348 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1349 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1350 debugstr_w(fn));
1351 goto error;
1354 creg = base;
1355 /* load the header (rgkn) */
1356 rgkn = (_w95rgkn*)(creg + 1);
1357 if (rgkn->id != W95_REG_RGKN_ID) {
1358 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1359 goto error;
1361 if (rgkn->root_off != 0x20) {
1362 ERR("rgkn->root_off not 0x20, please report !\n");
1363 goto error;
1365 if (rgkn->last_dke > rgkn->size)
1367 ERR("registry file corrupt! last_dke > size!\n");
1368 goto error;
1370 /* verify last dke */
1371 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1372 if (dke->x1 != 0x80000000)
1373 { /* wrong magic */
1374 ERR("last dke invalid !\n");
1375 goto error;
1377 if (rgkn->size > creg->rgdb_off)
1379 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1380 goto error;
1382 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1383 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1385 ERR("registry file corrupt! invalid root dke !\n");
1386 goto error;
1389 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1390 fprintf(f,"WINE REGISTRY Version 2");
1391 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1392 fclose(f);
1394 error:
1395 if(ret == NULL) {
1396 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1397 ERR("Please report this.\n");
1398 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1401 munmap(base, st.st_size);
1402 error1:
1403 close(fd);
1404 return ret;
1407 /* convert winnt native registry file to wine format [Internal] */
1408 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1410 FILE *f;
1411 void *base;
1412 LPSTR ret = NULL;
1413 HANDLE hFile;
1414 HANDLE hMapping;
1416 nt_regf *regf;
1417 nt_hbin *hbin;
1418 nt_hbin_sub *hbin_sub;
1419 nt_nk *nk;
1421 TRACE("%s\n", debugstr_w(fn));
1423 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1424 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1425 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1426 if (!hMapping) goto error1;
1427 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1428 CloseHandle( hMapping );
1429 if (!base) goto error1;
1431 /* control signature */
1432 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1433 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1434 debugstr_w(fn));
1435 goto error;
1438 /* start block */
1439 regf = base;
1441 /* hbin block */
1442 hbin = (nt_hbin*)((char*) base + 0x1000);
1443 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1444 ERR( "hbin block invalid\n");
1445 goto error;
1448 /* hbin_sub block */
1449 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1450 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1451 ERR( "hbin_sub block invalid\n");
1452 goto error;
1455 /* nk block */
1456 nk = (nt_nk*)&(hbin_sub->data[0]);
1457 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1458 ERR( "special nk block not found\n");
1459 goto error;
1462 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1463 fprintf(f,"WINE REGISTRY Version 2");
1464 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1465 fclose(f);
1467 error:
1468 UnmapViewOfFile( base );
1469 error1:
1470 CloseHandle(hFile);
1471 return ret;
1474 /* convert native registry to wine format and load it via server call [Internal] */
1475 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1477 LPSTR tmp = NULL;
1479 switch (reg_type) {
1480 case REG_WINNT:
1481 /* FIXME: following function doesn't really convert yet */
1482 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1483 break;
1484 case REG_WIN95:
1485 tmp = _convert_win95_registry_to_wine_format(fn,level);
1486 break;
1487 case REG_WIN31:
1488 ERR("Don't know how to convert native 3.1 registry yet.\n");
1489 break;
1490 default:
1491 ERR("Unknown registry format parameter (%d)\n",reg_type);
1492 break;
1495 if (tmp != NULL) {
1496 load_wine_registry(hkey,tmp);
1497 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1498 debugstr_w(fn), tmp);
1499 unlink(tmp);
1501 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1502 free(tmp);
1505 /* load all native windows registry files [Internal] */
1506 static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1507 HKEY hkey_users_default )
1509 int reg_type;
1510 WCHAR windir[MAX_PATHNAME_LEN];
1511 WCHAR path[MAX_PATHNAME_LEN];
1512 OBJECT_ATTRIBUTES attr;
1513 UNICODE_STRING nameW;
1514 HKEY hkey;
1516 static const WCHAR WineW[] = {'W','i','n','e',0};
1517 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1518 static const WCHAR empty_strW[] = { 0 };
1519 static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1520 static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1521 static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
1522 'S','y','s','t','e','m','\\',
1523 'C','l','o','n','e',0};
1525 attr.Length = sizeof(attr);
1526 attr.RootDirectory = 0;
1527 attr.ObjectName = &nameW;
1528 attr.Attributes = 0;
1529 attr.SecurityDescriptor = NULL;
1530 attr.SecurityQualityOfService = NULL;
1532 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1534 reg_type = _get_reg_type();
1535 switch (reg_type) {
1536 case REG_WINNT: {
1537 HKEY hkey;
1538 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1539 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};
1540 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};
1541 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};
1542 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1543 static const WCHAR securityW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','e','c','u','r','i','t','y',0};
1545 /* user specific ntuser.dat */
1546 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1547 strcatW(path, ntuser_datW);
1548 _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
1551 /* default user.dat */
1552 if (hkey_users_default) {
1553 strcpyW(path, windir);
1554 strcatW(path, defaultW);
1555 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1559 * FIXME
1560 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1562 RtlInitUnicodeString( &nameW, System );
1563 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1565 strcpyW(path, windir);
1566 strcatW(path, systemW);
1567 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1568 NtClose( hkey );
1570 RtlInitUnicodeString( &nameW, Software );
1571 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1573 strcpyW(path, windir);
1574 strcatW(path, softwareW);
1575 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1576 NtClose( hkey );
1579 strcpyW(path, windir);
1580 strcatW(path, samW);
1581 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1583 strcpyW(path,windir);
1584 strcatW(path, securityW);
1585 _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
1587 /* this key is generated when the nt-core booted successfully */
1588 RtlInitUnicodeString( &nameW, Clone );
1589 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
1590 break;
1593 case REG_WIN95:
1595 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1596 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1597 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1598 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1600 _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
1602 strcpyW(path, windir);
1603 strcatW(path, system_datW);
1604 _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
1606 RtlInitUnicodeString( &nameW, ClassesRootW );
1607 if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1609 strcpyW(path, windir);
1610 strcatW(path, classes_datW);
1611 _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
1612 NtClose( hkey );
1615 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1616 /* user specific user.dat */
1617 strcatW(path, user_datW);
1618 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1620 /* default user.dat */
1621 if (hkey_users_default) {
1622 strcpyW(path, windir);
1623 strcatW(path, user_datW);
1624 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1626 } else {
1627 strcpyW(path, windir);
1628 strcatW(path, user_datW);
1629 _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
1631 break;
1634 case REG_WIN31:
1635 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1636 _w31_loadreg();
1637 break;
1639 case REG_DONTLOAD:
1640 TRACE("REG_DONTLOAD\n");
1641 break;
1643 default:
1644 ERR("switch: no match (%d)\n",reg_type);
1645 break;
1650 /* load global registry files (stored in /etc/wine) [Internal] */
1651 static void _load_global_registry( HKEY hkey_local_machine, HKEY hkey_users )
1653 WCHAR Wglobalregistrydir[MAX_PATHNAME_LEN];
1654 char globalregistrydir[MAX_PATHNAME_LEN];
1655 char configfile[MAX_PATHNAME_LEN];
1656 static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0};
1657 static const WCHAR GlobalRegistryDirW[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1658 static const WCHAR empty_strW[] = { 0 };
1660 TRACE("(void)\n");
1662 /* Override ETCDIR? */
1663 PROFILE_GetWineIniString( registryW, GlobalRegistryDirW, empty_strW , Wglobalregistrydir, MAX_PATHNAME_LEN);
1664 WideCharToMultiByte(CP_ACP, 0, Wglobalregistrydir, -1, globalregistrydir, MAX_PATHNAME_LEN, NULL, NULL);
1666 if (globalregistrydir[0] != '/') strcpy(globalregistrydir, ETCDIR);
1668 TRACE("GlobalRegistryDir is '%s'.\n", globalregistrydir);
1670 /* Load the global HKU hive directly from sysconfdir */
1671 strcpy(configfile, globalregistrydir);
1672 strcat(configfile, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT);
1673 load_wine_registry( hkey_users, configfile );
1675 /* Load the global machine defaults directly from sysconfdir */
1676 strcpy(configfile, globalregistrydir);
1677 strcat(configfile, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE);
1678 load_wine_registry( hkey_local_machine, configfile );
1681 /* load home registry files (stored in ~/.wine) [Internal] */
1682 static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
1683 HKEY hkey_users_default )
1685 LPCSTR confdir = wine_get_config_dir();
1686 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1688 strcpy(tmp,confdir);
1689 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1690 load_wine_registry(hkey_users_default,tmp);
1692 strcpy(tmp,confdir);
1693 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1694 load_wine_registry(hkey_current_user,tmp);
1696 strcpy(tmp,confdir);
1697 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1698 load_wine_registry(hkey_local_machine,tmp);
1700 free(tmp);
1703 /* load all registry (native and global and home) */
1704 void SHELL_LoadRegistry( void )
1706 HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user;
1707 OBJECT_ATTRIBUTES attr;
1708 UNICODE_STRING nameW;
1710 static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
1711 static const WCHAR UserW[] = {'U','s','e','r',0};
1712 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
1713 static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0};
1714 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};
1715 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};
1716 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};
1718 TRACE("(void)\n");
1720 if (!CLIENT_IsBootThread()) return; /* already loaded */
1722 attr.Length = sizeof(attr);
1723 attr.RootDirectory = 0;
1724 attr.ObjectName = &nameW;
1725 attr.Attributes = 0;
1726 attr.SecurityDescriptor = NULL;
1727 attr.SecurityQualityOfService = NULL;
1729 RtlInitUnicodeString( &nameW, MachineW );
1730 NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1731 RtlInitUnicodeString( &nameW, UserW );
1732 NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
1734 attr.RootDirectory = hkey_users;
1735 RtlInitUnicodeString( &nameW, DefaultW );
1736 if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
1738 ERR("Cannot create HKEY_USERS/.Default\n" );
1739 ExitProcess(1);
1741 RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
1743 _set_registry_levels(0,0,0);
1744 _allocate_default_keys();
1745 if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1))
1746 _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1747 if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1))
1748 _load_global_registry( hkey_local_machine, hkey_users );
1749 _set_registry_levels(1,0,0);
1750 if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1))
1751 _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
1752 _init_registry_saving( hkey_local_machine, hkey_current_user, hkey_users_default );
1753 NtClose(hkey_users_default);
1754 NtClose(hkey_current_user);
1755 NtClose(hkey_users);
1756 NtClose(hkey_local_machine);