Fixed memory allocation bug in PROPSHEET_CollectPageInfo.
[wine.git] / misc / registry.c
blobd4f0f01361de1b7f95b6cbeb6d272f2ed7f402a9
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 #include <unistd.h>
43 #include <errno.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #ifdef HAVE_SYS_MMAN_H
48 # include <sys/mman.h>
49 #endif
51 #include "winerror.h"
52 #include "winnt.h"
53 #include "winreg.h"
55 #include "wine/winbase16.h"
56 #include "wine/server.h"
57 #include "wine/unicode.h"
58 #include "file.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(reg);
64 /* FIXME: following defines should be configured global */
65 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
66 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
68 /* relative in ~user/.wine/ : */
69 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
70 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
71 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
73 /* _xmalloc [Internal] */
74 static void *_xmalloc( size_t size )
76 void *res;
78 res = malloc (size ? size : 1);
79 if (res == NULL) {
80 WARN("Virtual memory exhausted.\n");
81 exit (1);
83 return res;
86 /* _strdupnA [Internal] */
87 static LPSTR _strdupnA(LPCSTR str,size_t len)
89 LPSTR ret;
91 if (!str) return NULL;
92 ret = _xmalloc( len + 1 );
93 memcpy( ret, str, len );
94 ret[len] = 0x00;
95 return ret;
98 /* convert ansi string to unicode [Internal] */
99 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
101 LPWSTR ret;
102 size_t lenW;
104 if (!strA) return NULL;
105 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
106 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
107 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
108 ret[lenW] = 0;
109 return ret;
112 /* dump a Unicode string with proper escaping [Internal] */
113 /* FIXME: this code duplicates server/unicode.c */
114 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
116 static const char escapes[32] = ".......abtnvfr.............e....";
117 char buffer[256];
118 LPSTR pos = buffer;
119 int count = 0;
121 for (; len; str++, len--)
123 if (pos > buffer + sizeof(buffer) - 8)
125 fwrite( buffer, pos - buffer, 1, f );
126 count += pos - buffer;
127 pos = buffer;
129 if (*str > 127) /* hex escape */
131 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
132 pos += sprintf( pos, "\\x%04x", *str );
133 else
134 pos += sprintf( pos, "\\x%x", *str );
135 continue;
137 if (*str < 32) /* octal or C escape */
139 if (!*str && len == 1) continue; /* do not output terminating NULL */
140 if (escapes[*str] != '.')
141 pos += sprintf( pos, "\\%c", escapes[*str] );
142 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
143 pos += sprintf( pos, "\\%03o", *str );
144 else
145 pos += sprintf( pos, "\\%o", *str );
146 continue;
148 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
149 *pos++ = *str;
151 fwrite( buffer, pos - buffer, 1, f );
152 count += pos - buffer;
153 return count;
156 /* convert ansi string to unicode and dump with proper escaping [Internal] */
157 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
159 WCHAR *strW;
160 int ret;
162 if (strA == NULL) return 0;
163 strW = _strdupnAtoW(strA,len);
164 ret = _dump_strW(strW,len,f,escape);
165 free(strW);
166 return ret;
169 /* a key value */
170 /* FIXME: this code duplicates server/registry.c */
171 struct key_value {
172 WCHAR *nameW; /* value name */
173 int type; /* value type */
174 size_t len; /* value data length in bytes */
175 void *data; /* pointer to value data */
178 /* dump a value to a text file */
179 /* FIXME: this code duplicates server/registry.c */
180 static void _dump_value(struct key_value *value,FILE *f)
182 int i, count;
184 if (value->nameW[0]) {
185 fputc( '\"', f );
186 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
187 count += fprintf( f, "\"=" );
189 else count = fprintf( f, "@=" );
191 switch(value->type) {
192 case REG_SZ:
193 case REG_EXPAND_SZ:
194 case REG_MULTI_SZ:
195 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
196 fputc( '\"', f );
197 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
198 fputc( '\"', f );
199 break;
200 case REG_DWORD:
201 if (value->len == sizeof(DWORD)) {
202 DWORD dw;
203 memcpy( &dw, value->data, sizeof(DWORD) );
204 fprintf( f, "dword:%08lx", dw );
205 break;
207 /* else fall through */
208 default:
209 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
210 else count += fprintf( f, "hex(%x):", value->type );
211 for (i = 0; i < value->len; i++) {
212 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
213 if (i < value->len-1) {
214 fputc( ',', f );
215 if (++count > 76) {
216 fprintf( f, "\\\n " );
217 count = 2;
221 break;
223 fputc( '\n', f );
226 /******************************************************************/
227 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
229 reghack - windows 3.11 registry data format demo program.
231 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
232 a combined hash table and tree description, and finally a text table.
234 The header is obvious from the struct header. The taboff1 and taboff2
235 fields are always 0x20, and their usage is unknown.
237 The 8-byte entry table has various entry types.
239 tabent[0] is a root index. The second word has the index of the root of
240 the directory.
241 tabent[1..hashsize] is a hash table. The first word in the hash entry is
242 the index of the key/value that has that hash. Data with the same
243 hash value are on a circular list. The other three words in the
244 hash entry are always zero.
245 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
246 entry: dirent and keyent/valent. They are identified by context.
247 tabent[freeidx] is the first free entry. The first word in a free entry
248 is the index of the next free entry. The last has 0 as a link.
249 The other three words in the free list are probably irrelevant.
251 Entries in text table are preceded by a word at offset-2. This word
252 has the value (2*index)+1, where index is the referring keyent/valent
253 entry in the table. I have no suggestion for the 2* and the +1.
254 Following the word, there are N bytes of data, as per the keyent/valent
255 entry length. The offset of the keyent/valent entry is from the start
256 of the text table to the first data byte.
258 This information is not available from Microsoft. The data format is
259 deduced from the reg.dat file by me. Mistakes may
260 have been made. I claim no rights and give no guarantees for this program.
262 Tor Sjøwall, tor@sn.no
265 /* reg.dat header format */
266 struct _w31_header {
267 char cookie[8]; /* 'SHCC3.10' */
268 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
269 unsigned long taboff2; /* offset of index table (??) = 0x20 */
270 unsigned long tabcnt; /* number of entries in index table */
271 unsigned long textoff; /* offset of text part */
272 unsigned long textsize; /* byte size of text part */
273 unsigned short hashsize; /* hash size */
274 unsigned short freeidx; /* free index */
277 /* generic format of table entries */
278 struct _w31_tabent {
279 unsigned short w0, w1, w2, w3;
282 /* directory tabent: */
283 struct _w31_dirent {
284 unsigned short sibling_idx; /* table index of sibling dirent */
285 unsigned short child_idx; /* table index of child dirent */
286 unsigned short key_idx; /* table index of key keyent */
287 unsigned short value_idx; /* table index of value valent */
290 /* key tabent: */
291 struct _w31_keyent {
292 unsigned short hash_idx; /* hash chain index for string */
293 unsigned short refcnt; /* reference count */
294 unsigned short length; /* length of string */
295 unsigned short string_off; /* offset of string in text table */
298 /* value tabent: */
299 struct _w31_valent {
300 unsigned short hash_idx; /* hash chain index for string */
301 unsigned short refcnt; /* reference count */
302 unsigned short length; /* length of string */
303 unsigned short string_off; /* offset of string in text table */
306 /* recursive helper function to display a directory tree [Internal] */
307 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
309 struct _w31_dirent *dir;
310 struct _w31_keyent *key;
311 struct _w31_valent *val;
312 HKEY subkey = 0;
313 static char tail[400];
315 while (idx!=0) {
316 dir=(struct _w31_dirent*)&tab[idx];
318 if (dir->key_idx) {
319 key = (struct _w31_keyent*)&tab[dir->key_idx];
321 memcpy(tail,&txt[key->string_off],key->length);
322 tail[key->length]='\0';
323 /* all toplevel entries AND the entries in the
324 * toplevel subdirectory belong to \SOFTWARE\Classes
326 if (!level && !strcmp(tail,".classes")) {
327 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
328 idx=dir->sibling_idx;
329 continue;
331 if (subkey) RegCloseKey( subkey );
332 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
333 /* only add if leaf node or valued node */
334 if (dir->value_idx!=0||dir->child_idx==0) {
335 if (dir->value_idx) {
336 val=(struct _w31_valent*)&tab[dir->value_idx];
337 memcpy(tail,&txt[val->string_off],val->length);
338 tail[val->length]='\0';
339 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
342 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
343 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
344 idx=dir->sibling_idx;
346 if (subkey) RegCloseKey( subkey );
350 /******************************************************************************
351 * _w31_loadreg [Internal]
353 void _w31_loadreg(void)
355 HFILE hf;
356 struct _w31_header head;
357 struct _w31_tabent *tab;
358 unsigned char *txt;
359 unsigned int len;
360 OFSTRUCT ofs;
361 BY_HANDLE_FILE_INFORMATION hfinfo;
362 time_t lastmodified;
364 TRACE("(void)\n");
366 hf = OpenFile("reg.dat",&ofs,OF_READ);
367 if (hf==HFILE_ERROR) return;
369 /* read & dump header */
370 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
371 ERR("reg.dat is too short.\n");
372 _lclose(hf);
373 return;
375 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
376 ERR("reg.dat has bad signature.\n");
377 _lclose(hf);
378 return;
381 len = head.tabcnt * sizeof(struct _w31_tabent);
382 /* read and dump index table */
383 tab = _xmalloc(len);
384 if (len!=_lread(hf,tab,len)) {
385 ERR("couldn't read %d bytes.\n",len);
386 free(tab);
387 _lclose(hf);
388 return;
391 /* read text */
392 txt = _xmalloc(head.textsize);
393 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
394 ERR("couldn't seek to textblock.\n");
395 free(tab);
396 free(txt);
397 _lclose(hf);
398 return;
400 if (head.textsize!=_lread(hf,txt,head.textsize)) {
401 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
402 free(tab);
403 free(txt);
404 _lclose(hf);
405 return;
408 if (!GetFileInformationByHandle(hf,&hfinfo)) {
409 ERR("GetFileInformationByHandle failed?.\n");
410 free(tab);
411 free(txt);
412 _lclose(hf);
413 return;
415 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
416 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
417 free(tab);
418 free(txt);
419 _lclose(hf);
420 return;
423 /***********************************************************************************/
424 /* windows 95 registry loader */
425 /***********************************************************************************/
427 /* SECTION 1: main header
429 * once at offset 0
431 #define W95_REG_CREG_ID 0x47455243
433 typedef struct {
434 DWORD id; /* "CREG" = W95_REG_CREG_ID */
435 DWORD version; /* ???? 0x00010000 */
436 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
437 DWORD uk2; /* 0x0c */
438 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
439 WORD uk3;
440 DWORD uk[3];
441 /* rgkn */
442 } _w95creg;
444 /* SECTION 2: Directory information (tree structure)
446 * once on offset 0x20
448 * structure: [rgkn][dke]* (repeat till last_dke is reached)
450 #define W95_REG_RGKN_ID 0x4e4b4752
452 typedef struct {
453 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
454 DWORD size; /* Size of the RGKN-block */
455 DWORD root_off; /* Rel. Offset of the root-record */
456 DWORD last_dke; /* Offset to last DKE ? */
457 DWORD uk[4];
458 } _w95rgkn;
460 /* Disk Key Entry Structure
462 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
463 * hive itself. It looks the same like other keys. Even the ID-number can
464 * be any value.
466 * The "hash"-value is a value representing the key's name. Windows will not
467 * search for the name, but for a matching hash-value. if it finds one, it
468 * will compare the actual string info, otherwise continue with the next key.
469 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
470 * of the string which are smaller than 0x80 (128) to this D-Word.
472 * If you want to modify key names, also modify the hash-values, since they
473 * cannot be found again (although they would be displayed in REGEDIT)
474 * End of list-pointers are filled with 0xFFFFFFFF
476 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
477 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
478 * structure) and reading another RGDB_section.
480 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
481 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
482 * The remaining space between last_dke and the offset calculated from
483 * rgkn->size seems to be free for use for more dke:s.
484 * So it seems if more dke:s are added, they are added to that space and
485 * last_dke is grown, and in case that "free" space is out, the space
486 * gets grown and rgkn->size gets adjusted.
488 * there is a one to one relationship between dke and dkh
490 /* key struct, once per key */
491 typedef struct {
492 DWORD x1; /* Free entry indicator(?) */
493 DWORD hash; /* sum of bytes of keyname */
494 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
495 DWORD prevlvl; /* offset of previous key */
496 DWORD nextsub; /* offset of child key */
497 DWORD next; /* offset of sibling key */
498 WORD nrLS; /* id inside the rgdb block */
499 WORD nrMS; /* number of the rgdb block */
500 } _w95dke;
502 /* SECTION 3: key information, values and data
504 * structure:
505 * section: [blocks]* (repeat creg->rgdb_num times)
506 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
507 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
509 * An interesting relationship exists in RGDB_section. The DWORD value
510 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
511 * I have no idea at the moment what this means. (Kevin Cozens)
514 /* block header, once per block */
515 #define W95_REG_RGDB_ID 0x42444752
517 typedef struct {
518 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
519 DWORD size; /* 0x04 */
520 DWORD uk1; /* 0x08 */
521 DWORD uk2; /* 0x0c */
522 DWORD uk3; /* 0x10 */
523 DWORD uk4; /* 0x14 */
524 DWORD uk5; /* 0x18 */
525 DWORD uk6; /* 0x1c */
526 /* dkh */
527 } _w95rgdb;
529 /* Disk Key Header structure (RGDB part), once per key */
530 typedef struct {
531 DWORD nextkeyoff; /* 0x00 offset to next dkh */
532 WORD nrLS; /* 0x04 id inside the rgdb block */
533 WORD nrMS; /* 0x06 number of the rgdb block */
534 DWORD bytesused; /* 0x08 */
535 WORD keynamelen; /* 0x0c len of name */
536 WORD values; /* 0x0e number of values */
537 DWORD xx1; /* 0x10 */
538 char name[1]; /* 0x14 */
539 /* dkv */ /* 0x14 + keynamelen */
540 } _w95dkh;
542 /* Disk Key Value structure, once per value */
543 typedef struct {
544 DWORD type; /* 0x00 */
545 DWORD x1; /* 0x04 */
546 WORD valnamelen; /* 0x08 length of name, 0 is default key */
547 WORD valdatalen; /* 0x0A length of data */
548 char name[1]; /* 0x0c */
549 /* raw data */ /* 0x0c + valnamelen */
550 } _w95dkv;
552 /******************************************************************************
553 * _w95_lookup_dkh [Internal]
555 * seeks the dkh belonging to a dke
557 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
559 _w95rgdb * rgdb;
560 _w95dkh * dkh;
561 int i;
563 /* get the beginning of the rgdb datastore */
564 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
566 /* check: requested block < last_block) */
567 if (creg->rgdb_num <= nrMS) {
568 ERR("registry file corrupt! requested block no. beyond end.\n");
569 goto error;
572 /* find the right block */
573 for(i=0; i<nrMS ;i++) {
574 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
575 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
576 goto error;
578 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
581 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
583 do {
584 if(nrLS==dkh->nrLS ) return dkh;
585 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
586 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
588 error:
589 return NULL;
592 /******************************************************************************
593 * _w95_dump_dkv [Internal]
595 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
597 _w95dkv * dkv;
598 int i;
600 /* first value block */
601 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
603 /* loop through the values */
604 for (i=0; i< dkh->values; i++) {
605 struct key_value value;
606 WCHAR *pdata;
608 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
609 value.type = dkv->type;
610 value.len = dkv->valdatalen;
612 value.data = &(dkv->name[dkv->valnamelen]);
613 pdata = NULL;
614 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
615 pdata = _strdupnAtoW(value.data,value.len);
616 value.len *= 2;
618 if (pdata != NULL) value.data = pdata;
620 _dump_value(&value,f);
621 free(value.nameW);
622 if (pdata != NULL) free(pdata);
624 /* next value */
625 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
627 return TRUE;
630 /******************************************************************************
631 * _w95_dump_dke [Internal]
633 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
635 _w95dkh * dkh;
636 LPSTR new_key_name = NULL;
638 /* special root key */
639 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
641 /* parse the one subkey */
642 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
643 /* has no sibling keys */
644 return FALSE;
647 /* search subblock */
648 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
649 ERR("dke pointing to missing dkh !\n");
650 return FALSE;
653 if (level <= 0) {
654 /* create new subkey name */
655 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
656 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
657 strncat(new_key_name,dkh->name,dkh->keynamelen);
659 /* walk sibling keys */
660 if (dke->next != 0xffffffff ) {
661 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
662 free(new_key_name);
663 return FALSE;
667 /* write the key path (something like [Software\\Microsoft\\..]) only if:
668 1) key has some values
669 2) key has no values and no subkeys
671 if (dkh->values > 0) {
672 /* there are some values */
673 fprintf(f,"\n[");
674 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
675 fprintf(f,"]\n");
676 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
677 free(new_key_name);
678 return FALSE;
681 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
682 /* no subkeys and no values */
683 fprintf(f,"\n[");
684 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
685 fprintf(f,"]\n");
687 } else new_key_name = _strdupnA(key_name,strlen(key_name));
689 /* next sub key */
690 if (dke->nextsub != 0xffffffff) {
691 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
692 free(new_key_name);
693 return FALSE;
697 free(new_key_name);
698 return TRUE;
700 /* end windows 95 loader */
702 /***********************************************************************************/
703 /* windows NT registry loader */
704 /***********************************************************************************/
706 /* NT REGISTRY LOADER */
708 #ifdef HAVE_SYS_MMAN_H
709 # include <sys/mman.h>
710 #endif
712 #ifndef MAP_FAILED
713 #define MAP_FAILED ((LPVOID)-1)
714 #endif
716 #define NT_REG_BLOCK_SIZE 0x1000
718 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
719 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
720 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
721 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
723 /* subblocks of nk */
724 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
725 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
726 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
728 #define NT_REG_KEY_BLOCK_TYPE 0x20
729 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
731 typedef struct {
732 DWORD id; /* 0x66676572 'regf'*/
733 DWORD uk1; /* 0x04 */
734 DWORD uk2; /* 0x08 */
735 FILETIME DateModified; /* 0x0c */
736 DWORD uk3; /* 0x14 */
737 DWORD uk4; /* 0x18 */
738 DWORD uk5; /* 0x1c */
739 DWORD uk6; /* 0x20 */
740 DWORD RootKeyBlock; /* 0x24 */
741 DWORD BlockSize; /* 0x28 */
742 DWORD uk7[116];
743 DWORD Checksum; /* at offset 0x1FC */
744 } nt_regf;
746 typedef struct {
747 DWORD blocksize;
748 BYTE data[1];
749 } nt_hbin_sub;
751 typedef struct {
752 DWORD id; /* 0x6E696268 'hbin' */
753 DWORD off_prev;
754 DWORD off_next;
755 DWORD uk1;
756 DWORD uk2; /* 0x10 */
757 DWORD uk3; /* 0x14 */
758 DWORD uk4; /* 0x18 */
759 DWORD size; /* 0x1C */
760 nt_hbin_sub hbin_sub; /* 0x20 */
761 } nt_hbin;
764 * the value_list consists of offsets to the values (vk)
766 typedef struct {
767 WORD SubBlockId; /* 0x00 0x6B6E */
768 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
769 FILETIME writetime; /* 0x04 */
770 DWORD uk1; /* 0x0C */
771 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
772 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
773 DWORD uk8; /* 0x18 */
774 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
775 DWORD uk2; /* 0x20 */
776 DWORD nr_values; /* 0x24 number of values */
777 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
778 DWORD off_sk; /* 0x2c Offset of the sk-Record */
779 DWORD off_class; /* 0x30 Offset of the Class-Name */
780 DWORD uk3; /* 0x34 */
781 DWORD uk4; /* 0x38 */
782 DWORD uk5; /* 0x3c */
783 DWORD uk6; /* 0x40 */
784 DWORD uk7; /* 0x44 */
785 WORD name_len; /* 0x48 name-length */
786 WORD class_len; /* 0x4a class-name length */
787 char name[1]; /* 0x4c key-name */
788 } nt_nk;
790 typedef struct {
791 DWORD off_nk; /* 0x00 */
792 DWORD name; /* 0x04 */
793 } hash_rec;
795 typedef struct {
796 WORD id; /* 0x00 0x666c */
797 WORD nr_keys; /* 0x06 */
798 hash_rec hash_rec[1];
799 } nt_lf;
802 list of subkeys without hash
804 li --+-->nk
806 +-->nk
808 typedef struct {
809 WORD id; /* 0x00 0x696c */
810 WORD nr_keys;
811 DWORD off_nk[1];
812 } nt_li;
815 this is a intermediate node
817 ri --+-->li--+-->nk
819 | +-->nk
821 +-->li--+-->nk
823 +-->nk
825 typedef struct {
826 WORD id; /* 0x00 0x6972 */
827 WORD nr_li; /* 0x02 number off offsets */
828 DWORD off_li[1]; /* 0x04 points to li */
829 } nt_ri;
831 typedef struct {
832 WORD id; /* 0x00 'vk' */
833 WORD nam_len;
834 DWORD data_len;
835 DWORD data_off;
836 DWORD type;
837 WORD flag;
838 WORD uk1;
839 char name[1];
840 } nt_vk;
843 * gets a value
845 * vk->flag:
846 * 0 value is a default value
847 * 1 the value has a name
849 * vk->data_len
850 * len of the whole data block
851 * - reg_sz (unicode)
852 * bytes including the terminating \0 = 2*(number_of_chars+1)
853 * - reg_dword, reg_binary:
854 * if highest bit of data_len is set data_off contains the value
856 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
858 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
859 struct key_value value;
861 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
862 ERR("unknown block found (0x%04x), please report!\n", vk->id);
863 return FALSE;
866 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
867 value.type = vk->type;
868 value.len = (vk->data_len & 0x7fffffff);
869 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
871 _dump_value(&value,f);
872 free(value.nameW);
874 return TRUE;
877 /* it's called from _nt_dump_lf() */
878 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
881 * get the subkeys
883 * this structure contains the hash of a keyname and points to all
884 * subkeys
886 * exception: if the id is 'il' there are no hash values and every
887 * dword is a offset
889 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
891 int i;
893 if (lf->id == NT_REG_HASH_BLOCK_ID) {
894 if (subkeys != lf->nr_keys) goto error1;
896 for (i=0; i<lf->nr_keys; i++)
897 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
898 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
899 nt_li * li = (nt_li*)lf;
900 if (subkeys != li->nr_keys) goto error1;
902 for (i=0; i<li->nr_keys; i++)
903 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
904 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
905 nt_ri * ri = (nt_ri*)lf;
906 int li_subkeys = 0;
908 /* count all subkeys */
909 for (i=0; i<ri->nr_li; i++) {
910 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
911 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
912 li_subkeys += li->nr_keys;
915 /* check number */
916 if (subkeys != li_subkeys) goto error1;
918 /* loop through the keys */
919 for (i=0; i<ri->nr_li; i++) {
920 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
921 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
923 } else goto error2;
925 return TRUE;
927 error2:
928 if (lf->id == 0x686c)
929 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
930 else
931 ERR("unknown node id 0x%04x, please report!\n", lf->id);
932 return TRUE;
934 error1:
935 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
936 return FALSE;
938 error:
939 ERR("error reading lf block\n");
940 return FALSE;
943 /* _nt_dump_nk [Internal] */
944 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
946 unsigned int n;
947 DWORD *vl;
948 LPSTR new_key_name = NULL;
950 TRACE("%s\n", key_name);
952 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
953 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
954 return FALSE;
957 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
958 ERR("registry file corrupt!\n");
959 return FALSE;
962 /* create the new key */
963 if (level <= 0) {
964 /* create new subkey name */
965 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
966 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
967 strncat(new_key_name,nk->name,nk->name_len);
969 /* write the key path (something like [Software\\Microsoft\\..]) only if:
970 1) key has some values
971 2) key has no values and no subkeys
973 if (nk->nr_values > 0) {
974 /* there are some values */
975 fprintf(f,"\n[");
976 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
977 fprintf(f,"]\n");
979 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
980 /* no subkeys and no values */
981 fprintf(f,"\n[");
982 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
983 fprintf(f,"]\n");
986 /* loop trough the value list */
987 vl = (DWORD *)(base+nk->valuelist_off+4);
988 for (n=0; n<nk->nr_values; n++) {
989 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
990 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
991 free(new_key_name);
992 return FALSE;
995 } else new_key_name = _strdupnA(key_name,strlen(key_name));
997 /* loop through the subkeys */
998 if (nk->nr_subkeys) {
999 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1000 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1001 free(new_key_name);
1002 return FALSE;
1006 free(new_key_name);
1007 return TRUE;
1010 /* end nt loader */
1012 /**********************************************************************************
1013 * _set_registry_levels [Internal]
1015 * set level to 0 for loading system files
1016 * set level to 1 for loading user files
1018 static void _set_registry_levels(int level,int saving,int period)
1020 SERVER_START_REQ( set_registry_levels )
1022 req->current = level;
1023 req->saving = saving;
1024 req->period = period;
1025 wine_server_call( req );
1027 SERVER_END_REQ;
1030 /* _save_at_exit [Internal] */
1031 static void _save_at_exit(HKEY hkey,LPCSTR path)
1033 LPCSTR confdir = get_config_dir();
1035 SERVER_START_REQ( save_registry_atexit )
1037 req->hkey = hkey;
1038 wine_server_add_data( req, confdir, strlen(confdir) );
1039 wine_server_add_data( req, path, strlen(path)+1 );
1040 wine_server_call( req );
1042 SERVER_END_REQ;
1045 /* configure save files and start the periodic saving timer [Internal] */
1046 static void _init_registry_saving( HKEY hkey_users_default )
1048 int all;
1049 int period = 0;
1050 char buffer[20];
1052 all = !PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1053 PROFILE_GetWineIniString( "registry", "PeriodicSave", "", buffer, sizeof(buffer) );
1054 if (buffer[0]) period = atoi(buffer);
1056 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1057 _set_registry_levels(1,!all,period*1000);
1059 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1061 _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1062 _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1063 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1068 /******************************************************************************
1069 * _allocate_default_keys [Internal]
1070 * Registry initialisation, allocates some default keys.
1072 static void _allocate_default_keys(void) {
1073 HKEY hkey;
1074 char buf[200];
1076 TRACE("(void)\n");
1078 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1079 RegCloseKey(hkey);
1081 /* This was an Open, but since it is called before the real registries
1082 are loaded, it was changed to a Create - MTB 980507*/
1083 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1084 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1085 RegCloseKey(hkey);
1087 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1088 * CurrentVersion
1089 * CurrentBuildNumber
1090 * CurrentType
1091 * string RegisteredOwner
1092 * string RegisteredOrganization
1095 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1096 * string SysContact
1097 * string SysLocation
1098 * SysServices
1100 if (-1!=gethostname(buf,200)) {
1101 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1102 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1103 RegCloseKey(hkey);
1106 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1107 RegCloseKey(hkey);
1110 #define REG_DONTLOAD -1
1111 #define REG_WIN31 0
1112 #define REG_WIN95 1
1113 #define REG_WINNT 2
1115 /* return the type of native registry [Internal] */
1116 static int _get_reg_type(void)
1118 char windir[MAX_PATHNAME_LEN];
1119 char tmp[MAX_PATHNAME_LEN];
1120 int ret = REG_WIN31;
1122 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1124 /* test %windir%/system32/config/system --> winnt */
1125 strcpy(tmp, windir);
1126 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1127 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1128 ret = REG_WINNT;
1130 else
1132 /* test %windir%/system.dat --> win95 */
1133 strcpy(tmp, windir);
1134 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1135 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1136 ret = REG_WIN95;
1140 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1141 MESSAGE("When you are running with a native NT directory specify\n");
1142 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1143 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1144 ret = REG_DONTLOAD;
1147 return ret;
1150 #define WINE_REG_VER_ERROR -1
1151 #define WINE_REG_VER_1 0
1152 #define WINE_REG_VER_2 1
1153 #define WINE_REG_VER_OLD 2
1154 #define WINE_REG_VER_UNKNOWN 3
1156 /* return the version of wine registry file [Internal] */
1157 static int _get_wine_registry_file_format_version(LPCSTR fn)
1159 FILE *f;
1160 char tmp[50];
1161 int ver;
1163 if ((f=fopen(fn,"rt")) == NULL) {
1164 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1165 return WINE_REG_VER_ERROR;
1168 if (fgets(tmp,50,f) == NULL) {
1169 WARN("Error reading %s: %s\n",fn,strerror(errno));
1170 fclose(f);
1171 return WINE_REG_VER_ERROR;
1173 fclose(f);
1175 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1176 switch (ver) {
1177 case 1:
1178 return WINE_REG_VER_1;
1179 break;
1180 case 2:
1181 return WINE_REG_VER_2;
1182 break;
1183 default:
1184 return WINE_REG_VER_UNKNOWN;
1188 /* load the registry file in wine format [Internal] */
1189 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1191 int file_format;
1193 file_format = _get_wine_registry_file_format_version(fn);
1194 switch (file_format) {
1196 case WINE_REG_VER_1:
1197 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1198 break;
1200 case WINE_REG_VER_2: {
1201 HANDLE file;
1202 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1203 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1205 SERVER_START_REQ( load_registry )
1207 req->hkey = hkey;
1208 req->file = file;
1209 wine_server_call( req );
1211 SERVER_END_REQ;
1212 CloseHandle( file );
1214 break;
1217 case WINE_REG_VER_UNKNOWN:
1218 WARN("Unable to load registry file %s: unknown format.\n",fn);
1219 break;
1221 case WINE_REG_VER_ERROR:
1222 break;
1226 /* generate and return the name of the tmp file and associated stream [Internal] */
1227 static LPSTR _get_tmp_fn(FILE **f)
1229 LPSTR ret;
1230 int tmp_fd,count;
1232 ret = _xmalloc(50);
1233 for (count = 0;;) {
1234 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1235 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1236 if (errno != EEXIST) {
1237 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1238 free(ret);
1239 *f = NULL;
1240 return NULL;
1244 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1245 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1246 close(tmp_fd);
1247 free(ret);
1248 return NULL;
1251 return ret;
1254 /* convert win95 native registry file to wine format [Internal] */
1255 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1257 int fd;
1258 FILE *f;
1259 DOS_FULL_NAME full_name;
1260 void *base;
1261 LPSTR ret = NULL;
1262 struct stat st;
1264 _w95creg *creg;
1265 _w95rgkn *rgkn;
1266 _w95dke *dke, *root_dke;
1268 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1270 /* map the registry into the memory */
1271 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1272 if ((fstat(fd, &st) == -1)) goto error1;
1273 if (!st.st_size) goto error1;
1274 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1276 /* control signature */
1277 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1278 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1279 goto error;
1282 creg = base;
1283 /* load the header (rgkn) */
1284 rgkn = (_w95rgkn*)(creg + 1);
1285 if (rgkn->id != W95_REG_RGKN_ID) {
1286 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1287 goto error;
1289 if (rgkn->root_off != 0x20) {
1290 ERR("rgkn->root_off not 0x20, please report !\n");
1291 goto error;
1293 if (rgkn->last_dke > rgkn->size)
1295 ERR("registry file corrupt! last_dke > size!\n");
1296 goto error;
1298 /* verify last dke */
1299 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1300 if (dke->x1 != 0x80000000)
1301 { /* wrong magic */
1302 ERR("last dke invalid !\n");
1303 goto error;
1305 if (rgkn->size > creg->rgdb_off)
1307 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1308 goto error;
1310 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1311 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1313 ERR("registry file corrupt! invalid root dke !\n");
1314 goto error;
1317 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1318 fprintf(f,"WINE REGISTRY Version 2");
1319 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1320 fclose(f);
1322 error:
1323 if(ret == NULL) {
1324 ERR("Unable to load native win95 registry file %s.\n",fn);
1325 ERR("Please report this.\n");
1326 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1329 munmap(base, st.st_size);
1330 error1:
1331 close(fd);
1332 return ret;
1335 /* convert winnt native registry file to wine format [Internal] */
1336 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1338 FILE *f;
1339 void *base;
1340 LPSTR ret = NULL;
1341 HANDLE hFile;
1342 HANDLE hMapping;
1344 nt_regf *regf;
1345 nt_hbin *hbin;
1346 nt_hbin_sub *hbin_sub;
1347 nt_nk *nk;
1349 TRACE("%s\n", fn);
1351 hFile = CreateFileA( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1352 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1353 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1354 if (!hMapping) goto error1;
1355 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1356 CloseHandle( hMapping );
1357 if (!base) goto error1;
1359 /* control signature */
1360 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1361 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1362 goto error;
1365 /* start block */
1366 regf = base;
1368 /* hbin block */
1369 hbin = (nt_hbin*)((char*) base + 0x1000);
1370 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1371 ERR( "hbin block invalid\n");
1372 goto error;
1375 /* hbin_sub block */
1376 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1377 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1378 ERR( "hbin_sub block invalid\n");
1379 goto error;
1382 /* nk block */
1383 nk = (nt_nk*)&(hbin_sub->data[0]);
1384 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1385 ERR( "special nk block not found\n");
1386 goto error;
1389 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1390 fprintf(f,"WINE REGISTRY Version 2");
1391 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1392 fclose(f);
1394 error:
1395 UnmapViewOfFile( base );
1396 error1:
1397 CloseHandle(hFile);
1398 return ret;
1401 /* convert native registry to wine format and load it via server call [Internal] */
1402 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1404 LPSTR tmp = NULL;
1406 switch (reg_type) {
1407 case REG_WINNT:
1408 /* FIXME: following function doesn't really convert yet */
1409 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1410 break;
1411 case REG_WIN95:
1412 tmp = _convert_win95_registry_to_wine_format(fn,level);
1413 break;
1414 case REG_WIN31:
1415 ERR("Don't know how to convert native 3.1 registry yet.\n");
1416 break;
1417 default:
1418 ERR("Unknown registry format parameter (%d)\n",reg_type);
1419 break;
1422 if (tmp != NULL) {
1423 load_wine_registry(hkey,tmp);
1424 TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp);
1425 unlink(tmp);
1427 else WARN("Unable to convert %s (doesn't exist?)\n",fn);
1428 free(tmp);
1431 /* load all native windows registry files [Internal] */
1432 static void _load_windows_registry( HKEY hkey_users_default )
1434 int reg_type;
1435 char windir[MAX_PATHNAME_LEN];
1436 char path[MAX_PATHNAME_LEN];
1438 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1440 reg_type = _get_reg_type();
1441 switch (reg_type) {
1442 case REG_WINNT: {
1443 HKEY hkey;
1445 /* user specific ntuser.dat */
1446 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1447 strcat(path,"\\ntuser.dat");
1448 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1451 /* default user.dat */
1452 if (hkey_users_default) {
1453 strcpy(path,windir);
1454 strcat(path,"\\system32\\config\\default");
1455 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1459 * FIXME
1460 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1463 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1464 strcpy(path,windir);
1465 strcat(path,"\\system32\\config\\system");
1466 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1467 RegCloseKey(hkey);
1470 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1471 strcpy(path,windir);
1472 strcat(path,"\\system32\\config\\software");
1473 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1474 RegCloseKey(hkey);
1477 strcpy(path,windir);
1478 strcat(path,"\\system32\\config\\sam");
1479 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1481 strcpy(path,windir);
1482 strcat(path,"\\system32\\config\\security");
1483 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1485 /* this key is generated when the nt-core booted successfully */
1486 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1487 break;
1490 case REG_WIN95:
1491 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1493 strcpy(path,windir);
1494 strcat(path,"\\system.dat");
1495 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1497 strcpy(path,windir);
1498 strcat(path,"\\classes.dat");
1499 _convert_and_load_native_registry(path,HKEY_CLASSES_ROOT,REG_WIN95,0);
1501 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1502 /* user specific user.dat */
1503 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1504 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1506 /* default user.dat */
1507 if (hkey_users_default) {
1508 strcpy(path,windir);
1509 strcat(path,"\\user.dat");
1510 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1512 } else {
1513 strcpy(path,windir);
1514 strcat(path,"\\user.dat");
1515 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1517 break;
1519 case REG_WIN31:
1520 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1521 _w31_loadreg();
1522 break;
1524 case REG_DONTLOAD:
1525 TRACE("REG_DONTLOAD\n");
1526 break;
1528 default:
1529 ERR("switch: no match (%d)\n",reg_type);
1530 break;
1535 /* load global registry files (stored in /etc/wine) [Internal] */
1536 static void _load_global_registry(void)
1538 TRACE("(void)\n");
1540 /* Load the global HKU hive directly from sysconfdir */
1541 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1543 /* Load the global machine defaults directly from sysconfdir */
1544 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1547 /* load home registry files (stored in ~/.wine) [Internal] */
1548 static void _load_home_registry( HKEY hkey_users_default )
1550 LPCSTR confdir = 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);
1568 /* load all registry (native and global and home) */
1569 void SHELL_LoadRegistry( void )
1571 HKEY hkey_users_default;
1573 TRACE("(void)\n");
1575 if (!CLIENT_IsBootThread()) return; /* already loaded */
1577 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1579 ERR("Cannot create HKEY_USERS/.Default\n" );
1580 ExitProcess(1);
1583 _allocate_default_keys();
1584 _set_registry_levels(0,0,0);
1585 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1586 _load_windows_registry( hkey_users_default );
1587 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1588 _load_global_registry();
1589 _set_registry_levels(1,0,0);
1590 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1591 _load_home_registry( hkey_users_default );
1592 _init_registry_saving( hkey_users_default );
1593 RegCloseKey(hkey_users_default);
1596 /***************************************************************************/
1597 /* API FUNCTIONS */
1598 /***************************************************************************/
1600 /******************************************************************************
1601 * RegFlushKey [ADVAPI32.@]
1602 * Immediately writes key to registry.
1603 * Only returns after data has been written to disk.
1605 * FIXME: does it really wait until data is written ?
1607 * PARAMS
1608 * hkey [I] Handle of key to write
1610 * RETURNS
1611 * Success: ERROR_SUCCESS
1612 * Failure: Error code
1614 DWORD WINAPI RegFlushKey( HKEY hkey )
1616 FIXME( "(%x): stub\n", hkey );
1617 return ERROR_SUCCESS;
1621 /******************************************************************************
1622 * RegUnLoadKeyA [ADVAPI32.@]
1624 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1626 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1627 return ERROR_SUCCESS;
1631 /******************************************************************************
1632 * RegReplaceKeyA [ADVAPI32.@]
1634 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1635 LPCSTR lpOldFile )
1637 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1638 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1639 return ERROR_SUCCESS;
1647 /* 16-bit functions */
1649 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1650 * some programs. Do not remove those cases. -MM
1652 static inline void fix_win16_hkey( HKEY *hkey )
1654 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1657 /******************************************************************************
1658 * RegEnumKey [KERNEL.216]
1659 * RegEnumKey [SHELL.7]
1661 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1663 fix_win16_hkey( &hkey );
1664 return RegEnumKeyA( hkey, index, name, name_len );
1667 /******************************************************************************
1668 * RegOpenKey [KERNEL.217]
1669 * RegOpenKey [SHELL.1]
1671 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1673 fix_win16_hkey( &hkey );
1674 return RegOpenKeyA( hkey, name, retkey );
1677 /******************************************************************************
1678 * RegCreateKey [KERNEL.218]
1679 * RegCreateKey [SHELL.2]
1681 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1683 fix_win16_hkey( &hkey );
1684 return RegCreateKeyA( hkey, name, retkey );
1687 /******************************************************************************
1688 * RegDeleteKey [KERNEL.219]
1689 * RegDeleteKey [SHELL.4]
1691 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1693 fix_win16_hkey( &hkey );
1694 return RegDeleteKeyA( hkey, name );
1697 /******************************************************************************
1698 * RegCloseKey [KERNEL.220]
1699 * RegCloseKey [SHELL.3]
1701 DWORD WINAPI RegCloseKey16( HKEY hkey )
1703 fix_win16_hkey( &hkey );
1704 return RegCloseKey( hkey );
1707 /******************************************************************************
1708 * RegSetValue [KERNEL.221]
1709 * RegSetValue [SHELL.5]
1711 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1713 fix_win16_hkey( &hkey );
1714 return RegSetValueA( hkey, name, type, data, count );
1717 /******************************************************************************
1718 * RegDeleteValue [KERNEL.222]
1720 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1722 fix_win16_hkey( &hkey );
1723 return RegDeleteValueA( hkey, name );
1726 /******************************************************************************
1727 * RegEnumValue [KERNEL.223]
1729 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1730 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1732 fix_win16_hkey( &hkey );
1733 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1736 /******************************************************************************
1737 * RegQueryValue [KERNEL.224]
1738 * RegQueryValue [SHELL.6]
1740 * NOTES
1741 * Is this HACK still applicable?
1743 * HACK
1744 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1745 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1746 * Aldus FH4)
1748 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1750 fix_win16_hkey( &hkey );
1751 if (count) *count &= 0xffff;
1752 return RegQueryValueA( hkey, name, data, count );
1755 /******************************************************************************
1756 * RegQueryValueEx [KERNEL.225]
1758 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1759 LPBYTE data, LPDWORD count )
1761 fix_win16_hkey( &hkey );
1762 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1765 /******************************************************************************
1766 * RegSetValueEx [KERNEL.226]
1768 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1769 CONST BYTE *data, DWORD count )
1771 fix_win16_hkey( &hkey );
1772 if (!count && (type==REG_SZ)) count = strlen(data);
1773 return RegSetValueExA( hkey, name, reserved, type, data, count );
1776 /******************************************************************************
1777 * RegFlushKey [KERNEL.227]
1779 DWORD WINAPI RegFlushKey16( HKEY hkey )
1781 fix_win16_hkey( &hkey );
1782 return RegFlushKey( hkey );