Stubs for DAD_Drag Enter, EnterEx, Move AutoScroll and Leave.
[wine/dcerpc.git] / misc / registry.c
blobb83841946c9d0808f8f1471ca60f4297029ce6f0
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/library.h"
57 #include "wine/server.h"
58 #include "wine/unicode.h"
59 #include "file.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(reg);
65 /* FIXME: following defines should be configured global */
66 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
67 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
69 /* relative in ~user/.wine/ : */
70 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
71 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
72 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
74 /* _xmalloc [Internal] */
75 static void *_xmalloc( size_t size )
77 void *res;
79 res = malloc (size ? size : 1);
80 if (res == NULL) {
81 WARN("Virtual memory exhausted.\n");
82 exit (1);
84 return res;
87 /* _strdupnA [Internal] */
88 static LPSTR _strdupnA(LPCSTR str,size_t len)
90 LPSTR ret;
92 if (!str) return NULL;
93 ret = _xmalloc( len + 1 );
94 memcpy( ret, str, len );
95 ret[len] = 0x00;
96 return ret;
99 /* convert ansi string to unicode [Internal] */
100 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
102 LPWSTR ret;
103 size_t lenW;
105 if (!strA) return NULL;
106 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
107 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
108 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
109 ret[lenW] = 0;
110 return ret;
113 /* dump a Unicode string with proper escaping [Internal] */
114 /* FIXME: this code duplicates server/unicode.c */
115 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
117 static const char escapes[32] = ".......abtnvfr.............e....";
118 char buffer[256];
119 LPSTR pos = buffer;
120 int count = 0;
122 for (; len; str++, len--)
124 if (pos > buffer + sizeof(buffer) - 8)
126 fwrite( buffer, pos - buffer, 1, f );
127 count += pos - buffer;
128 pos = buffer;
130 if (*str > 127) /* hex escape */
132 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
133 pos += sprintf( pos, "\\x%04x", *str );
134 else
135 pos += sprintf( pos, "\\x%x", *str );
136 continue;
138 if (*str < 32) /* octal or C escape */
140 if (!*str && len == 1) continue; /* do not output terminating NULL */
141 if (escapes[*str] != '.')
142 pos += sprintf( pos, "\\%c", escapes[*str] );
143 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
144 pos += sprintf( pos, "\\%03o", *str );
145 else
146 pos += sprintf( pos, "\\%o", *str );
147 continue;
149 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
150 *pos++ = *str;
152 fwrite( buffer, pos - buffer, 1, f );
153 count += pos - buffer;
154 return count;
157 /* convert ansi string to unicode and dump with proper escaping [Internal] */
158 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
160 WCHAR *strW;
161 int ret;
163 if (strA == NULL) return 0;
164 strW = _strdupnAtoW(strA,len);
165 ret = _dump_strW(strW,len,f,escape);
166 free(strW);
167 return ret;
170 /* a key value */
171 /* FIXME: this code duplicates server/registry.c */
172 struct key_value {
173 WCHAR *nameW; /* value name */
174 int type; /* value type */
175 size_t len; /* value data length in bytes */
176 void *data; /* pointer to value data */
179 /* dump a value to a text file */
180 /* FIXME: this code duplicates server/registry.c */
181 static void _dump_value(struct key_value *value,FILE *f)
183 int i, count;
185 if (value->nameW[0]) {
186 fputc( '\"', f );
187 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
188 count += fprintf( f, "\"=" );
190 else count = fprintf( f, "@=" );
192 switch(value->type) {
193 case REG_SZ:
194 case REG_EXPAND_SZ:
195 case REG_MULTI_SZ:
196 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
197 fputc( '\"', f );
198 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
199 fputc( '\"', f );
200 break;
201 case REG_DWORD:
202 if (value->len == sizeof(DWORD)) {
203 DWORD dw;
204 memcpy( &dw, value->data, sizeof(DWORD) );
205 fprintf( f, "dword:%08lx", dw );
206 break;
208 /* else fall through */
209 default:
210 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
211 else count += fprintf( f, "hex(%x):", value->type );
212 for (i = 0; i < value->len; i++) {
213 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
214 if (i < value->len-1) {
215 fputc( ',', f );
216 if (++count > 76) {
217 fprintf( f, "\\\n " );
218 count = 2;
222 break;
224 fputc( '\n', f );
227 /******************************************************************/
228 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
230 reghack - windows 3.11 registry data format demo program.
232 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
233 a combined hash table and tree description, and finally a text table.
235 The header is obvious from the struct header. The taboff1 and taboff2
236 fields are always 0x20, and their usage is unknown.
238 The 8-byte entry table has various entry types.
240 tabent[0] is a root index. The second word has the index of the root of
241 the directory.
242 tabent[1..hashsize] is a hash table. The first word in the hash entry is
243 the index of the key/value that has that hash. Data with the same
244 hash value are on a circular list. The other three words in the
245 hash entry are always zero.
246 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
247 entry: dirent and keyent/valent. They are identified by context.
248 tabent[freeidx] is the first free entry. The first word in a free entry
249 is the index of the next free entry. The last has 0 as a link.
250 The other three words in the free list are probably irrelevant.
252 Entries in text table are preceded by a word at offset-2. This word
253 has the value (2*index)+1, where index is the referring keyent/valent
254 entry in the table. I have no suggestion for the 2* and the +1.
255 Following the word, there are N bytes of data, as per the keyent/valent
256 entry length. The offset of the keyent/valent entry is from the start
257 of the text table to the first data byte.
259 This information is not available from Microsoft. The data format is
260 deduced from the reg.dat file by me. Mistakes may
261 have been made. I claim no rights and give no guarantees for this program.
263 Tor Sjøwall, tor@sn.no
266 /* reg.dat header format */
267 struct _w31_header {
268 char cookie[8]; /* 'SHCC3.10' */
269 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
270 unsigned long taboff2; /* offset of index table (??) = 0x20 */
271 unsigned long tabcnt; /* number of entries in index table */
272 unsigned long textoff; /* offset of text part */
273 unsigned long textsize; /* byte size of text part */
274 unsigned short hashsize; /* hash size */
275 unsigned short freeidx; /* free index */
278 /* generic format of table entries */
279 struct _w31_tabent {
280 unsigned short w0, w1, w2, w3;
283 /* directory tabent: */
284 struct _w31_dirent {
285 unsigned short sibling_idx; /* table index of sibling dirent */
286 unsigned short child_idx; /* table index of child dirent */
287 unsigned short key_idx; /* table index of key keyent */
288 unsigned short value_idx; /* table index of value valent */
291 /* key tabent: */
292 struct _w31_keyent {
293 unsigned short hash_idx; /* hash chain index for string */
294 unsigned short refcnt; /* reference count */
295 unsigned short length; /* length of string */
296 unsigned short string_off; /* offset of string in text table */
299 /* value tabent: */
300 struct _w31_valent {
301 unsigned short hash_idx; /* hash chain index for string */
302 unsigned short refcnt; /* reference count */
303 unsigned short length; /* length of string */
304 unsigned short string_off; /* offset of string in text table */
307 /* recursive helper function to display a directory tree [Internal] */
308 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
310 struct _w31_dirent *dir;
311 struct _w31_keyent *key;
312 struct _w31_valent *val;
313 HKEY subkey = 0;
314 static char tail[400];
316 while (idx!=0) {
317 dir=(struct _w31_dirent*)&tab[idx];
319 if (dir->key_idx) {
320 key = (struct _w31_keyent*)&tab[dir->key_idx];
322 memcpy(tail,&txt[key->string_off],key->length);
323 tail[key->length]='\0';
324 /* all toplevel entries AND the entries in the
325 * toplevel subdirectory belong to \SOFTWARE\Classes
327 if (!level && !strcmp(tail,".classes")) {
328 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
329 idx=dir->sibling_idx;
330 continue;
332 if (subkey) RegCloseKey( subkey );
333 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
334 /* only add if leaf node or valued node */
335 if (dir->value_idx!=0||dir->child_idx==0) {
336 if (dir->value_idx) {
337 val=(struct _w31_valent*)&tab[dir->value_idx];
338 memcpy(tail,&txt[val->string_off],val->length);
339 tail[val->length]='\0';
340 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
343 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
344 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
345 idx=dir->sibling_idx;
347 if (subkey) RegCloseKey( subkey );
351 /******************************************************************************
352 * _w31_loadreg [Internal]
354 void _w31_loadreg(void)
356 HFILE hf;
357 struct _w31_header head;
358 struct _w31_tabent *tab;
359 unsigned char *txt;
360 unsigned int len;
361 OFSTRUCT ofs;
362 BY_HANDLE_FILE_INFORMATION hfinfo;
363 time_t lastmodified;
365 TRACE("(void)\n");
367 hf = OpenFile("reg.dat",&ofs,OF_READ);
368 if (hf==HFILE_ERROR) return;
370 /* read & dump header */
371 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
372 ERR("reg.dat is too short.\n");
373 _lclose(hf);
374 return;
376 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
377 ERR("reg.dat has bad signature.\n");
378 _lclose(hf);
379 return;
382 len = head.tabcnt * sizeof(struct _w31_tabent);
383 /* read and dump index table */
384 tab = _xmalloc(len);
385 if (len!=_lread(hf,tab,len)) {
386 ERR("couldn't read %d bytes.\n",len);
387 free(tab);
388 _lclose(hf);
389 return;
392 /* read text */
393 txt = _xmalloc(head.textsize);
394 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
395 ERR("couldn't seek to textblock.\n");
396 free(tab);
397 free(txt);
398 _lclose(hf);
399 return;
401 if (head.textsize!=_lread(hf,txt,head.textsize)) {
402 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
403 free(tab);
404 free(txt);
405 _lclose(hf);
406 return;
409 if (!GetFileInformationByHandle(hf,&hfinfo)) {
410 ERR("GetFileInformationByHandle failed?.\n");
411 free(tab);
412 free(txt);
413 _lclose(hf);
414 return;
416 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
417 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
418 free(tab);
419 free(txt);
420 _lclose(hf);
421 return;
424 /***********************************************************************************/
425 /* windows 95 registry loader */
426 /***********************************************************************************/
428 /* SECTION 1: main header
430 * once at offset 0
432 #define W95_REG_CREG_ID 0x47455243
434 typedef struct {
435 DWORD id; /* "CREG" = W95_REG_CREG_ID */
436 DWORD version; /* ???? 0x00010000 */
437 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
438 DWORD uk2; /* 0x0c */
439 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
440 WORD uk3;
441 DWORD uk[3];
442 /* rgkn */
443 } _w95creg;
445 /* SECTION 2: Directory information (tree structure)
447 * once on offset 0x20
449 * structure: [rgkn][dke]* (repeat till last_dke is reached)
451 #define W95_REG_RGKN_ID 0x4e4b4752
453 typedef struct {
454 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
455 DWORD size; /* Size of the RGKN-block */
456 DWORD root_off; /* Rel. Offset of the root-record */
457 DWORD last_dke; /* Offset to last DKE ? */
458 DWORD uk[4];
459 } _w95rgkn;
461 /* Disk Key Entry Structure
463 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
464 * hive itself. It looks the same like other keys. Even the ID-number can
465 * be any value.
467 * The "hash"-value is a value representing the key's name. Windows will not
468 * search for the name, but for a matching hash-value. if it finds one, it
469 * will compare the actual string info, otherwise continue with the next key.
470 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
471 * of the string which are smaller than 0x80 (128) to this D-Word.
473 * If you want to modify key names, also modify the hash-values, since they
474 * cannot be found again (although they would be displayed in REGEDIT)
475 * End of list-pointers are filled with 0xFFFFFFFF
477 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
478 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
479 * structure) and reading another RGDB_section.
481 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
482 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
483 * The remaining space between last_dke and the offset calculated from
484 * rgkn->size seems to be free for use for more dke:s.
485 * So it seems if more dke:s are added, they are added to that space and
486 * last_dke is grown, and in case that "free" space is out, the space
487 * gets grown and rgkn->size gets adjusted.
489 * there is a one to one relationship between dke and dkh
491 /* key struct, once per key */
492 typedef struct {
493 DWORD x1; /* Free entry indicator(?) */
494 DWORD hash; /* sum of bytes of keyname */
495 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
496 DWORD prevlvl; /* offset of previous key */
497 DWORD nextsub; /* offset of child key */
498 DWORD next; /* offset of sibling key */
499 WORD nrLS; /* id inside the rgdb block */
500 WORD nrMS; /* number of the rgdb block */
501 } _w95dke;
503 /* SECTION 3: key information, values and data
505 * structure:
506 * section: [blocks]* (repeat creg->rgdb_num times)
507 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
508 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
510 * An interesting relationship exists in RGDB_section. The DWORD value
511 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
512 * I have no idea at the moment what this means. (Kevin Cozens)
515 /* block header, once per block */
516 #define W95_REG_RGDB_ID 0x42444752
518 typedef struct {
519 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
520 DWORD size; /* 0x04 */
521 DWORD uk1; /* 0x08 */
522 DWORD uk2; /* 0x0c */
523 DWORD uk3; /* 0x10 */
524 DWORD uk4; /* 0x14 */
525 DWORD uk5; /* 0x18 */
526 DWORD uk6; /* 0x1c */
527 /* dkh */
528 } _w95rgdb;
530 /* Disk Key Header structure (RGDB part), once per key */
531 typedef struct {
532 DWORD nextkeyoff; /* 0x00 offset to next dkh */
533 WORD nrLS; /* 0x04 id inside the rgdb block */
534 WORD nrMS; /* 0x06 number of the rgdb block */
535 DWORD bytesused; /* 0x08 */
536 WORD keynamelen; /* 0x0c len of name */
537 WORD values; /* 0x0e number of values */
538 DWORD xx1; /* 0x10 */
539 char name[1]; /* 0x14 */
540 /* dkv */ /* 0x14 + keynamelen */
541 } _w95dkh;
543 /* Disk Key Value structure, once per value */
544 typedef struct {
545 DWORD type; /* 0x00 */
546 DWORD x1; /* 0x04 */
547 WORD valnamelen; /* 0x08 length of name, 0 is default key */
548 WORD valdatalen; /* 0x0A length of data */
549 char name[1]; /* 0x0c */
550 /* raw data */ /* 0x0c + valnamelen */
551 } _w95dkv;
553 /******************************************************************************
554 * _w95_lookup_dkh [Internal]
556 * seeks the dkh belonging to a dke
558 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
560 _w95rgdb * rgdb;
561 _w95dkh * dkh;
562 int i;
564 /* get the beginning of the rgdb datastore */
565 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
567 /* check: requested block < last_block) */
568 if (creg->rgdb_num <= nrMS) {
569 ERR("registry file corrupt! requested block no. beyond end.\n");
570 goto error;
573 /* find the right block */
574 for(i=0; i<nrMS ;i++) {
575 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
576 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
577 goto error;
579 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
582 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
584 do {
585 if(nrLS==dkh->nrLS ) return dkh;
586 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
587 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
589 error:
590 return NULL;
593 /******************************************************************************
594 * _w95_dump_dkv [Internal]
596 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
598 _w95dkv * dkv;
599 int i;
601 /* first value block */
602 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
604 /* loop through the values */
605 for (i=0; i< dkh->values; i++) {
606 struct key_value value;
607 WCHAR *pdata;
609 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
610 value.type = dkv->type;
611 value.len = dkv->valdatalen;
613 value.data = &(dkv->name[dkv->valnamelen]);
614 pdata = NULL;
615 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
616 pdata = _strdupnAtoW(value.data,value.len);
617 value.len *= 2;
619 if (pdata != NULL) value.data = pdata;
621 _dump_value(&value,f);
622 free(value.nameW);
623 if (pdata != NULL) free(pdata);
625 /* next value */
626 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
628 return TRUE;
631 /******************************************************************************
632 * _w95_dump_dke [Internal]
634 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
636 _w95dkh * dkh;
637 LPSTR new_key_name = NULL;
639 /* special root key */
640 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
642 /* parse the one subkey */
643 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
644 /* has no sibling keys */
645 return FALSE;
648 /* search subblock */
649 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
650 ERR("dke pointing to missing dkh !\n");
651 return FALSE;
654 if (level <= 0) {
655 /* create new subkey name */
656 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
657 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
658 strncat(new_key_name,dkh->name,dkh->keynamelen);
660 /* walk sibling keys */
661 if (dke->next != 0xffffffff ) {
662 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
663 free(new_key_name);
664 return FALSE;
668 /* write the key path (something like [Software\\Microsoft\\..]) only if:
669 1) key has some values
670 2) key has no values and no subkeys
672 if (dkh->values > 0) {
673 /* there are some values */
674 fprintf(f,"\n[");
675 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
676 fprintf(f,"]\n");
677 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
678 free(new_key_name);
679 return FALSE;
682 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
683 /* no subkeys and no values */
684 fprintf(f,"\n[");
685 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
686 fprintf(f,"]\n");
688 } else new_key_name = _strdupnA(key_name,strlen(key_name));
690 /* next sub key */
691 if (dke->nextsub != 0xffffffff) {
692 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
693 free(new_key_name);
694 return FALSE;
698 free(new_key_name);
699 return TRUE;
701 /* end windows 95 loader */
703 /***********************************************************************************/
704 /* windows NT registry loader */
705 /***********************************************************************************/
707 /* NT REGISTRY LOADER */
709 #ifdef HAVE_SYS_MMAN_H
710 # include <sys/mman.h>
711 #endif
713 #ifndef MAP_FAILED
714 #define MAP_FAILED ((LPVOID)-1)
715 #endif
717 #define NT_REG_BLOCK_SIZE 0x1000
719 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
720 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
721 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
722 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
724 /* subblocks of nk */
725 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
726 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
727 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
729 #define NT_REG_KEY_BLOCK_TYPE 0x20
730 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
732 typedef struct {
733 DWORD id; /* 0x66676572 'regf'*/
734 DWORD uk1; /* 0x04 */
735 DWORD uk2; /* 0x08 */
736 FILETIME DateModified; /* 0x0c */
737 DWORD uk3; /* 0x14 */
738 DWORD uk4; /* 0x18 */
739 DWORD uk5; /* 0x1c */
740 DWORD uk6; /* 0x20 */
741 DWORD RootKeyBlock; /* 0x24 */
742 DWORD BlockSize; /* 0x28 */
743 DWORD uk7[116];
744 DWORD Checksum; /* at offset 0x1FC */
745 } nt_regf;
747 typedef struct {
748 DWORD blocksize;
749 BYTE data[1];
750 } nt_hbin_sub;
752 typedef struct {
753 DWORD id; /* 0x6E696268 'hbin' */
754 DWORD off_prev;
755 DWORD off_next;
756 DWORD uk1;
757 DWORD uk2; /* 0x10 */
758 DWORD uk3; /* 0x14 */
759 DWORD uk4; /* 0x18 */
760 DWORD size; /* 0x1C */
761 nt_hbin_sub hbin_sub; /* 0x20 */
762 } nt_hbin;
765 * the value_list consists of offsets to the values (vk)
767 typedef struct {
768 WORD SubBlockId; /* 0x00 0x6B6E */
769 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
770 FILETIME writetime; /* 0x04 */
771 DWORD uk1; /* 0x0C */
772 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
773 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
774 DWORD uk8; /* 0x18 */
775 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
776 DWORD uk2; /* 0x20 */
777 DWORD nr_values; /* 0x24 number of values */
778 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
779 DWORD off_sk; /* 0x2c Offset of the sk-Record */
780 DWORD off_class; /* 0x30 Offset of the Class-Name */
781 DWORD uk3; /* 0x34 */
782 DWORD uk4; /* 0x38 */
783 DWORD uk5; /* 0x3c */
784 DWORD uk6; /* 0x40 */
785 DWORD uk7; /* 0x44 */
786 WORD name_len; /* 0x48 name-length */
787 WORD class_len; /* 0x4a class-name length */
788 char name[1]; /* 0x4c key-name */
789 } nt_nk;
791 typedef struct {
792 DWORD off_nk; /* 0x00 */
793 DWORD name; /* 0x04 */
794 } hash_rec;
796 typedef struct {
797 WORD id; /* 0x00 0x666c */
798 WORD nr_keys; /* 0x06 */
799 hash_rec hash_rec[1];
800 } nt_lf;
803 list of subkeys without hash
805 li --+-->nk
807 +-->nk
809 typedef struct {
810 WORD id; /* 0x00 0x696c */
811 WORD nr_keys;
812 DWORD off_nk[1];
813 } nt_li;
816 this is a intermediate node
818 ri --+-->li--+-->nk
820 | +-->nk
822 +-->li--+-->nk
824 +-->nk
826 typedef struct {
827 WORD id; /* 0x00 0x6972 */
828 WORD nr_li; /* 0x02 number off offsets */
829 DWORD off_li[1]; /* 0x04 points to li */
830 } nt_ri;
832 typedef struct {
833 WORD id; /* 0x00 'vk' */
834 WORD nam_len;
835 DWORD data_len;
836 DWORD data_off;
837 DWORD type;
838 WORD flag;
839 WORD uk1;
840 char name[1];
841 } nt_vk;
844 * gets a value
846 * vk->flag:
847 * 0 value is a default value
848 * 1 the value has a name
850 * vk->data_len
851 * len of the whole data block
852 * - reg_sz (unicode)
853 * bytes including the terminating \0 = 2*(number_of_chars+1)
854 * - reg_dword, reg_binary:
855 * if highest bit of data_len is set data_off contains the value
857 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
859 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
860 struct key_value value;
862 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
863 ERR("unknown block found (0x%04x), please report!\n", vk->id);
864 return FALSE;
867 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
868 value.type = vk->type;
869 value.len = (vk->data_len & 0x7fffffff);
870 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
872 _dump_value(&value,f);
873 free(value.nameW);
875 return TRUE;
878 /* it's called from _nt_dump_lf() */
879 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
882 * get the subkeys
884 * this structure contains the hash of a keyname and points to all
885 * subkeys
887 * exception: if the id is 'il' there are no hash values and every
888 * dword is a offset
890 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
892 int i;
894 if (lf->id == NT_REG_HASH_BLOCK_ID) {
895 if (subkeys != lf->nr_keys) goto error1;
897 for (i=0; i<lf->nr_keys; i++)
898 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
899 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
900 nt_li * li = (nt_li*)lf;
901 if (subkeys != li->nr_keys) goto error1;
903 for (i=0; i<li->nr_keys; i++)
904 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
905 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
906 nt_ri * ri = (nt_ri*)lf;
907 int li_subkeys = 0;
909 /* count all subkeys */
910 for (i=0; i<ri->nr_li; i++) {
911 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
912 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
913 li_subkeys += li->nr_keys;
916 /* check number */
917 if (subkeys != li_subkeys) goto error1;
919 /* loop through the keys */
920 for (i=0; i<ri->nr_li; i++) {
921 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
922 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
924 } else goto error2;
926 return TRUE;
928 error2:
929 if (lf->id == 0x686c)
930 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
931 else
932 ERR("unknown node id 0x%04x, please report!\n", lf->id);
933 return TRUE;
935 error1:
936 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
937 return FALSE;
939 error:
940 ERR("error reading lf block\n");
941 return FALSE;
944 /* _nt_dump_nk [Internal] */
945 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
947 unsigned int n;
948 DWORD *vl;
949 LPSTR new_key_name = NULL;
951 TRACE("%s\n", key_name);
953 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
954 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
955 return FALSE;
958 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
959 ERR("registry file corrupt!\n");
960 return FALSE;
963 /* create the new key */
964 if (level <= 0) {
965 /* create new subkey name */
966 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
967 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
968 strncat(new_key_name,nk->name,nk->name_len);
970 /* write the key path (something like [Software\\Microsoft\\..]) only if:
971 1) key has some values
972 2) key has no values and no subkeys
974 if (nk->nr_values > 0) {
975 /* there are some values */
976 fprintf(f,"\n[");
977 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
978 fprintf(f,"]\n");
980 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
981 /* no subkeys and no values */
982 fprintf(f,"\n[");
983 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
984 fprintf(f,"]\n");
987 /* loop trough the value list */
988 vl = (DWORD *)(base+nk->valuelist_off+4);
989 for (n=0; n<nk->nr_values; n++) {
990 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
991 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
992 free(new_key_name);
993 return FALSE;
996 } else new_key_name = _strdupnA(key_name,strlen(key_name));
998 /* loop through the subkeys */
999 if (nk->nr_subkeys) {
1000 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1001 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1002 free(new_key_name);
1003 return FALSE;
1007 free(new_key_name);
1008 return TRUE;
1011 /* end nt loader */
1013 /**********************************************************************************
1014 * _set_registry_levels [Internal]
1016 * set level to 0 for loading system files
1017 * set level to 1 for loading user files
1019 static void _set_registry_levels(int level,int saving,int period)
1021 SERVER_START_REQ( set_registry_levels )
1023 req->current = level;
1024 req->saving = saving;
1025 req->period = period;
1026 wine_server_call( req );
1028 SERVER_END_REQ;
1031 /* _save_at_exit [Internal] */
1032 static void _save_at_exit(HKEY hkey,LPCSTR path)
1034 LPCSTR confdir = wine_get_config_dir();
1036 SERVER_START_REQ( save_registry_atexit )
1038 req->hkey = hkey;
1039 wine_server_add_data( req, confdir, strlen(confdir) );
1040 wine_server_add_data( req, path, strlen(path)+1 );
1041 wine_server_call( req );
1043 SERVER_END_REQ;
1046 /* configure save files and start the periodic saving timer [Internal] */
1047 static void _init_registry_saving( HKEY hkey_users_default )
1049 int all;
1050 int period = 0;
1051 char buffer[20];
1053 all = !PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1054 PROFILE_GetWineIniString( "registry", "PeriodicSave", "", buffer, sizeof(buffer) );
1055 if (buffer[0]) period = atoi(buffer);
1057 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1058 _set_registry_levels(1,!all,period*1000);
1060 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1062 _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1063 _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1064 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1069 /******************************************************************************
1070 * _allocate_default_keys [Internal]
1071 * Registry initialisation, allocates some default keys.
1073 static void _allocate_default_keys(void) {
1074 HKEY hkey;
1075 char buf[200];
1077 TRACE("(void)\n");
1079 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1080 RegCloseKey(hkey);
1082 /* This was an Open, but since it is called before the real registries
1083 are loaded, it was changed to a Create - MTB 980507*/
1084 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1085 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1086 RegCloseKey(hkey);
1088 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1089 * CurrentVersion
1090 * CurrentBuildNumber
1091 * CurrentType
1092 * string RegisteredOwner
1093 * string RegisteredOrganization
1096 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1097 * string SysContact
1098 * string SysLocation
1099 * SysServices
1101 if (-1!=gethostname(buf,200)) {
1102 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1103 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1104 RegCloseKey(hkey);
1107 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1108 RegCloseKey(hkey);
1111 #define REG_DONTLOAD -1
1112 #define REG_WIN31 0
1113 #define REG_WIN95 1
1114 #define REG_WINNT 2
1116 /* return the type of native registry [Internal] */
1117 static int _get_reg_type(void)
1119 char windir[MAX_PATHNAME_LEN];
1120 char tmp[MAX_PATHNAME_LEN];
1121 int ret = REG_WIN31;
1123 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1125 /* test %windir%/system32/config/system --> winnt */
1126 strcpy(tmp, windir);
1127 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1128 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1129 ret = REG_WINNT;
1131 else
1133 /* test %windir%/system.dat --> win95 */
1134 strcpy(tmp, windir);
1135 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1136 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1137 ret = REG_WIN95;
1141 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1142 MESSAGE("When you are running with a native NT directory specify\n");
1143 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1144 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1145 ret = REG_DONTLOAD;
1148 return ret;
1151 #define WINE_REG_VER_ERROR -1
1152 #define WINE_REG_VER_1 0
1153 #define WINE_REG_VER_2 1
1154 #define WINE_REG_VER_OLD 2
1155 #define WINE_REG_VER_UNKNOWN 3
1157 /* return the version of wine registry file [Internal] */
1158 static int _get_wine_registry_file_format_version(LPCSTR fn)
1160 FILE *f;
1161 char tmp[50];
1162 int ver;
1164 if ((f=fopen(fn,"rt")) == NULL) {
1165 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1166 return WINE_REG_VER_ERROR;
1169 if (fgets(tmp,50,f) == NULL) {
1170 WARN("Error reading %s: %s\n",fn,strerror(errno));
1171 fclose(f);
1172 return WINE_REG_VER_ERROR;
1174 fclose(f);
1176 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1177 switch (ver) {
1178 case 1:
1179 return WINE_REG_VER_1;
1180 break;
1181 case 2:
1182 return WINE_REG_VER_2;
1183 break;
1184 default:
1185 return WINE_REG_VER_UNKNOWN;
1189 /* load the registry file in wine format [Internal] */
1190 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1192 int file_format;
1194 file_format = _get_wine_registry_file_format_version(fn);
1195 switch (file_format) {
1197 case WINE_REG_VER_1:
1198 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1199 break;
1201 case WINE_REG_VER_2: {
1202 HANDLE file;
1203 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1204 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1206 SERVER_START_REQ( load_registry )
1208 req->hkey = hkey;
1209 req->file = file;
1210 wine_server_call( req );
1212 SERVER_END_REQ;
1213 CloseHandle( file );
1215 break;
1218 case WINE_REG_VER_UNKNOWN:
1219 WARN("Unable to load registry file %s: unknown format.\n",fn);
1220 break;
1222 case WINE_REG_VER_ERROR:
1223 break;
1227 /* generate and return the name of the tmp file and associated stream [Internal] */
1228 static LPSTR _get_tmp_fn(FILE **f)
1230 LPSTR ret;
1231 int tmp_fd,count;
1233 ret = _xmalloc(50);
1234 for (count = 0;;) {
1235 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1236 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1237 if (errno != EEXIST) {
1238 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1239 free(ret);
1240 *f = NULL;
1241 return NULL;
1245 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1246 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1247 close(tmp_fd);
1248 free(ret);
1249 return NULL;
1252 return ret;
1255 /* convert win95 native registry file to wine format [Internal] */
1256 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1258 int fd;
1259 FILE *f;
1260 DOS_FULL_NAME full_name;
1261 void *base;
1262 LPSTR ret = NULL;
1263 struct stat st;
1265 _w95creg *creg;
1266 _w95rgkn *rgkn;
1267 _w95dke *dke, *root_dke;
1269 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1271 /* map the registry into the memory */
1272 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1273 if ((fstat(fd, &st) == -1)) goto error1;
1274 if (!st.st_size) goto error1;
1275 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1277 /* control signature */
1278 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1279 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1280 goto error;
1283 creg = base;
1284 /* load the header (rgkn) */
1285 rgkn = (_w95rgkn*)(creg + 1);
1286 if (rgkn->id != W95_REG_RGKN_ID) {
1287 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1288 goto error;
1290 if (rgkn->root_off != 0x20) {
1291 ERR("rgkn->root_off not 0x20, please report !\n");
1292 goto error;
1294 if (rgkn->last_dke > rgkn->size)
1296 ERR("registry file corrupt! last_dke > size!\n");
1297 goto error;
1299 /* verify last dke */
1300 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1301 if (dke->x1 != 0x80000000)
1302 { /* wrong magic */
1303 ERR("last dke invalid !\n");
1304 goto error;
1306 if (rgkn->size > creg->rgdb_off)
1308 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1309 goto error;
1311 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1312 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1314 ERR("registry file corrupt! invalid root dke !\n");
1315 goto error;
1318 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1319 fprintf(f,"WINE REGISTRY Version 2");
1320 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1321 fclose(f);
1323 error:
1324 if(ret == NULL) {
1325 ERR("Unable to load native win95 registry file %s.\n",fn);
1326 ERR("Please report this.\n");
1327 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1330 munmap(base, st.st_size);
1331 error1:
1332 close(fd);
1333 return ret;
1336 /* convert winnt native registry file to wine format [Internal] */
1337 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1339 FILE *f;
1340 void *base;
1341 LPSTR ret = NULL;
1342 HANDLE hFile;
1343 HANDLE hMapping;
1345 nt_regf *regf;
1346 nt_hbin *hbin;
1347 nt_hbin_sub *hbin_sub;
1348 nt_nk *nk;
1350 TRACE("%s\n", fn);
1352 hFile = CreateFileA( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1353 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1354 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1355 if (!hMapping) goto error1;
1356 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1357 CloseHandle( hMapping );
1358 if (!base) goto error1;
1360 /* control signature */
1361 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1362 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1363 goto error;
1366 /* start block */
1367 regf = base;
1369 /* hbin block */
1370 hbin = (nt_hbin*)((char*) base + 0x1000);
1371 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1372 ERR( "hbin block invalid\n");
1373 goto error;
1376 /* hbin_sub block */
1377 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1378 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1379 ERR( "hbin_sub block invalid\n");
1380 goto error;
1383 /* nk block */
1384 nk = (nt_nk*)&(hbin_sub->data[0]);
1385 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1386 ERR( "special nk block not found\n");
1387 goto error;
1390 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1391 fprintf(f,"WINE REGISTRY Version 2");
1392 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1393 fclose(f);
1395 error:
1396 UnmapViewOfFile( base );
1397 error1:
1398 CloseHandle(hFile);
1399 return ret;
1402 /* convert native registry to wine format and load it via server call [Internal] */
1403 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1405 LPSTR tmp = NULL;
1407 switch (reg_type) {
1408 case REG_WINNT:
1409 /* FIXME: following function doesn't really convert yet */
1410 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1411 break;
1412 case REG_WIN95:
1413 tmp = _convert_win95_registry_to_wine_format(fn,level);
1414 break;
1415 case REG_WIN31:
1416 ERR("Don't know how to convert native 3.1 registry yet.\n");
1417 break;
1418 default:
1419 ERR("Unknown registry format parameter (%d)\n",reg_type);
1420 break;
1423 if (tmp != NULL) {
1424 load_wine_registry(hkey,tmp);
1425 TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp);
1426 unlink(tmp);
1428 else WARN("Unable to convert %s (doesn't exist?)\n",fn);
1429 free(tmp);
1432 /* load all native windows registry files [Internal] */
1433 static void _load_windows_registry( HKEY hkey_users_default )
1435 int reg_type;
1436 char windir[MAX_PATHNAME_LEN];
1437 char path[MAX_PATHNAME_LEN];
1439 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1441 reg_type = _get_reg_type();
1442 switch (reg_type) {
1443 case REG_WINNT: {
1444 HKEY hkey;
1446 /* user specific ntuser.dat */
1447 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1448 strcat(path,"\\ntuser.dat");
1449 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1452 /* default user.dat */
1453 if (hkey_users_default) {
1454 strcpy(path,windir);
1455 strcat(path,"\\system32\\config\\default");
1456 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1460 * FIXME
1461 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1464 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1465 strcpy(path,windir);
1466 strcat(path,"\\system32\\config\\system");
1467 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1468 RegCloseKey(hkey);
1471 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1472 strcpy(path,windir);
1473 strcat(path,"\\system32\\config\\software");
1474 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1475 RegCloseKey(hkey);
1478 strcpy(path,windir);
1479 strcat(path,"\\system32\\config\\sam");
1480 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1482 strcpy(path,windir);
1483 strcat(path,"\\system32\\config\\security");
1484 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1486 /* this key is generated when the nt-core booted successfully */
1487 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1488 break;
1491 case REG_WIN95:
1492 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1494 strcpy(path,windir);
1495 strcat(path,"\\system.dat");
1496 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1498 strcpy(path,windir);
1499 strcat(path,"\\classes.dat");
1500 _convert_and_load_native_registry(path,HKEY_CLASSES_ROOT,REG_WIN95,0);
1502 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1503 /* user specific user.dat */
1504 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1505 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1507 /* default user.dat */
1508 if (hkey_users_default) {
1509 strcpy(path,windir);
1510 strcat(path,"\\user.dat");
1511 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1513 } else {
1514 strcpy(path,windir);
1515 strcat(path,"\\user.dat");
1516 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1518 break;
1520 case REG_WIN31:
1521 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1522 _w31_loadreg();
1523 break;
1525 case REG_DONTLOAD:
1526 TRACE("REG_DONTLOAD\n");
1527 break;
1529 default:
1530 ERR("switch: no match (%d)\n",reg_type);
1531 break;
1536 /* load global registry files (stored in /etc/wine) [Internal] */
1537 static void _load_global_registry(void)
1539 TRACE("(void)\n");
1541 /* Load the global HKU hive directly from sysconfdir */
1542 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1544 /* Load the global machine defaults directly from sysconfdir */
1545 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1548 /* load home registry files (stored in ~/.wine) [Internal] */
1549 static void _load_home_registry( HKEY hkey_users_default )
1551 LPCSTR confdir = wine_get_config_dir();
1552 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1554 strcpy(tmp,confdir);
1555 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1556 load_wine_registry(hkey_users_default,tmp);
1558 strcpy(tmp,confdir);
1559 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1560 load_wine_registry(HKEY_CURRENT_USER,tmp);
1562 strcpy(tmp,confdir);
1563 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1564 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1566 free(tmp);
1569 /* load all registry (native and global and home) */
1570 void SHELL_LoadRegistry( void )
1572 HKEY hkey_users_default;
1574 TRACE("(void)\n");
1576 if (!CLIENT_IsBootThread()) return; /* already loaded */
1578 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1580 ERR("Cannot create HKEY_USERS/.Default\n" );
1581 ExitProcess(1);
1584 _allocate_default_keys();
1585 _set_registry_levels(0,0,0);
1586 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1587 _load_windows_registry( hkey_users_default );
1588 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1589 _load_global_registry();
1590 _set_registry_levels(1,0,0);
1591 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1592 _load_home_registry( hkey_users_default );
1593 _init_registry_saving( hkey_users_default );
1594 RegCloseKey(hkey_users_default);
1597 /***************************************************************************/
1598 /* API FUNCTIONS */
1599 /***************************************************************************/
1601 /******************************************************************************
1602 * RegFlushKey [ADVAPI32.@]
1603 * Immediately writes key to registry.
1604 * Only returns after data has been written to disk.
1606 * FIXME: does it really wait until data is written ?
1608 * PARAMS
1609 * hkey [I] Handle of key to write
1611 * RETURNS
1612 * Success: ERROR_SUCCESS
1613 * Failure: Error code
1615 DWORD WINAPI RegFlushKey( HKEY hkey )
1617 FIXME( "(%x): stub\n", hkey );
1618 return ERROR_SUCCESS;
1622 /******************************************************************************
1623 * RegUnLoadKeyA [ADVAPI32.@]
1625 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1627 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1628 return ERROR_SUCCESS;
1632 /******************************************************************************
1633 * RegReplaceKeyA [ADVAPI32.@]
1635 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1636 LPCSTR lpOldFile )
1638 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1639 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1640 return ERROR_SUCCESS;
1648 /* 16-bit functions */
1650 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1651 * some programs. Do not remove those cases. -MM
1653 static inline void fix_win16_hkey( HKEY *hkey )
1655 if (*hkey == 0 || *hkey == (HKEY)1) *hkey = HKEY_CLASSES_ROOT;
1658 /******************************************************************************
1659 * RegEnumKey [KERNEL.216]
1660 * RegEnumKey [SHELL.7]
1662 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1664 fix_win16_hkey( &hkey );
1665 return RegEnumKeyA( hkey, index, name, name_len );
1668 /******************************************************************************
1669 * RegOpenKey [KERNEL.217]
1670 * RegOpenKey [SHELL.1]
1672 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1674 fix_win16_hkey( &hkey );
1675 return RegOpenKeyA( hkey, name, retkey );
1678 /******************************************************************************
1679 * RegCreateKey [KERNEL.218]
1680 * RegCreateKey [SHELL.2]
1682 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1684 fix_win16_hkey( &hkey );
1685 return RegCreateKeyA( hkey, name, retkey );
1688 /******************************************************************************
1689 * RegDeleteKey [KERNEL.219]
1690 * RegDeleteKey [SHELL.4]
1692 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1694 fix_win16_hkey( &hkey );
1695 return RegDeleteKeyA( hkey, name );
1698 /******************************************************************************
1699 * RegCloseKey [KERNEL.220]
1700 * RegCloseKey [SHELL.3]
1702 DWORD WINAPI RegCloseKey16( HKEY hkey )
1704 fix_win16_hkey( &hkey );
1705 return RegCloseKey( hkey );
1708 /******************************************************************************
1709 * RegSetValue [KERNEL.221]
1710 * RegSetValue [SHELL.5]
1712 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1714 fix_win16_hkey( &hkey );
1715 return RegSetValueA( hkey, name, type, data, count );
1718 /******************************************************************************
1719 * RegDeleteValue [KERNEL.222]
1721 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1723 fix_win16_hkey( &hkey );
1724 return RegDeleteValueA( hkey, name );
1727 /******************************************************************************
1728 * RegEnumValue [KERNEL.223]
1730 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1731 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1733 fix_win16_hkey( &hkey );
1734 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1737 /******************************************************************************
1738 * RegQueryValue [KERNEL.224]
1739 * RegQueryValue [SHELL.6]
1741 * NOTES
1742 * Is this HACK still applicable?
1744 * HACK
1745 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1746 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1747 * Aldus FH4)
1749 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1751 fix_win16_hkey( &hkey );
1752 if (count) *count &= 0xffff;
1753 return RegQueryValueA( hkey, name, data, count );
1756 /******************************************************************************
1757 * RegQueryValueEx [KERNEL.225]
1759 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1760 LPBYTE data, LPDWORD count )
1762 fix_win16_hkey( &hkey );
1763 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1766 /******************************************************************************
1767 * RegSetValueEx [KERNEL.226]
1769 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1770 CONST BYTE *data, DWORD count )
1772 fix_win16_hkey( &hkey );
1773 if (!count && (type==REG_SZ)) count = strlen(data);
1774 return RegSetValueExA( hkey, name, reserved, type, data, count );
1777 /******************************************************************************
1778 * RegFlushKey [KERNEL.227]
1780 DWORD WINAPI RegFlushKey16( HKEY hkey )
1782 fix_win16_hkey( &hkey );
1783 return RegFlushKey( hkey );