Save a disk file's drive type in the server object.
[wine/multimedia.git] / misc / registry.c
blob818cd6567f80f18ce21612d7fe7ac78de08eef6d
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 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
36 #include "winerror.h"
37 #include "winnt.h"
38 #include "winreg.h"
40 #include "wine/winbase16.h"
41 #include "file.h"
42 #include "heap.h"
43 #include "options.h"
44 #include "wine/server.h"
46 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(reg);
50 /* FIXME: following defines should be configured global */
51 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
52 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
54 /* relative in ~user/.wine/ : */
55 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
56 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
57 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
59 /* _xmalloc [Internal] */
60 static void *_xmalloc( size_t size )
62 void *res;
64 res = malloc (size ? size : 1);
65 if (res == NULL) {
66 WARN("Virtual memory exhausted.\n");
67 exit (1);
69 return res;
72 /* _strdupnA [Internal] */
73 static LPSTR _strdupnA(LPCSTR str,size_t len)
75 LPSTR ret;
77 if (!str) return NULL;
78 ret = _xmalloc( len + 1 );
79 memcpy( ret, str, len );
80 ret[len] = 0x00;
81 return ret;
84 /* convert ansi string to unicode [Internal] */
85 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
87 LPWSTR ret;
88 size_t lenW;
90 if (!strA) return NULL;
91 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
92 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
93 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
94 ret[lenW] = 0;
95 return ret;
98 /* dump a Unicode string with proper escaping [Internal] */
99 /* FIXME: this code duplicates server/unicode.c */
100 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
102 static const char escapes[32] = ".......abtnvfr.............e....";
103 char buffer[256];
104 LPSTR pos = buffer;
105 int count = 0;
107 for (; len; str++, len--)
109 if (pos > buffer + sizeof(buffer) - 8)
111 fwrite( buffer, pos - buffer, 1, f );
112 count += pos - buffer;
113 pos = buffer;
115 if (*str > 127) /* hex escape */
117 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
118 pos += sprintf( pos, "\\x%04x", *str );
119 else
120 pos += sprintf( pos, "\\x%x", *str );
121 continue;
123 if (*str < 32) /* octal or C escape */
125 if (!*str && len == 1) continue; /* do not output terminating NULL */
126 if (escapes[*str] != '.')
127 pos += sprintf( pos, "\\%c", escapes[*str] );
128 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
129 pos += sprintf( pos, "\\%03o", *str );
130 else
131 pos += sprintf( pos, "\\%o", *str );
132 continue;
134 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
135 *pos++ = *str;
137 fwrite( buffer, pos - buffer, 1, f );
138 count += pos - buffer;
139 return count;
142 /* convert ansi string to unicode and dump with proper escaping [Internal] */
143 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
145 WCHAR *strW;
146 int ret;
148 if (strA == NULL) return 0;
149 strW = _strdupnAtoW(strA,len);
150 ret = _dump_strW(strW,len,f,escape);
151 free(strW);
152 return ret;
155 /* a key value */
156 /* FIXME: this code duplicates server/registry.c */
157 struct key_value {
158 WCHAR *nameW; /* value name */
159 int type; /* value type */
160 size_t len; /* value data length in bytes */
161 void *data; /* pointer to value data */
164 /* dump a value to a text file */
165 /* FIXME: this code duplicates server/registry.c */
166 static void _dump_value(struct key_value *value,FILE *f)
168 int i, count;
170 if (value->nameW[0]) {
171 fputc( '\"', f );
172 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
173 count += fprintf( f, "\"=" );
175 else count = fprintf( f, "@=" );
177 switch(value->type) {
178 case REG_SZ:
179 case REG_EXPAND_SZ:
180 case REG_MULTI_SZ:
181 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
182 fputc( '\"', f );
183 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
184 fputc( '\"', f );
185 break;
186 case REG_DWORD:
187 if (value->len == sizeof(DWORD)) {
188 DWORD dw;
189 memcpy( &dw, value->data, sizeof(DWORD) );
190 fprintf( f, "dword:%08lx", dw );
191 break;
193 /* else fall through */
194 default:
195 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
196 else count += fprintf( f, "hex(%x):", value->type );
197 for (i = 0; i < value->len; i++) {
198 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
199 if (i < value->len-1) {
200 fputc( ',', f );
201 if (++count > 76) {
202 fprintf( f, "\\\n " );
203 count = 2;
207 break;
209 fputc( '\n', f );
212 /******************************************************************/
213 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
215 reghack - windows 3.11 registry data format demo program.
217 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
218 a combined hash table and tree description, and finally a text table.
220 The header is obvious from the struct header. The taboff1 and taboff2
221 fields are always 0x20, and their usage is unknown.
223 The 8-byte entry table has various entry types.
225 tabent[0] is a root index. The second word has the index of the root of
226 the directory.
227 tabent[1..hashsize] is a hash table. The first word in the hash entry is
228 the index of the key/value that has that hash. Data with the same
229 hash value are on a circular list. The other three words in the
230 hash entry are always zero.
231 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
232 entry: dirent and keyent/valent. They are identified by context.
233 tabent[freeidx] is the first free entry. The first word in a free entry
234 is the index of the next free entry. The last has 0 as a link.
235 The other three words in the free list are probably irrelevant.
237 Entries in text table are preceded by a word at offset-2. This word
238 has the value (2*index)+1, where index is the referring keyent/valent
239 entry in the table. I have no suggestion for the 2* and the +1.
240 Following the word, there are N bytes of data, as per the keyent/valent
241 entry length. The offset of the keyent/valent entry is from the start
242 of the text table to the first data byte.
244 This information is not available from Microsoft. The data format is
245 deduced from the reg.dat file by me. Mistakes may
246 have been made. I claim no rights and give no guarantees for this program.
248 Tor Sjøwall, tor@sn.no
251 /* reg.dat header format */
252 struct _w31_header {
253 char cookie[8]; /* 'SHCC3.10' */
254 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
255 unsigned long taboff2; /* offset of index table (??) = 0x20 */
256 unsigned long tabcnt; /* number of entries in index table */
257 unsigned long textoff; /* offset of text part */
258 unsigned long textsize; /* byte size of text part */
259 unsigned short hashsize; /* hash size */
260 unsigned short freeidx; /* free index */
263 /* generic format of table entries */
264 struct _w31_tabent {
265 unsigned short w0, w1, w2, w3;
268 /* directory tabent: */
269 struct _w31_dirent {
270 unsigned short sibling_idx; /* table index of sibling dirent */
271 unsigned short child_idx; /* table index of child dirent */
272 unsigned short key_idx; /* table index of key keyent */
273 unsigned short value_idx; /* table index of value valent */
276 /* key tabent: */
277 struct _w31_keyent {
278 unsigned short hash_idx; /* hash chain index for string */
279 unsigned short refcnt; /* reference count */
280 unsigned short length; /* length of string */
281 unsigned short string_off; /* offset of string in text table */
284 /* value tabent: */
285 struct _w31_valent {
286 unsigned short hash_idx; /* hash chain index for string */
287 unsigned short refcnt; /* reference count */
288 unsigned short length; /* length of string */
289 unsigned short string_off; /* offset of string in text table */
292 /* recursive helper function to display a directory tree [Internal] */
293 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
295 struct _w31_dirent *dir;
296 struct _w31_keyent *key;
297 struct _w31_valent *val;
298 HKEY subkey = 0;
299 static char tail[400];
301 while (idx!=0) {
302 dir=(struct _w31_dirent*)&tab[idx];
304 if (dir->key_idx) {
305 key = (struct _w31_keyent*)&tab[dir->key_idx];
307 memcpy(tail,&txt[key->string_off],key->length);
308 tail[key->length]='\0';
309 /* all toplevel entries AND the entries in the
310 * toplevel subdirectory belong to \SOFTWARE\Classes
312 if (!level && !strcmp(tail,".classes")) {
313 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
314 idx=dir->sibling_idx;
315 continue;
317 if (subkey) RegCloseKey( subkey );
318 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
319 /* only add if leaf node or valued node */
320 if (dir->value_idx!=0||dir->child_idx==0) {
321 if (dir->value_idx) {
322 val=(struct _w31_valent*)&tab[dir->value_idx];
323 memcpy(tail,&txt[val->string_off],val->length);
324 tail[val->length]='\0';
325 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
328 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
329 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
330 idx=dir->sibling_idx;
332 if (subkey) RegCloseKey( subkey );
336 /******************************************************************************
337 * _w31_loadreg [Internal]
339 void _w31_loadreg(void)
341 HFILE hf;
342 struct _w31_header head;
343 struct _w31_tabent *tab;
344 unsigned char *txt;
345 unsigned int len;
346 OFSTRUCT ofs;
347 BY_HANDLE_FILE_INFORMATION hfinfo;
348 time_t lastmodified;
350 TRACE("(void)\n");
352 hf = OpenFile("reg.dat",&ofs,OF_READ);
353 if (hf==HFILE_ERROR) return;
355 /* read & dump header */
356 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
357 ERR("reg.dat is too short.\n");
358 _lclose(hf);
359 return;
361 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
362 ERR("reg.dat has bad signature.\n");
363 _lclose(hf);
364 return;
367 len = head.tabcnt * sizeof(struct _w31_tabent);
368 /* read and dump index table */
369 tab = _xmalloc(len);
370 if (len!=_lread(hf,tab,len)) {
371 ERR("couldn't read %d bytes.\n",len);
372 free(tab);
373 _lclose(hf);
374 return;
377 /* read text */
378 txt = _xmalloc(head.textsize);
379 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
380 ERR("couldn't seek to textblock.\n");
381 free(tab);
382 free(txt);
383 _lclose(hf);
384 return;
386 if (head.textsize!=_lread(hf,txt,head.textsize)) {
387 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
388 free(tab);
389 free(txt);
390 _lclose(hf);
391 return;
394 if (!GetFileInformationByHandle(hf,&hfinfo)) {
395 ERR("GetFileInformationByHandle failed?.\n");
396 free(tab);
397 free(txt);
398 _lclose(hf);
399 return;
401 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
402 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
403 free(tab);
404 free(txt);
405 _lclose(hf);
406 return;
409 /***********************************************************************************/
410 /* windows 95 registry loader */
411 /***********************************************************************************/
413 /* SECTION 1: main header
415 * once at offset 0
417 #define W95_REG_CREG_ID 0x47455243
419 typedef struct {
420 DWORD id; /* "CREG" = W95_REG_CREG_ID */
421 DWORD version; /* ???? 0x00010000 */
422 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
423 DWORD uk2; /* 0x0c */
424 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
425 WORD uk3;
426 DWORD uk[3];
427 /* rgkn */
428 } _w95creg;
430 /* SECTION 2: Directory information (tree structure)
432 * once on offset 0x20
434 * structure: [rgkn][dke]* (repeat till last_dke is reached)
436 #define W95_REG_RGKN_ID 0x4e4b4752
438 typedef struct {
439 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
440 DWORD size; /* Size of the RGKN-block */
441 DWORD root_off; /* Rel. Offset of the root-record */
442 DWORD last_dke; /* Offset to last DKE ? */
443 DWORD uk[4];
444 } _w95rgkn;
446 /* Disk Key Entry Structure
448 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
449 * hive itself. It looks the same like other keys. Even the ID-number can
450 * be any value.
452 * The "hash"-value is a value representing the key's name. Windows will not
453 * search for the name, but for a matching hash-value. if it finds one, it
454 * will compare the actual string info, otherwise continue with the next key.
455 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
456 * of the string which are smaller than 0x80 (128) to this D-Word.
458 * If you want to modify key names, also modify the hash-values, since they
459 * cannot be found again (although they would be displayed in REGEDIT)
460 * End of list-pointers are filled with 0xFFFFFFFF
462 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
463 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
464 * structure) and reading another RGDB_section.
466 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
467 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
468 * The remaining space between last_dke and the offset calculated from
469 * rgkn->size seems to be free for use for more dke:s.
470 * So it seems if more dke:s are added, they are added to that space and
471 * last_dke is grown, and in case that "free" space is out, the space
472 * gets grown and rgkn->size gets adjusted.
474 * there is a one to one relationship between dke and dkh
476 /* key struct, once per key */
477 typedef struct {
478 DWORD x1; /* Free entry indicator(?) */
479 DWORD hash; /* sum of bytes of keyname */
480 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
481 DWORD prevlvl; /* offset of previous key */
482 DWORD nextsub; /* offset of child key */
483 DWORD next; /* offset of sibling key */
484 WORD nrLS; /* id inside the rgdb block */
485 WORD nrMS; /* number of the rgdb block */
486 } _w95dke;
488 /* SECTION 3: key information, values and data
490 * structure:
491 * section: [blocks]* (repeat creg->rgdb_num times)
492 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
493 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
495 * An interesting relationship exists in RGDB_section. The DWORD value
496 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
497 * I have no idea at the moment what this means. (Kevin Cozens)
500 /* block header, once per block */
501 #define W95_REG_RGDB_ID 0x42444752
503 typedef struct {
504 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
505 DWORD size; /* 0x04 */
506 DWORD uk1; /* 0x08 */
507 DWORD uk2; /* 0x0c */
508 DWORD uk3; /* 0x10 */
509 DWORD uk4; /* 0x14 */
510 DWORD uk5; /* 0x18 */
511 DWORD uk6; /* 0x1c */
512 /* dkh */
513 } _w95rgdb;
515 /* Disk Key Header structure (RGDB part), once per key */
516 typedef struct {
517 DWORD nextkeyoff; /* 0x00 offset to next dkh */
518 WORD nrLS; /* 0x04 id inside the rgdb block */
519 WORD nrMS; /* 0x06 number of the rgdb block */
520 DWORD bytesused; /* 0x08 */
521 WORD keynamelen; /* 0x0c len of name */
522 WORD values; /* 0x0e number of values */
523 DWORD xx1; /* 0x10 */
524 char name[1]; /* 0x14 */
525 /* dkv */ /* 0x14 + keynamelen */
526 } _w95dkh;
528 /* Disk Key Value structure, once per value */
529 typedef struct {
530 DWORD type; /* 0x00 */
531 DWORD x1; /* 0x04 */
532 WORD valnamelen; /* 0x08 length of name, 0 is default key */
533 WORD valdatalen; /* 0x0A length of data */
534 char name[1]; /* 0x0c */
535 /* raw data */ /* 0x0c + valnamelen */
536 } _w95dkv;
538 /******************************************************************************
539 * _w95_lookup_dkh [Internal]
541 * seeks the dkh belonging to a dke
543 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
545 _w95rgdb * rgdb;
546 _w95dkh * dkh;
547 int i;
549 /* get the beginning of the rgdb datastore */
550 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
552 /* check: requested block < last_block) */
553 if (creg->rgdb_num <= nrMS) {
554 ERR("registry file corrupt! requested block no. beyond end.\n");
555 goto error;
558 /* find the right block */
559 for(i=0; i<nrMS ;i++) {
560 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
561 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
562 goto error;
564 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
567 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
569 do {
570 if(nrLS==dkh->nrLS ) return dkh;
571 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
572 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
574 error:
575 return NULL;
578 /******************************************************************************
579 * _w95_dump_dkv [Internal]
581 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
583 _w95dkv * dkv;
584 int i;
586 /* first value block */
587 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
589 /* loop through the values */
590 for (i=0; i< dkh->values; i++) {
591 struct key_value value;
592 WCHAR *pdata;
594 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
595 value.type = dkv->type;
596 value.len = dkv->valdatalen;
598 value.data = &(dkv->name[dkv->valnamelen]);
599 pdata = NULL;
600 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
601 pdata = _strdupnAtoW(value.data,value.len);
602 value.len *= 2;
604 if (pdata != NULL) value.data = pdata;
606 _dump_value(&value,f);
607 free(value.nameW);
608 if (pdata != NULL) free(pdata);
610 /* next value */
611 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
613 return TRUE;
616 /******************************************************************************
617 * _w95_dump_dke [Internal]
619 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
621 _w95dkh * dkh;
622 LPSTR new_key_name = NULL;
624 /* special root key */
625 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
627 /* parse the one subkey */
628 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
629 /* has no sibling keys */
630 return FALSE;
633 /* search subblock */
634 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
635 ERR("dke pointing to missing dkh !\n");
636 return FALSE;
639 if (level <= 0) {
640 /* create new subkey name */
641 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
642 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
643 strncat(new_key_name,dkh->name,dkh->keynamelen);
645 /* walk sibling keys */
646 if (dke->next != 0xffffffff ) {
647 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
648 free(new_key_name);
649 return FALSE;
653 /* write the key path (something like [Software\\Microsoft\\..]) only if:
654 1) key has some values
655 2) key has no values and no subkeys
657 if (dkh->values > 0) {
658 /* there are some values */
659 fprintf(f,"\n[");
660 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
661 fprintf(f,"]\n");
662 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
663 free(new_key_name);
664 return FALSE;
667 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
668 /* no subkeys and no values */
669 fprintf(f,"\n[");
670 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
671 fprintf(f,"]\n");
673 } else new_key_name = _strdupnA(key_name,strlen(key_name));
675 /* next sub key */
676 if (dke->nextsub != 0xffffffff) {
677 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
678 free(new_key_name);
679 return FALSE;
683 free(new_key_name);
684 return TRUE;
686 /* end windows 95 loader */
688 /***********************************************************************************/
689 /* windows NT registry loader */
690 /***********************************************************************************/
692 /* NT REGISTRY LOADER */
694 #ifdef HAVE_SYS_MMAN_H
695 # include <sys/mman.h>
696 #endif
698 #ifndef MAP_FAILED
699 #define MAP_FAILED ((LPVOID)-1)
700 #endif
702 #define NT_REG_BLOCK_SIZE 0x1000
704 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
705 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
706 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
707 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
709 /* subblocks of nk */
710 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
711 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
712 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
714 #define NT_REG_KEY_BLOCK_TYPE 0x20
715 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
717 typedef struct {
718 DWORD id; /* 0x66676572 'regf'*/
719 DWORD uk1; /* 0x04 */
720 DWORD uk2; /* 0x08 */
721 FILETIME DateModified; /* 0x0c */
722 DWORD uk3; /* 0x14 */
723 DWORD uk4; /* 0x18 */
724 DWORD uk5; /* 0x1c */
725 DWORD uk6; /* 0x20 */
726 DWORD RootKeyBlock; /* 0x24 */
727 DWORD BlockSize; /* 0x28 */
728 DWORD uk7[116];
729 DWORD Checksum; /* at offset 0x1FC */
730 } nt_regf;
732 typedef struct {
733 DWORD blocksize;
734 BYTE data[1];
735 } nt_hbin_sub;
737 typedef struct {
738 DWORD id; /* 0x6E696268 'hbin' */
739 DWORD off_prev;
740 DWORD off_next;
741 DWORD uk1;
742 DWORD uk2; /* 0x10 */
743 DWORD uk3; /* 0x14 */
744 DWORD uk4; /* 0x18 */
745 DWORD size; /* 0x1C */
746 nt_hbin_sub hbin_sub; /* 0x20 */
747 } nt_hbin;
750 * the value_list consists of offsets to the values (vk)
752 typedef struct {
753 WORD SubBlockId; /* 0x00 0x6B6E */
754 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
755 FILETIME writetime; /* 0x04 */
756 DWORD uk1; /* 0x0C */
757 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
758 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
759 DWORD uk8; /* 0x18 */
760 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
761 DWORD uk2; /* 0x20 */
762 DWORD nr_values; /* 0x24 number of values */
763 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
764 DWORD off_sk; /* 0x2c Offset of the sk-Record */
765 DWORD off_class; /* 0x30 Offset of the Class-Name */
766 DWORD uk3; /* 0x34 */
767 DWORD uk4; /* 0x38 */
768 DWORD uk5; /* 0x3c */
769 DWORD uk6; /* 0x40 */
770 DWORD uk7; /* 0x44 */
771 WORD name_len; /* 0x48 name-length */
772 WORD class_len; /* 0x4a class-name length */
773 char name[1]; /* 0x4c key-name */
774 } nt_nk;
776 typedef struct {
777 DWORD off_nk; /* 0x00 */
778 DWORD name; /* 0x04 */
779 } hash_rec;
781 typedef struct {
782 WORD id; /* 0x00 0x666c */
783 WORD nr_keys; /* 0x06 */
784 hash_rec hash_rec[1];
785 } nt_lf;
788 list of subkeys without hash
790 li --+-->nk
792 +-->nk
794 typedef struct {
795 WORD id; /* 0x00 0x696c */
796 WORD nr_keys;
797 DWORD off_nk[1];
798 } nt_li;
801 this is a intermediate node
803 ri --+-->li--+-->nk
805 | +-->nk
807 +-->li--+-->nk
809 +-->nk
811 typedef struct {
812 WORD id; /* 0x00 0x6972 */
813 WORD nr_li; /* 0x02 number off offsets */
814 DWORD off_li[1]; /* 0x04 points to li */
815 } nt_ri;
817 typedef struct {
818 WORD id; /* 0x00 'vk' */
819 WORD nam_len;
820 DWORD data_len;
821 DWORD data_off;
822 DWORD type;
823 WORD flag;
824 WORD uk1;
825 char name[1];
826 } nt_vk;
829 * gets a value
831 * vk->flag:
832 * 0 value is a default value
833 * 1 the value has a name
835 * vk->data_len
836 * len of the whole data block
837 * - reg_sz (unicode)
838 * bytes including the terminating \0 = 2*(number_of_chars+1)
839 * - reg_dword, reg_binary:
840 * if highest bit of data_len is set data_off contains the value
842 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
844 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
845 struct key_value value;
847 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
848 ERR("unknown block found (0x%04x), please report!\n", vk->id);
849 return FALSE;
852 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
853 value.type = vk->type;
854 value.len = (vk->data_len & 0x7fffffff);
855 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
857 _dump_value(&value,f);
858 free(value.nameW);
860 return TRUE;
863 /* it's called from _nt_dump_lf() */
864 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
867 * get the subkeys
869 * this structure contains the hash of a keyname and points to all
870 * subkeys
872 * exception: if the id is 'il' there are no hash values and every
873 * dword is a offset
875 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
877 int i;
879 if (lf->id == NT_REG_HASH_BLOCK_ID) {
880 if (subkeys != lf->nr_keys) goto error1;
882 for (i=0; i<lf->nr_keys; i++)
883 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
884 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
885 nt_li * li = (nt_li*)lf;
886 if (subkeys != li->nr_keys) goto error1;
888 for (i=0; i<li->nr_keys; i++)
889 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
890 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
891 nt_ri * ri = (nt_ri*)lf;
892 int li_subkeys = 0;
894 /* count all subkeys */
895 for (i=0; i<ri->nr_li; i++) {
896 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
897 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
898 li_subkeys += li->nr_keys;
901 /* check number */
902 if (subkeys != li_subkeys) goto error1;
904 /* loop through the keys */
905 for (i=0; i<ri->nr_li; i++) {
906 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
907 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
909 } else goto error2;
911 return TRUE;
913 error2:
914 ERR("unknown node id 0x%04x, please report!\n", lf->id);
915 return TRUE;
917 error1:
918 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
919 return FALSE;
921 error:
922 ERR("error reading lf block\n");
923 return FALSE;
926 /* _nt_dump_nk [Internal] */
927 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
929 unsigned int n;
930 DWORD *vl;
931 LPSTR new_key_name = NULL;
934 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
935 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
936 return FALSE;
939 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
940 ERR("registry file corrupt!\n");
941 return FALSE;
944 /* create the new key */
945 if (level <= 0) {
946 /* create new subkey name */
947 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
948 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
949 strncat(new_key_name,nk->name,nk->name_len);
951 /* write the key path (something like [Software\\Microsoft\\..]) only if:
952 1) key has some values
953 2) key has no values and no subkeys
955 if (nk->nr_values > 0) {
956 /* there are some values */
957 fprintf(f,"\n[");
958 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
959 fprintf(f,"]\n");
961 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
962 /* no subkeys and no values */
963 fprintf(f,"\n[");
964 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
965 fprintf(f,"]\n");
968 /* loop trough the value list */
969 vl = (DWORD *)(base+nk->valuelist_off+4);
970 for (n=0; n<nk->nr_values; n++) {
971 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
972 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
973 free(new_key_name);
974 return FALSE;
977 } else new_key_name = _strdupnA(key_name,strlen(key_name));
979 /* loop through the subkeys */
980 if (nk->nr_subkeys) {
981 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
982 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
983 free(new_key_name);
984 return FALSE;
988 free(new_key_name);
989 return TRUE;
992 /* end nt loader */
994 /**********************************************************************************
995 * _set_registry_levels [Internal]
997 * set level to 0 for loading system files
998 * set level to 1 for loading user files
1000 static void _set_registry_levels(int level,int saving,int period)
1002 SERVER_START_REQ( set_registry_levels )
1004 req->current = level;
1005 req->saving = saving;
1006 req->period = period;
1007 SERVER_CALL();
1009 SERVER_END_REQ;
1012 /* _save_at_exit [Internal] */
1013 static void _save_at_exit(HKEY hkey,LPCSTR path)
1015 LPCSTR confdir = get_config_dir();
1016 size_t len = strlen(confdir) + strlen(path) + 2;
1018 if (len > REQUEST_MAX_VAR_SIZE) {
1019 ERR( "config dir '%s' too long\n", confdir );
1020 return;
1022 SERVER_START_VAR_REQ( save_registry_atexit, len )
1024 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1025 req->hkey = hkey;
1026 SERVER_CALL();
1028 SERVER_END_VAR_REQ;
1031 /* configure save files and start the periodic saving timer [Internal] */
1032 static void _init_registry_saving( HKEY hkey_users_default )
1034 int all;
1035 int period;
1037 all = PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1038 period = PROFILE_GetWineIniInt("registry","PeriodicSave",0);
1040 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1041 _set_registry_levels(1,!all,period*1000);
1043 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1045 _save_at_exit(HKEY_CURRENT_USER,SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1046 _save_at_exit(HKEY_LOCAL_MACHINE,SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1047 _save_at_exit(hkey_users_default,SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1052 /******************************************************************************
1053 * _allocate_default_keys [Internal]
1054 * Registry initialisation, allocates some default keys.
1056 static void _allocate_default_keys(void) {
1057 HKEY hkey;
1058 char buf[200];
1060 TRACE("(void)\n");
1062 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1063 RegCloseKey(hkey);
1065 /* This was an Open, but since it is called before the real registries
1066 are loaded, it was changed to a Create - MTB 980507*/
1067 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1068 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1069 RegCloseKey(hkey);
1071 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1072 * CurrentVersion
1073 * CurrentBuildNumber
1074 * CurrentType
1075 * string RegisteredOwner
1076 * string RegisteredOrganization
1079 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1080 * string SysContact
1081 * string SysLocation
1082 * SysServices
1084 if (-1!=gethostname(buf,200)) {
1085 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1086 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1087 RegCloseKey(hkey);
1090 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1091 RegCloseKey(hkey);
1094 #define REG_DONTLOAD -1
1095 #define REG_WIN31 0
1096 #define REG_WIN95 1
1097 #define REG_WINNT 2
1099 /* return the type of native registry [Internal] */
1100 static int _get_reg_type(void)
1102 char windir[MAX_PATHNAME_LEN];
1103 char tmp[MAX_PATHNAME_LEN];
1104 int ret = REG_WIN31;
1106 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1108 /* test %windir%/system32/config/system --> winnt */
1109 strcpy(tmp, windir);
1110 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1111 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1112 ret = REG_WINNT;
1114 else
1116 /* test %windir%/system.dat --> win95 */
1117 strcpy(tmp, windir);
1118 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1119 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1120 ret = REG_WIN95;
1124 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1125 MESSAGE("When you are running with a native NT directory specify\n");
1126 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1127 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1128 ret = REG_DONTLOAD;
1131 return ret;
1134 #define WINE_REG_VER_ERROR -1
1135 #define WINE_REG_VER_1 0
1136 #define WINE_REG_VER_2 1
1137 #define WINE_REG_VER_OLD 2
1138 #define WINE_REG_VER_UNKNOWN 3
1140 /* return the version of wine registry file [Internal] */
1141 static int _get_wine_registry_file_format_version(LPCSTR fn)
1143 FILE *f;
1144 char tmp[50];
1145 int ver;
1147 if ((f=fopen(fn,"rt")) == NULL) {
1148 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1149 return WINE_REG_VER_ERROR;
1152 if (fgets(tmp,50,f) == NULL) {
1153 WARN("Error reading %s: %s\n",fn,strerror(errno));
1154 fclose(f);
1155 return WINE_REG_VER_ERROR;
1157 fclose(f);
1159 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1160 switch (ver) {
1161 case 1:
1162 return WINE_REG_VER_1;
1163 break;
1164 case 2:
1165 return WINE_REG_VER_2;
1166 break;
1167 default:
1168 return WINE_REG_VER_UNKNOWN;
1172 /* load the registry file in wine format [Internal] */
1173 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1175 int file_format;
1177 file_format = _get_wine_registry_file_format_version(fn);
1178 switch (file_format) {
1180 case WINE_REG_VER_1:
1181 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1182 break;
1184 case WINE_REG_VER_2: {
1185 HANDLE file;
1186 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1187 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1189 SERVER_START_REQ( load_registry )
1191 req->hkey = hkey;
1192 req->file = file;
1193 SERVER_CALL();
1195 SERVER_END_REQ;
1196 CloseHandle( file );
1198 break;
1201 case WINE_REG_VER_UNKNOWN:
1202 WARN("Unable to load registry file %s: unknown format.\n",fn);
1203 break;
1205 case WINE_REG_VER_ERROR:
1206 break;
1210 /* generate and return the name of the tmp file and associated stream [Internal] */
1211 static LPSTR _get_tmp_fn(FILE **f)
1213 LPSTR ret;
1214 int tmp_fd,count;
1216 ret = _xmalloc(50);
1217 for (count = 0;;) {
1218 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1219 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1220 if (errno != EEXIST) {
1221 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1222 free(ret);
1223 *f = NULL;
1224 return NULL;
1228 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1229 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1230 close(tmp_fd);
1231 free(ret);
1232 return NULL;
1235 return ret;
1238 /* convert win95 native registry file to wine format [Internal] */
1239 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1241 int fd;
1242 FILE *f;
1243 DOS_FULL_NAME full_name;
1244 void *base;
1245 LPSTR ret = NULL;
1246 struct stat st;
1248 _w95creg *creg;
1249 _w95rgkn *rgkn;
1250 _w95dke *dke, *root_dke;
1252 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1254 /* map the registry into the memory */
1255 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1256 if ((fstat(fd, &st) == -1)) goto error1;
1257 if (!st.st_size) goto error1;
1258 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1260 /* control signature */
1261 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1262 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1263 goto error;
1266 creg = base;
1267 /* load the header (rgkn) */
1268 rgkn = (_w95rgkn*)(creg + 1);
1269 if (rgkn->id != W95_REG_RGKN_ID) {
1270 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1271 goto error;
1273 if (rgkn->root_off != 0x20) {
1274 ERR("rgkn->root_off not 0x20, please report !\n");
1275 goto error;
1277 if (rgkn->last_dke > rgkn->size)
1279 ERR("registry file corrupt! last_dke > size!\n");
1280 goto error;
1282 /* verify last dke */
1283 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1284 if (dke->x1 != 0x80000000)
1285 { /* wrong magic */
1286 ERR("last dke invalid !\n");
1287 goto error;
1289 if (rgkn->size > creg->rgdb_off)
1291 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1292 goto error;
1294 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1295 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1297 ERR("registry file corrupt! invalid root dke !\n");
1298 goto error;
1301 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1302 fprintf(f,"WINE REGISTRY Version 2");
1303 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1304 fclose(f);
1306 error:
1307 if(ret == NULL) {
1308 ERR("Unable to load native win95 registry file %s.\n",fn);
1309 ERR("Please report to a.mohr@mailto.de.\n");
1310 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1313 munmap(base, st.st_size);
1314 error1:
1315 close(fd);
1316 return ret;
1319 /* convert winnt native registry file to wine format [Internal] */
1320 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1322 int fd;
1323 FILE *f;
1324 DOS_FULL_NAME full_name;
1325 void *base;
1326 LPSTR ret = NULL;
1327 struct stat st;
1329 nt_regf *regf;
1330 nt_hbin *hbin;
1331 nt_hbin_sub *hbin_sub;
1332 nt_nk *nk;
1334 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1336 /* map the registry into the memory */
1337 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1338 if ((fstat(fd, &st) == -1)) goto error1;
1339 if (!st.st_size) goto error1;
1340 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1342 /* control signature */
1343 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1344 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1345 goto error;
1348 /* start block */
1349 regf = base;
1351 /* hbin block */
1352 hbin = (nt_hbin*)((char*) base + 0x1000);
1353 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1354 ERR( "hbin block invalid\n");
1355 goto error;
1358 /* hbin_sub block */
1359 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1360 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1361 ERR( "hbin_sub block invalid\n");
1362 goto error;
1365 /* nk block */
1366 nk = (nt_nk*)&(hbin_sub->data[0]);
1367 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1368 ERR( "special nk block not found\n");
1369 goto error;
1372 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1373 fprintf(f,"WINE REGISTRY Version 2");
1374 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1375 fclose(f);
1377 error:
1378 munmap(base,st.st_size);
1379 error1:
1380 close(fd);
1381 return ret;
1384 /* convert native registry to wine format and load it via server call [Internal] */
1385 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1387 LPSTR tmp = NULL;
1389 switch (reg_type) {
1390 case REG_WINNT:
1391 /* FIXME: following function doesn't really convert yet */
1392 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1393 break;
1394 case REG_WIN95:
1395 tmp = _convert_win95_registry_to_wine_format(fn,level);
1396 break;
1397 case REG_WIN31:
1398 ERR("Don't know how to convert native 3.1 registry yet.\n");
1399 break;
1400 default:
1401 ERR("Unknown registry format parameter (%d)\n",reg_type);
1402 break;
1405 if (tmp != NULL) {
1406 load_wine_registry(hkey,tmp);
1407 TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp);
1408 unlink(tmp);
1410 else WARN("Unable to convert %s (doesn't exist?)\n",fn);
1411 free(tmp);
1414 /* load all native windows registry files [Internal] */
1415 static void _load_windows_registry( HKEY hkey_users_default )
1417 int reg_type;
1418 char windir[MAX_PATHNAME_LEN];
1419 char path[MAX_PATHNAME_LEN];
1421 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1423 reg_type = _get_reg_type();
1424 switch (reg_type) {
1425 case REG_WINNT: {
1426 HKEY hkey;
1428 /* user specific ntuser.dat */
1429 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1430 strcat(path,"\\ntuser.dat");
1431 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1434 /* default user.dat */
1435 if (hkey_users_default) {
1436 strcpy(path,windir);
1437 strcat(path,"\\system32\\config\\default");
1438 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1442 * FIXME
1443 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1446 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1447 strcpy(path,windir);
1448 strcat(path,"\\system32\\config\\system");
1449 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1450 RegCloseKey(hkey);
1453 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1454 strcpy(path,windir);
1455 strcat(path,"\\system32\\config\\software");
1456 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1457 RegCloseKey(hkey);
1460 strcpy(path,windir);
1461 strcat(path,"\\system32\\config\\sam");
1462 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1464 strcpy(path,windir);
1465 strcat(path,"\\system32\\config\\security");
1466 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1468 /* this key is generated when the nt-core booted successfully */
1469 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1470 break;
1473 case REG_WIN95:
1474 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1476 strcpy(path,windir);
1477 strcat(path,"\\system.dat");
1478 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1480 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1481 /* user specific user.dat */
1482 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1483 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1485 /* default user.dat */
1486 if (hkey_users_default) {
1487 strcpy(path,windir);
1488 strcat(path,"\\user.dat");
1489 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1491 } else {
1492 strcpy(path,windir);
1493 strcat(path,"\\user.dat");
1494 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1496 break;
1498 case REG_WIN31:
1499 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1500 _w31_loadreg();
1501 break;
1503 case REG_DONTLOAD:
1504 TRACE("REG_DONTLOAD\n");
1505 break;
1507 default:
1508 ERR("switch: no match (%d)\n",reg_type);
1509 break;
1514 /* load global registry files (stored in /etc/wine) [Internal] */
1515 static void _load_global_registry(void)
1517 TRACE("(void)\n");
1519 /* Load the global HKU hive directly from sysconfdir */
1520 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1522 /* Load the global machine defaults directly from sysconfdir */
1523 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1526 /* load home registry files (stored in ~/.wine) [Internal] */
1527 static void _load_home_registry( HKEY hkey_users_default )
1529 LPCSTR confdir = get_config_dir();
1530 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1532 strcpy(tmp,confdir);
1533 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1534 load_wine_registry(hkey_users_default,tmp);
1536 strcpy(tmp,confdir);
1537 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1538 load_wine_registry(HKEY_CURRENT_USER,tmp);
1540 strcpy(tmp,confdir);
1541 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1542 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1544 free(tmp);
1547 /* load all registry (native and global and home) */
1548 void SHELL_LoadRegistry( void )
1550 HKEY hkey_users_default;
1552 TRACE("(void)\n");
1554 if (!CLIENT_IsBootThread()) return; /* already loaded */
1556 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1558 ERR("Cannot create HKEY_USERS/.Default\n" );
1559 ExitProcess(1);
1562 _allocate_default_keys();
1563 _set_registry_levels(0,0,0);
1564 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1565 _load_windows_registry( hkey_users_default );
1566 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1567 _load_global_registry();
1568 _set_registry_levels(1,0,0);
1569 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1570 _load_home_registry( hkey_users_default );
1571 _init_registry_saving( hkey_users_default );
1572 RegCloseKey(hkey_users_default);
1575 /***************************************************************************/
1576 /* API FUNCTIONS */
1577 /***************************************************************************/
1579 /******************************************************************************
1580 * RegFlushKey [ADVAPI32.@]
1581 * Immediately writes key to registry.
1582 * Only returns after data has been written to disk.
1584 * FIXME: does it really wait until data is written ?
1586 * PARAMS
1587 * hkey [I] Handle of key to write
1589 * RETURNS
1590 * Success: ERROR_SUCCESS
1591 * Failure: Error code
1593 DWORD WINAPI RegFlushKey( HKEY hkey )
1595 FIXME( "(%x): stub\n", hkey );
1596 return ERROR_SUCCESS;
1600 /******************************************************************************
1601 * RegUnLoadKeyA [ADVAPI32.@]
1603 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1605 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1606 return ERROR_SUCCESS;
1610 /******************************************************************************
1611 * RegRestoreKeyW [ADVAPI32.@]
1613 * PARAMS
1614 * hkey [I] Handle of key where restore begins
1615 * lpFile [I] Address of filename containing saved tree
1616 * dwFlags [I] Optional flags
1618 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1620 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1622 /* It seems to do this check before the hkey check */
1623 if (!lpFile || !*lpFile)
1624 return ERROR_INVALID_PARAMETER;
1626 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1628 /* Check for file existence */
1630 return ERROR_SUCCESS;
1634 /******************************************************************************
1635 * RegRestoreKeyA [ADVAPI32.@]
1637 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1639 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1640 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1641 HeapFree( GetProcessHeap(), 0, lpFileW );
1642 return ret;
1646 /******************************************************************************
1647 * RegReplaceKeyA [ADVAPI32.@]
1649 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1650 LPCSTR lpOldFile )
1652 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1653 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1654 return ERROR_SUCCESS;
1662 /* 16-bit functions */
1664 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1665 * some programs. Do not remove those cases. -MM
1667 static inline void fix_win16_hkey( HKEY *hkey )
1669 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1672 /******************************************************************************
1673 * RegEnumKey [KERNEL.216]
1674 * RegEnumKey [SHELL.7]
1676 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1678 fix_win16_hkey( &hkey );
1679 return RegEnumKeyA( hkey, index, name, name_len );
1682 /******************************************************************************
1683 * RegOpenKey [KERNEL.217]
1684 * RegOpenKey [SHELL.1]
1686 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1688 fix_win16_hkey( &hkey );
1689 return RegOpenKeyA( hkey, name, retkey );
1692 /******************************************************************************
1693 * RegCreateKey [KERNEL.218]
1694 * RegCreateKey [SHELL.2]
1696 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1698 fix_win16_hkey( &hkey );
1699 return RegCreateKeyA( hkey, name, retkey );
1702 /******************************************************************************
1703 * RegDeleteKey [KERNEL.219]
1704 * RegDeleteKey [SHELL.4]
1706 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1708 fix_win16_hkey( &hkey );
1709 return RegDeleteKeyA( hkey, name );
1712 /******************************************************************************
1713 * RegCloseKey [KERNEL.220]
1714 * RegCloseKey [SHELL.3]
1716 DWORD WINAPI RegCloseKey16( HKEY hkey )
1718 fix_win16_hkey( &hkey );
1719 return RegCloseKey( hkey );
1722 /******************************************************************************
1723 * RegSetValue [KERNEL.221]
1724 * RegSetValue [SHELL.5]
1726 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1728 fix_win16_hkey( &hkey );
1729 return RegSetValueA( hkey, name, type, data, count );
1732 /******************************************************************************
1733 * RegDeleteValue [KERNEL.222]
1735 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1737 fix_win16_hkey( &hkey );
1738 return RegDeleteValueA( hkey, name );
1741 /******************************************************************************
1742 * RegEnumValue [KERNEL.223]
1744 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1745 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1747 fix_win16_hkey( &hkey );
1748 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1751 /******************************************************************************
1752 * RegQueryValue [KERNEL.224]
1753 * RegQueryValue [SHELL.6]
1755 * NOTES
1756 * Is this HACK still applicable?
1758 * HACK
1759 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1760 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1761 * Aldus FH4)
1763 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1765 fix_win16_hkey( &hkey );
1766 if (count) *count &= 0xffff;
1767 return RegQueryValueA( hkey, name, data, count );
1770 /******************************************************************************
1771 * RegQueryValueEx [KERNEL.225]
1773 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1774 LPBYTE data, LPDWORD count )
1776 fix_win16_hkey( &hkey );
1777 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1780 /******************************************************************************
1781 * RegSetValueEx [KERNEL.226]
1783 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1784 CONST BYTE *data, DWORD count )
1786 fix_win16_hkey( &hkey );
1787 if (!count && (type==REG_SZ)) count = strlen(data);
1788 return RegSetValueExA( hkey, name, reserved, type, data, count );
1791 /******************************************************************************
1792 * RegFlushKey [KERNEL.227]
1794 DWORD WINAPI RegFlushKey16( HKEY hkey )
1796 fix_win16_hkey( &hkey );
1797 return RegFlushKey( hkey );