Convert most of the file APIs to Unicode.
[wine/wine64.git] / misc / registry.c
blobfeb548b05678c3f8ab7dfb66f64a344dc1f633bd
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * NOTES
27 * When changing this file, please re-run the regtest program to ensure
28 * the conditions are handled properly.
30 * TODO
31 * Security access
32 * Option handling
33 * Time for RegEnumKey*, RegQueryInfoKey*
36 #include "config.h"
37 #include "wine/port.h"
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
51 #endif
53 #include "winerror.h"
54 #include "winnt.h"
55 #include "winreg.h"
57 #include "wine/winbase16.h"
58 #include "wine/library.h"
59 #include "wine/server.h"
60 #include "wine/unicode.h"
61 #include "file.h"
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(reg);
67 /* FIXME: following defines should be configured global */
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
71 /* relative in ~user/.wine/ : */
72 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
73 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
74 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
76 /* _xmalloc [Internal] */
77 static void *_xmalloc( size_t size )
79 void *res;
81 res = malloc (size ? size : 1);
82 if (res == NULL) {
83 WARN("Virtual memory exhausted.\n");
84 exit (1);
86 return res;
89 /* _strdupnA [Internal] */
90 static LPSTR _strdupnA(LPCSTR str,size_t len)
92 LPSTR ret;
94 if (!str) return NULL;
95 ret = _xmalloc( len + 1 );
96 memcpy( ret, str, len );
97 ret[len] = 0x00;
98 return ret;
101 /* convert ansi string to unicode [Internal] */
102 static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
104 LPWSTR ret;
105 size_t lenW;
107 if (!strA) return NULL;
108 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
109 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
110 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
111 ret[lenW] = 0;
112 return ret;
115 /* dump a Unicode string with proper escaping [Internal] */
116 /* FIXME: this code duplicates server/unicode.c */
117 static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
119 static const char escapes[32] = ".......abtnvfr.............e....";
120 char buffer[256];
121 LPSTR pos = buffer;
122 int count = 0;
124 for (; len; str++, len--)
126 if (pos > buffer + sizeof(buffer) - 8)
128 fwrite( buffer, pos - buffer, 1, f );
129 count += pos - buffer;
130 pos = buffer;
132 if (*str > 127) /* hex escape */
134 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
135 pos += sprintf( pos, "\\x%04x", *str );
136 else
137 pos += sprintf( pos, "\\x%x", *str );
138 continue;
140 if (*str < 32) /* octal or C escape */
142 if (!*str && len == 1) continue; /* do not output terminating NULL */
143 if (escapes[*str] != '.')
144 pos += sprintf( pos, "\\%c", escapes[*str] );
145 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
146 pos += sprintf( pos, "\\%03o", *str );
147 else
148 pos += sprintf( pos, "\\%o", *str );
149 continue;
151 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
152 *pos++ = *str;
154 fwrite( buffer, pos - buffer, 1, f );
155 count += pos - buffer;
156 return count;
159 /* convert ansi string to unicode and dump with proper escaping [Internal] */
160 static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
162 WCHAR *strW;
163 int ret;
165 if (strA == NULL) return 0;
166 strW = _strdupnAtoW(strA,len);
167 ret = _dump_strW(strW,len,f,escape);
168 free(strW);
169 return ret;
172 /* a key value */
173 /* FIXME: this code duplicates server/registry.c */
174 struct key_value {
175 WCHAR *nameW; /* value name */
176 int type; /* value type */
177 size_t len; /* value data length in bytes */
178 void *data; /* pointer to value data */
181 /* dump a value to a text file */
182 /* FIXME: this code duplicates server/registry.c */
183 static void _dump_value(struct key_value *value,FILE *f)
185 int i, count;
187 if (value->nameW[0]) {
188 fputc( '\"', f );
189 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
190 count += fprintf( f, "\"=" );
192 else count = fprintf( f, "@=" );
194 switch(value->type) {
195 case REG_SZ:
196 case REG_EXPAND_SZ:
197 case REG_MULTI_SZ:
198 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
199 fputc( '\"', f );
200 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
201 fputc( '\"', f );
202 break;
203 case REG_DWORD:
204 if (value->len == sizeof(DWORD)) {
205 DWORD dw;
206 memcpy( &dw, value->data, sizeof(DWORD) );
207 fprintf( f, "dword:%08lx", dw );
208 break;
210 /* else fall through */
211 default:
212 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
213 else count += fprintf( f, "hex(%x):", value->type );
214 for (i = 0; i < value->len; i++) {
215 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
216 if (i < value->len-1) {
217 fputc( ',', f );
218 if (++count > 76) {
219 fprintf( f, "\\\n " );
220 count = 2;
224 break;
226 fputc( '\n', f );
229 /******************************************************************/
230 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
232 reghack - windows 3.11 registry data format demo program.
234 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
235 a combined hash table and tree description, and finally a text table.
237 The header is obvious from the struct header. The taboff1 and taboff2
238 fields are always 0x20, and their usage is unknown.
240 The 8-byte entry table has various entry types.
242 tabent[0] is a root index. The second word has the index of the root of
243 the directory.
244 tabent[1..hashsize] is a hash table. The first word in the hash entry is
245 the index of the key/value that has that hash. Data with the same
246 hash value are on a circular list. The other three words in the
247 hash entry are always zero.
248 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
249 entry: dirent and keyent/valent. They are identified by context.
250 tabent[freeidx] is the first free entry. The first word in a free entry
251 is the index of the next free entry. The last has 0 as a link.
252 The other three words in the free list are probably irrelevant.
254 Entries in text table are preceded by a word at offset-2. This word
255 has the value (2*index)+1, where index is the referring keyent/valent
256 entry in the table. I have no suggestion for the 2* and the +1.
257 Following the word, there are N bytes of data, as per the keyent/valent
258 entry length. The offset of the keyent/valent entry is from the start
259 of the text table to the first data byte.
261 This information is not available from Microsoft. The data format is
262 deduced from the reg.dat file by me. Mistakes may
263 have been made. I claim no rights and give no guarantees for this program.
265 Tor Sjøwall, tor@sn.no
268 /* reg.dat header format */
269 struct _w31_header {
270 char cookie[8]; /* 'SHCC3.10' */
271 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
272 unsigned long taboff2; /* offset of index table (??) = 0x20 */
273 unsigned long tabcnt; /* number of entries in index table */
274 unsigned long textoff; /* offset of text part */
275 unsigned long textsize; /* byte size of text part */
276 unsigned short hashsize; /* hash size */
277 unsigned short freeidx; /* free index */
280 /* generic format of table entries */
281 struct _w31_tabent {
282 unsigned short w0, w1, w2, w3;
285 /* directory tabent: */
286 struct _w31_dirent {
287 unsigned short sibling_idx; /* table index of sibling dirent */
288 unsigned short child_idx; /* table index of child dirent */
289 unsigned short key_idx; /* table index of key keyent */
290 unsigned short value_idx; /* table index of value valent */
293 /* key tabent: */
294 struct _w31_keyent {
295 unsigned short hash_idx; /* hash chain index for string */
296 unsigned short refcnt; /* reference count */
297 unsigned short length; /* length of string */
298 unsigned short string_off; /* offset of string in text table */
301 /* value tabent: */
302 struct _w31_valent {
303 unsigned short hash_idx; /* hash chain index for string */
304 unsigned short refcnt; /* reference count */
305 unsigned short length; /* length of string */
306 unsigned short string_off; /* offset of string in text table */
309 /* recursive helper function to display a directory tree [Internal] */
310 void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
312 struct _w31_dirent *dir;
313 struct _w31_keyent *key;
314 struct _w31_valent *val;
315 HKEY subkey = 0;
316 static char tail[400];
318 while (idx!=0) {
319 dir=(struct _w31_dirent*)&tab[idx];
321 if (dir->key_idx) {
322 key = (struct _w31_keyent*)&tab[dir->key_idx];
324 memcpy(tail,&txt[key->string_off],key->length);
325 tail[key->length]='\0';
326 /* all toplevel entries AND the entries in the
327 * toplevel subdirectory belong to \SOFTWARE\Classes
329 if (!level && !strcmp(tail,".classes")) {
330 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
331 idx=dir->sibling_idx;
332 continue;
334 if (subkey) RegCloseKey( subkey );
335 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
336 /* only add if leaf node or valued node */
337 if (dir->value_idx!=0||dir->child_idx==0) {
338 if (dir->value_idx) {
339 val=(struct _w31_valent*)&tab[dir->value_idx];
340 memcpy(tail,&txt[val->string_off],val->length);
341 tail[val->length]='\0';
342 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
345 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
346 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
347 idx=dir->sibling_idx;
349 if (subkey) RegCloseKey( subkey );
353 /******************************************************************************
354 * _w31_loadreg [Internal]
356 void _w31_loadreg(void)
358 HFILE hf;
359 struct _w31_header head;
360 struct _w31_tabent *tab;
361 unsigned char *txt;
362 unsigned int len;
363 OFSTRUCT ofs;
364 BY_HANDLE_FILE_INFORMATION hfinfo;
365 time_t lastmodified;
367 TRACE("(void)\n");
369 hf = OpenFile("reg.dat",&ofs,OF_READ);
370 if (hf==HFILE_ERROR) return;
372 /* read & dump header */
373 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
374 ERR("reg.dat is too short.\n");
375 _lclose(hf);
376 return;
378 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
379 ERR("reg.dat has bad signature.\n");
380 _lclose(hf);
381 return;
384 len = head.tabcnt * sizeof(struct _w31_tabent);
385 /* read and dump index table */
386 tab = _xmalloc(len);
387 if (len!=_lread(hf,tab,len)) {
388 ERR("couldn't read %d bytes.\n",len);
389 free(tab);
390 _lclose(hf);
391 return;
394 /* read text */
395 txt = _xmalloc(head.textsize);
396 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
397 ERR("couldn't seek to textblock.\n");
398 free(tab);
399 free(txt);
400 _lclose(hf);
401 return;
403 if (head.textsize!=_lread(hf,txt,head.textsize)) {
404 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
405 free(tab);
406 free(txt);
407 _lclose(hf);
408 return;
411 if (!GetFileInformationByHandle(hf,&hfinfo)) {
412 ERR("GetFileInformationByHandle failed?.\n");
413 free(tab);
414 free(txt);
415 _lclose(hf);
416 return;
418 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
419 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
420 free(tab);
421 free(txt);
422 _lclose(hf);
423 return;
426 /***********************************************************************************/
427 /* windows 95 registry loader */
428 /***********************************************************************************/
430 /* SECTION 1: main header
432 * once at offset 0
434 #define W95_REG_CREG_ID 0x47455243
436 typedef struct {
437 DWORD id; /* "CREG" = W95_REG_CREG_ID */
438 DWORD version; /* ???? 0x00010000 */
439 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
440 DWORD uk2; /* 0x0c */
441 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
442 WORD uk3;
443 DWORD uk[3];
444 /* rgkn */
445 } _w95creg;
447 /* SECTION 2: Directory information (tree structure)
449 * once on offset 0x20
451 * structure: [rgkn][dke]* (repeat till last_dke is reached)
453 #define W95_REG_RGKN_ID 0x4e4b4752
455 typedef struct {
456 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
457 DWORD size; /* Size of the RGKN-block */
458 DWORD root_off; /* Rel. Offset of the root-record */
459 DWORD last_dke; /* Offset to last DKE ? */
460 DWORD uk[4];
461 } _w95rgkn;
463 /* Disk Key Entry Structure
465 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
466 * hive itself. It looks the same like other keys. Even the ID-number can
467 * be any value.
469 * The "hash"-value is a value representing the key's name. Windows will not
470 * search for the name, but for a matching hash-value. if it finds one, it
471 * will compare the actual string info, otherwise continue with the next key.
472 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
473 * of the string which are smaller than 0x80 (128) to this D-Word.
475 * If you want to modify key names, also modify the hash-values, since they
476 * cannot be found again (although they would be displayed in REGEDIT)
477 * End of list-pointers are filled with 0xFFFFFFFF
479 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
480 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
481 * structure) and reading another RGDB_section.
483 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
484 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
485 * The remaining space between last_dke and the offset calculated from
486 * rgkn->size seems to be free for use for more dke:s.
487 * So it seems if more dke:s are added, they are added to that space and
488 * last_dke is grown, and in case that "free" space is out, the space
489 * gets grown and rgkn->size gets adjusted.
491 * there is a one to one relationship between dke and dkh
493 /* key struct, once per key */
494 typedef struct {
495 DWORD x1; /* Free entry indicator(?) */
496 DWORD hash; /* sum of bytes of keyname */
497 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
498 DWORD prevlvl; /* offset of previous key */
499 DWORD nextsub; /* offset of child key */
500 DWORD next; /* offset of sibling key */
501 WORD nrLS; /* id inside the rgdb block */
502 WORD nrMS; /* number of the rgdb block */
503 } _w95dke;
505 /* SECTION 3: key information, values and data
507 * structure:
508 * section: [blocks]* (repeat creg->rgdb_num times)
509 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
510 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
512 * An interesting relationship exists in RGDB_section. The DWORD value
513 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
514 * I have no idea at the moment what this means. (Kevin Cozens)
517 /* block header, once per block */
518 #define W95_REG_RGDB_ID 0x42444752
520 typedef struct {
521 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
522 DWORD size; /* 0x04 */
523 DWORD uk1; /* 0x08 */
524 DWORD uk2; /* 0x0c */
525 DWORD uk3; /* 0x10 */
526 DWORD uk4; /* 0x14 */
527 DWORD uk5; /* 0x18 */
528 DWORD uk6; /* 0x1c */
529 /* dkh */
530 } _w95rgdb;
532 /* Disk Key Header structure (RGDB part), once per key */
533 typedef struct {
534 DWORD nextkeyoff; /* 0x00 offset to next dkh */
535 WORD nrLS; /* 0x04 id inside the rgdb block */
536 WORD nrMS; /* 0x06 number of the rgdb block */
537 DWORD bytesused; /* 0x08 */
538 WORD keynamelen; /* 0x0c len of name */
539 WORD values; /* 0x0e number of values */
540 DWORD xx1; /* 0x10 */
541 char name[1]; /* 0x14 */
542 /* dkv */ /* 0x14 + keynamelen */
543 } _w95dkh;
545 /* Disk Key Value structure, once per value */
546 typedef struct {
547 DWORD type; /* 0x00 */
548 DWORD x1; /* 0x04 */
549 WORD valnamelen; /* 0x08 length of name, 0 is default key */
550 WORD valdatalen; /* 0x0A length of data */
551 char name[1]; /* 0x0c */
552 /* raw data */ /* 0x0c + valnamelen */
553 } _w95dkv;
555 /******************************************************************************
556 * _w95_lookup_dkh [Internal]
558 * seeks the dkh belonging to a dke
560 static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
562 _w95rgdb * rgdb;
563 _w95dkh * dkh;
564 int i;
566 /* get the beginning of the rgdb datastore */
567 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
569 /* check: requested block < last_block) */
570 if (creg->rgdb_num <= nrMS) {
571 ERR("registry file corrupt! requested block no. beyond end.\n");
572 goto error;
575 /* find the right block */
576 for(i=0; i<nrMS ;i++) {
577 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
578 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
579 goto error;
581 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
584 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
586 do {
587 if(nrLS==dkh->nrLS ) return dkh;
588 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
589 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
591 error:
592 return NULL;
595 /******************************************************************************
596 * _w95_dump_dkv [Internal]
598 static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
600 _w95dkv * dkv;
601 int i;
603 /* first value block */
604 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
606 /* loop through the values */
607 for (i=0; i< dkh->values; i++) {
608 struct key_value value;
609 WCHAR *pdata;
611 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
612 value.type = dkv->type;
613 value.len = dkv->valdatalen;
615 value.data = &(dkv->name[dkv->valnamelen]);
616 pdata = NULL;
617 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
618 pdata = _strdupnAtoW(value.data,value.len);
619 value.len *= 2;
621 if (pdata != NULL) value.data = pdata;
623 _dump_value(&value,f);
624 free(value.nameW);
625 if (pdata != NULL) free(pdata);
627 /* next value */
628 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
630 return TRUE;
633 /******************************************************************************
634 * _w95_dump_dke [Internal]
636 static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
638 _w95dkh * dkh;
639 LPSTR new_key_name = NULL;
641 /* special root key */
642 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
644 /* parse the one subkey */
645 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
646 /* has no sibling keys */
647 return FALSE;
650 /* search subblock */
651 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
652 ERR("dke pointing to missing dkh !\n");
653 return FALSE;
656 if (level <= 0) {
657 /* create new subkey name */
658 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
659 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
660 strncat(new_key_name,dkh->name,dkh->keynamelen);
662 /* walk sibling keys */
663 if (dke->next != 0xffffffff ) {
664 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
665 free(new_key_name);
666 return FALSE;
670 /* write the key path (something like [Software\\Microsoft\\..]) only if:
671 1) key has some values
672 2) key has no values and no subkeys
674 if (dkh->values > 0) {
675 /* there are some values */
676 fprintf(f,"\n[");
677 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
678 fprintf(f,"]\n");
679 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
680 free(new_key_name);
681 return FALSE;
684 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
685 /* no subkeys and no values */
686 fprintf(f,"\n[");
687 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
688 fprintf(f,"]\n");
690 } else new_key_name = _strdupnA(key_name,strlen(key_name));
692 /* next sub key */
693 if (dke->nextsub != 0xffffffff) {
694 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
695 free(new_key_name);
696 return FALSE;
700 free(new_key_name);
701 return TRUE;
703 /* end windows 95 loader */
705 /***********************************************************************************/
706 /* windows NT registry loader */
707 /***********************************************************************************/
709 /* NT REGISTRY LOADER */
711 #ifdef HAVE_SYS_MMAN_H
712 # include <sys/mman.h>
713 #endif
715 #ifndef MAP_FAILED
716 #define MAP_FAILED ((LPVOID)-1)
717 #endif
719 #define NT_REG_BLOCK_SIZE 0x1000
721 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
722 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
723 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
724 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
726 /* subblocks of nk */
727 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
728 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
729 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
731 #define NT_REG_KEY_BLOCK_TYPE 0x20
732 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
734 typedef struct {
735 DWORD id; /* 0x66676572 'regf'*/
736 DWORD uk1; /* 0x04 */
737 DWORD uk2; /* 0x08 */
738 FILETIME DateModified; /* 0x0c */
739 DWORD uk3; /* 0x14 */
740 DWORD uk4; /* 0x18 */
741 DWORD uk5; /* 0x1c */
742 DWORD uk6; /* 0x20 */
743 DWORD RootKeyBlock; /* 0x24 */
744 DWORD BlockSize; /* 0x28 */
745 DWORD uk7[116];
746 DWORD Checksum; /* at offset 0x1FC */
747 } nt_regf;
749 typedef struct {
750 DWORD blocksize;
751 BYTE data[1];
752 } nt_hbin_sub;
754 typedef struct {
755 DWORD id; /* 0x6E696268 'hbin' */
756 DWORD off_prev;
757 DWORD off_next;
758 DWORD uk1;
759 DWORD uk2; /* 0x10 */
760 DWORD uk3; /* 0x14 */
761 DWORD uk4; /* 0x18 */
762 DWORD size; /* 0x1C */
763 nt_hbin_sub hbin_sub; /* 0x20 */
764 } nt_hbin;
767 * the value_list consists of offsets to the values (vk)
769 typedef struct {
770 WORD SubBlockId; /* 0x00 0x6B6E */
771 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
772 FILETIME writetime; /* 0x04 */
773 DWORD uk1; /* 0x0C */
774 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
775 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
776 DWORD uk8; /* 0x18 */
777 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
778 DWORD uk2; /* 0x20 */
779 DWORD nr_values; /* 0x24 number of values */
780 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
781 DWORD off_sk; /* 0x2c Offset of the sk-Record */
782 DWORD off_class; /* 0x30 Offset of the Class-Name */
783 DWORD uk3; /* 0x34 */
784 DWORD uk4; /* 0x38 */
785 DWORD uk5; /* 0x3c */
786 DWORD uk6; /* 0x40 */
787 DWORD uk7; /* 0x44 */
788 WORD name_len; /* 0x48 name-length */
789 WORD class_len; /* 0x4a class-name length */
790 char name[1]; /* 0x4c key-name */
791 } nt_nk;
793 typedef struct {
794 DWORD off_nk; /* 0x00 */
795 DWORD name; /* 0x04 */
796 } hash_rec;
798 typedef struct {
799 WORD id; /* 0x00 0x666c */
800 WORD nr_keys; /* 0x06 */
801 hash_rec hash_rec[1];
802 } nt_lf;
805 list of subkeys without hash
807 li --+-->nk
809 +-->nk
811 typedef struct {
812 WORD id; /* 0x00 0x696c */
813 WORD nr_keys;
814 DWORD off_nk[1];
815 } nt_li;
818 this is a intermediate node
820 ri --+-->li--+-->nk
822 | +-->nk
824 +-->li--+-->nk
826 +-->nk
828 typedef struct {
829 WORD id; /* 0x00 0x6972 */
830 WORD nr_li; /* 0x02 number off offsets */
831 DWORD off_li[1]; /* 0x04 points to li */
832 } nt_ri;
834 typedef struct {
835 WORD id; /* 0x00 'vk' */
836 WORD nam_len;
837 DWORD data_len;
838 DWORD data_off;
839 DWORD type;
840 WORD flag;
841 WORD uk1;
842 char name[1];
843 } nt_vk;
846 * gets a value
848 * vk->flag:
849 * 0 value is a default value
850 * 1 the value has a name
852 * vk->data_len
853 * len of the whole data block
854 * - reg_sz (unicode)
855 * bytes including the terminating \0 = 2*(number_of_chars+1)
856 * - reg_dword, reg_binary:
857 * if highest bit of data_len is set data_off contains the value
859 static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
861 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
862 struct key_value value;
864 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
865 ERR("unknown block found (0x%04x), please report!\n", vk->id);
866 return FALSE;
869 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
870 value.type = vk->type;
871 value.len = (vk->data_len & 0x7fffffff);
872 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
874 _dump_value(&value,f);
875 free(value.nameW);
877 return TRUE;
880 /* it's called from _nt_dump_lf() */
881 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
884 * get the subkeys
886 * this structure contains the hash of a keyname and points to all
887 * subkeys
889 * exception: if the id is 'il' there are no hash values and every
890 * dword is a offset
892 static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
894 int i;
896 if (lf->id == NT_REG_HASH_BLOCK_ID) {
897 if (subkeys != lf->nr_keys) goto error1;
899 for (i=0; i<lf->nr_keys; i++)
900 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
901 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
902 nt_li * li = (nt_li*)lf;
903 if (subkeys != li->nr_keys) goto error1;
905 for (i=0; i<li->nr_keys; i++)
906 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
907 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
908 nt_ri * ri = (nt_ri*)lf;
909 int li_subkeys = 0;
911 /* count all subkeys */
912 for (i=0; i<ri->nr_li; i++) {
913 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
914 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
915 li_subkeys += li->nr_keys;
918 /* check number */
919 if (subkeys != li_subkeys) goto error1;
921 /* loop through the keys */
922 for (i=0; i<ri->nr_li; i++) {
923 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
924 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
926 } else goto error2;
928 return TRUE;
930 error2:
931 if (lf->id == 0x686c)
932 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
933 else
934 ERR("unknown node id 0x%04x, please report!\n", lf->id);
935 return TRUE;
937 error1:
938 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
939 return FALSE;
941 error:
942 ERR("error reading lf block\n");
943 return FALSE;
946 /* _nt_dump_nk [Internal] */
947 static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
949 unsigned int n;
950 DWORD *vl;
951 LPSTR new_key_name = NULL;
953 TRACE("%s\n", key_name);
955 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
956 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
957 return FALSE;
960 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
961 ERR("registry file corrupt!\n");
962 return FALSE;
965 /* create the new key */
966 if (level <= 0) {
967 /* create new subkey name */
968 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
969 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
970 strncat(new_key_name,nk->name,nk->name_len);
972 /* write the key path (something like [Software\\Microsoft\\..]) only if:
973 1) key has some values
974 2) key has no values and no subkeys
976 if (nk->nr_values > 0) {
977 /* there are some values */
978 fprintf(f,"\n[");
979 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
980 fprintf(f,"]\n");
982 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
983 /* no subkeys and no values */
984 fprintf(f,"\n[");
985 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
986 fprintf(f,"]\n");
989 /* loop trough the value list */
990 vl = (DWORD *)(base+nk->valuelist_off+4);
991 for (n=0; n<nk->nr_values; n++) {
992 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
993 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
994 free(new_key_name);
995 return FALSE;
998 } else new_key_name = _strdupnA(key_name,strlen(key_name));
1000 /* loop through the subkeys */
1001 if (nk->nr_subkeys) {
1002 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
1003 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
1004 free(new_key_name);
1005 return FALSE;
1009 free(new_key_name);
1010 return TRUE;
1013 /* end nt loader */
1015 /**********************************************************************************
1016 * _set_registry_levels [Internal]
1018 * set level to 0 for loading system files
1019 * set level to 1 for loading user files
1021 static void _set_registry_levels(int level,int saving,int period)
1023 SERVER_START_REQ( set_registry_levels )
1025 req->current = level;
1026 req->saving = saving;
1027 req->period = period;
1028 wine_server_call( req );
1030 SERVER_END_REQ;
1033 /* _save_at_exit [Internal] */
1034 static void _save_at_exit(HKEY hkey,LPCSTR path)
1036 LPCSTR confdir = wine_get_config_dir();
1038 SERVER_START_REQ( save_registry_atexit )
1040 req->hkey = hkey;
1041 wine_server_add_data( req, confdir, strlen(confdir) );
1042 wine_server_add_data( req, path, strlen(path)+1 );
1043 wine_server_call( req );
1045 SERVER_END_REQ;
1048 /* configure save files and start the periodic saving timer [Internal] */
1049 static void _init_registry_saving( HKEY hkey_users_default )
1051 int all;
1052 int period = 0;
1053 WCHAR buffer[20];
1054 static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0};
1055 static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1056 static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1057 static const WCHAR WritetoHomeRegistryFilesW[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1058 static const WCHAR empty_strW[] = { 0 };
1060 all = !PROFILE_GetWineIniBool(registryW, SaveOnlyUpdatedKeysW, 1);
1061 PROFILE_GetWineIniString( registryW, PeriodicSaveW, empty_strW, buffer, 20 );
1062 if (buffer[0]) period = (int)strtolW(buffer, NULL, 10);
1064 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1065 _set_registry_levels(1,!all,period*1000);
1067 if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1))
1069 _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1070 _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1071 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1076 /******************************************************************************
1077 * _allocate_default_keys [Internal]
1078 * Registry initialisation, allocates some default keys.
1080 static void _allocate_default_keys(void) {
1081 HKEY hkey;
1082 char buf[200];
1084 TRACE("(void)\n");
1086 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1087 RegCloseKey(hkey);
1089 /* This was an Open, but since it is called before the real registries
1090 are loaded, it was changed to a Create - MTB 980507*/
1091 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1092 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1093 RegCloseKey(hkey);
1095 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1096 * CurrentVersion
1097 * CurrentBuildNumber
1098 * CurrentType
1099 * string RegisteredOwner
1100 * string RegisteredOrganization
1103 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1104 * string SysContact
1105 * string SysLocation
1106 * SysServices
1108 if (-1!=gethostname(buf,200)) {
1109 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1110 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1111 RegCloseKey(hkey);
1114 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1115 RegCloseKey(hkey);
1118 #define REG_DONTLOAD -1
1119 #define REG_WIN31 0
1120 #define REG_WIN95 1
1121 #define REG_WINNT 2
1123 /* return the type of native registry [Internal] */
1124 static int _get_reg_type(void)
1126 WCHAR windir[MAX_PATHNAME_LEN];
1127 WCHAR tmp[MAX_PATHNAME_LEN];
1128 int ret = REG_WIN31;
1129 static const WCHAR nt_reg_pathW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1130 static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1131 static const WCHAR WineW[] = {'W','i','n','e',0};
1132 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1133 static const WCHAR empty_strW[] = { 0 };
1135 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1137 /* test %windir%/system32/config/system --> winnt */
1138 strcpyW(tmp, windir);
1139 strcatW(tmp, nt_reg_pathW);
1140 if(GetFileAttributesW(tmp) != (DWORD)-1)
1141 ret = REG_WINNT;
1142 else
1144 /* test %windir%/system.dat --> win95 */
1145 strcpyW(tmp, windir);
1146 strcatW(tmp, win9x_reg_pathW);
1147 if(GetFileAttributesW(tmp) != (DWORD)-1)
1148 ret = REG_WIN95;
1151 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, tmp, MAX_PATHNAME_LEN )))
1153 MESSAGE("When you are running with a native NT directory specify\n");
1154 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1155 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1156 ret = REG_DONTLOAD;
1159 return ret;
1162 #define WINE_REG_VER_ERROR -1
1163 #define WINE_REG_VER_1 0
1164 #define WINE_REG_VER_2 1
1165 #define WINE_REG_VER_OLD 2
1166 #define WINE_REG_VER_UNKNOWN 3
1168 /* return the version of wine registry file [Internal] */
1169 static int _get_wine_registry_file_format_version(LPCSTR fn)
1171 FILE *f;
1172 char tmp[50];
1173 int ver;
1175 if ((f=fopen(fn,"rt")) == NULL) {
1176 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1177 return WINE_REG_VER_ERROR;
1180 if (fgets(tmp,50,f) == NULL) {
1181 WARN("Error reading %s: %s\n",fn,strerror(errno));
1182 fclose(f);
1183 return WINE_REG_VER_ERROR;
1185 fclose(f);
1187 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1188 switch (ver) {
1189 case 1:
1190 return WINE_REG_VER_1;
1191 break;
1192 case 2:
1193 return WINE_REG_VER_2;
1194 break;
1195 default:
1196 return WINE_REG_VER_UNKNOWN;
1200 /* load the registry file in wine format [Internal] */
1201 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1203 int file_format;
1205 file_format = _get_wine_registry_file_format_version(fn);
1206 switch (file_format) {
1208 case WINE_REG_VER_1:
1209 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1210 break;
1212 case WINE_REG_VER_2: {
1213 HANDLE file;
1214 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1215 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1217 SERVER_START_REQ( load_registry )
1219 req->hkey = hkey;
1220 req->file = file;
1221 wine_server_call( req );
1223 SERVER_END_REQ;
1224 CloseHandle( file );
1226 break;
1229 case WINE_REG_VER_UNKNOWN:
1230 WARN("Unable to load registry file %s: unknown format.\n",fn);
1231 break;
1233 case WINE_REG_VER_ERROR:
1234 break;
1238 /* generate and return the name of the tmp file and associated stream [Internal] */
1239 static LPSTR _get_tmp_fn(FILE **f)
1241 LPSTR ret;
1242 int tmp_fd,count;
1244 ret = _xmalloc(50);
1245 for (count = 0;;) {
1246 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1247 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1248 if (errno != EEXIST) {
1249 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1250 free(ret);
1251 *f = NULL;
1252 return NULL;
1256 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1257 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1258 close(tmp_fd);
1259 free(ret);
1260 return NULL;
1263 return ret;
1266 /* convert win95 native registry file to wine format [Internal] */
1267 static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level)
1269 int fd;
1270 FILE *f;
1271 DOS_FULL_NAME full_name;
1272 void *base;
1273 LPSTR ret = NULL;
1274 struct stat st;
1276 _w95creg *creg;
1277 _w95rgkn *rgkn;
1278 _w95dke *dke, *root_dke;
1280 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1282 /* map the registry into the memory */
1283 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1284 if ((fstat(fd, &st) == -1)) goto error1;
1285 if (!st.st_size) goto error1;
1286 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1288 /* control signature */
1289 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1290 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1291 debugstr_w(fn));
1292 goto error;
1295 creg = base;
1296 /* load the header (rgkn) */
1297 rgkn = (_w95rgkn*)(creg + 1);
1298 if (rgkn->id != W95_REG_RGKN_ID) {
1299 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1300 goto error;
1302 if (rgkn->root_off != 0x20) {
1303 ERR("rgkn->root_off not 0x20, please report !\n");
1304 goto error;
1306 if (rgkn->last_dke > rgkn->size)
1308 ERR("registry file corrupt! last_dke > size!\n");
1309 goto error;
1311 /* verify last dke */
1312 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1313 if (dke->x1 != 0x80000000)
1314 { /* wrong magic */
1315 ERR("last dke invalid !\n");
1316 goto error;
1318 if (rgkn->size > creg->rgdb_off)
1320 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1321 goto error;
1323 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1324 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1326 ERR("registry file corrupt! invalid root dke !\n");
1327 goto error;
1330 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1331 fprintf(f,"WINE REGISTRY Version 2");
1332 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1333 fclose(f);
1335 error:
1336 if(ret == NULL) {
1337 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn));
1338 ERR("Please report this.\n");
1339 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1342 munmap(base, st.st_size);
1343 error1:
1344 close(fd);
1345 return ret;
1348 /* convert winnt native registry file to wine format [Internal] */
1349 static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level)
1351 FILE *f;
1352 void *base;
1353 LPSTR ret = NULL;
1354 HANDLE hFile;
1355 HANDLE hMapping;
1357 nt_regf *regf;
1358 nt_hbin *hbin;
1359 nt_hbin_sub *hbin_sub;
1360 nt_nk *nk;
1362 TRACE("%s\n", debugstr_w(fn));
1364 hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1365 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1366 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1367 if (!hMapping) goto error1;
1368 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1369 CloseHandle( hMapping );
1370 if (!base) goto error1;
1372 /* control signature */
1373 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1374 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1375 debugstr_w(fn));
1376 goto error;
1379 /* start block */
1380 regf = base;
1382 /* hbin block */
1383 hbin = (nt_hbin*)((char*) base + 0x1000);
1384 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1385 ERR( "hbin block invalid\n");
1386 goto error;
1389 /* hbin_sub block */
1390 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1391 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1392 ERR( "hbin_sub block invalid\n");
1393 goto error;
1396 /* nk block */
1397 nk = (nt_nk*)&(hbin_sub->data[0]);
1398 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1399 ERR( "special nk block not found\n");
1400 goto error;
1403 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1404 fprintf(f,"WINE REGISTRY Version 2");
1405 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1406 fclose(f);
1408 error:
1409 UnmapViewOfFile( base );
1410 error1:
1411 CloseHandle(hFile);
1412 return ret;
1415 /* convert native registry to wine format and load it via server call [Internal] */
1416 static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level)
1418 LPSTR tmp = NULL;
1420 switch (reg_type) {
1421 case REG_WINNT:
1422 /* FIXME: following function doesn't really convert yet */
1423 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1424 break;
1425 case REG_WIN95:
1426 tmp = _convert_win95_registry_to_wine_format(fn,level);
1427 break;
1428 case REG_WIN31:
1429 ERR("Don't know how to convert native 3.1 registry yet.\n");
1430 break;
1431 default:
1432 ERR("Unknown registry format parameter (%d)\n",reg_type);
1433 break;
1436 if (tmp != NULL) {
1437 load_wine_registry(hkey,tmp);
1438 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1439 debugstr_w(fn), tmp);
1440 unlink(tmp);
1442 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn));
1443 free(tmp);
1446 /* load all native windows registry files [Internal] */
1447 static void _load_windows_registry( HKEY hkey_users_default )
1449 int reg_type;
1450 WCHAR windir[MAX_PATHNAME_LEN];
1451 WCHAR path[MAX_PATHNAME_LEN];
1452 static const WCHAR WineW[] = {'W','i','n','e',0};
1453 static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
1454 static const WCHAR empty_strW[] = { 0 };
1456 GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN);
1458 reg_type = _get_reg_type();
1459 switch (reg_type) {
1460 case REG_WINNT: {
1461 HKEY hkey;
1462 static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1463 static const WCHAR defaultW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','d','e','f','a','u','l','t',0};
1464 static const WCHAR systemW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1465 static const WCHAR softwareW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','o','f','t','w','a','r','e',0};
1466 static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1467 static const WCHAR securityW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','e','c','u','r','i','t','y',0};
1469 /* user specific ntuser.dat */
1470 if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
1471 strcatW(path, ntuser_datW);
1472 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1475 /* default user.dat */
1476 if (hkey_users_default) {
1477 strcpyW(path, windir);
1478 strcatW(path, defaultW);
1479 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1483 * FIXME
1484 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1487 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1488 strcpyW(path, windir);
1489 strcatW(path, systemW);
1490 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1491 RegCloseKey(hkey);
1494 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1495 strcpyW(path, windir);
1496 strcatW(path, softwareW);
1497 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1498 RegCloseKey(hkey);
1501 strcpyW(path, windir);
1502 strcatW(path, samW);
1503 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1505 strcpyW(path,windir);
1506 strcatW(path, securityW);
1507 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1509 /* this key is generated when the nt-core booted successfully */
1510 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1511 break;
1514 case REG_WIN95:
1516 static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1517 static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1518 static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1519 static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
1521 _convert_and_load_native_registry(system_1stW,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1523 strcpyW(path, windir);
1524 strcatW(path, system_datW);
1525 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1527 strcpyW(path, windir);
1528 strcatW(path, classes_datW);
1529 _convert_and_load_native_registry(path,HKEY_CLASSES_ROOT,REG_WIN95,0);
1531 if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
1532 /* user specific user.dat */
1533 strcatW(path, user_datW);
1534 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1536 /* default user.dat */
1537 if (hkey_users_default) {
1538 strcpyW(path, windir);
1539 strcatW(path, user_datW);
1540 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1542 } else {
1543 strcpyW(path, windir);
1544 strcatW(path, user_datW);
1545 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1547 break;
1550 case REG_WIN31:
1551 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1552 _w31_loadreg();
1553 break;
1555 case REG_DONTLOAD:
1556 TRACE("REG_DONTLOAD\n");
1557 break;
1559 default:
1560 ERR("switch: no match (%d)\n",reg_type);
1561 break;
1566 /* load global registry files (stored in /etc/wine) [Internal] */
1567 static void _load_global_registry(void)
1569 TRACE("(void)\n");
1571 /* Load the global HKU hive directly from sysconfdir */
1572 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1574 /* Load the global machine defaults directly from sysconfdir */
1575 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1578 /* load home registry files (stored in ~/.wine) [Internal] */
1579 static void _load_home_registry( HKEY hkey_users_default )
1581 LPCSTR confdir = wine_get_config_dir();
1582 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1584 strcpy(tmp,confdir);
1585 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1586 load_wine_registry(hkey_users_default,tmp);
1588 strcpy(tmp,confdir);
1589 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1590 load_wine_registry(HKEY_CURRENT_USER,tmp);
1592 strcpy(tmp,confdir);
1593 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1594 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1596 free(tmp);
1599 /* load all registry (native and global and home) */
1600 void SHELL_LoadRegistry( void )
1602 HKEY hkey_users_default;
1603 static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0};
1604 static const WCHAR load_win_reg_filesW[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1605 static const WCHAR load_global_reg_filesW[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1606 static const WCHAR load_home_reg_filesW[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1608 TRACE("(void)\n");
1610 if (!CLIENT_IsBootThread()) return; /* already loaded */
1612 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1614 ERR("Cannot create HKEY_USERS/.Default\n" );
1615 ExitProcess(1);
1618 _allocate_default_keys();
1619 _set_registry_levels(0,0,0);
1620 if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1))
1621 _load_windows_registry( hkey_users_default );
1622 if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1))
1623 _load_global_registry();
1624 _set_registry_levels(1,0,0);
1625 if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1))
1626 _load_home_registry( hkey_users_default );
1627 _init_registry_saving( hkey_users_default );
1628 RegCloseKey(hkey_users_default);
1631 /***************************************************************************/
1632 /* 16-BIT API FUNCTIONS */
1633 /***************************************************************************/
1635 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1636 * some programs. Do not remove those cases. -MM
1638 static inline void fix_win16_hkey( HKEY *hkey )
1640 if (*hkey == 0 || *hkey == (HKEY)1) *hkey = HKEY_CLASSES_ROOT;
1643 /******************************************************************************
1644 * RegEnumKey [KERNEL.216]
1645 * RegEnumKey [SHELL.7]
1647 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1649 fix_win16_hkey( &hkey );
1650 return RegEnumKeyA( hkey, index, name, name_len );
1653 /******************************************************************************
1654 * RegOpenKey [KERNEL.217]
1655 * RegOpenKey [SHELL.1]
1657 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1659 fix_win16_hkey( &hkey );
1660 return RegOpenKeyA( hkey, name, retkey );
1663 /******************************************************************************
1664 * RegCreateKey [KERNEL.218]
1665 * RegCreateKey [SHELL.2]
1667 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1669 fix_win16_hkey( &hkey );
1670 return RegCreateKeyA( hkey, name, retkey );
1673 /******************************************************************************
1674 * RegDeleteKey [KERNEL.219]
1675 * RegDeleteKey [SHELL.4]
1677 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1679 fix_win16_hkey( &hkey );
1680 return RegDeleteKeyA( hkey, name );
1683 /******************************************************************************
1684 * RegCloseKey [KERNEL.220]
1685 * RegCloseKey [SHELL.3]
1687 DWORD WINAPI RegCloseKey16( HKEY hkey )
1689 fix_win16_hkey( &hkey );
1690 return RegCloseKey( hkey );
1693 /******************************************************************************
1694 * RegSetValue [KERNEL.221]
1695 * RegSetValue [SHELL.5]
1697 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1699 fix_win16_hkey( &hkey );
1700 return RegSetValueA( hkey, name, type, data, count );
1703 /******************************************************************************
1704 * RegDeleteValue [KERNEL.222]
1706 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1708 fix_win16_hkey( &hkey );
1709 return RegDeleteValueA( hkey, name );
1712 /******************************************************************************
1713 * RegEnumValue [KERNEL.223]
1715 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1716 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1718 fix_win16_hkey( &hkey );
1719 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1722 /******************************************************************************
1723 * RegQueryValue [KERNEL.224]
1724 * RegQueryValue [SHELL.6]
1726 * NOTES
1727 * Is this HACK still applicable?
1729 * HACK
1730 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1731 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1732 * Aldus FH4)
1734 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1736 fix_win16_hkey( &hkey );
1737 if (count) *count &= 0xffff;
1738 return RegQueryValueA( hkey, name, data, count );
1741 /******************************************************************************
1742 * RegQueryValueEx [KERNEL.225]
1744 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1745 LPBYTE data, LPDWORD count )
1747 fix_win16_hkey( &hkey );
1748 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1751 /******************************************************************************
1752 * RegSetValueEx [KERNEL.226]
1754 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1755 CONST BYTE *data, DWORD count )
1757 fix_win16_hkey( &hkey );
1758 if (!count && (type==REG_SZ)) count = strlen(data);
1759 return RegSetValueExA( hkey, name, reserved, type, data, count );
1762 /******************************************************************************
1763 * RegFlushKey [KERNEL.227]
1765 DWORD WINAPI RegFlushKey16( HKEY hkey )
1767 fix_win16_hkey( &hkey );
1768 return RegFlushKey( hkey );