Added include protection for unistd.h and sys/time.h.
[wine/multimedia.git] / misc / registry.c
blob093d636737e9337e9a3adb3c1e4dcc98437f1a22
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 char buffer[20];
1055 all = !PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1056 PROFILE_GetWineIniString( "registry", "PeriodicSave", "", buffer, sizeof(buffer) );
1057 if (buffer[0]) period = atoi(buffer);
1059 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1060 _set_registry_levels(1,!all,period*1000);
1062 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1064 _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1065 _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1066 _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1071 /******************************************************************************
1072 * _allocate_default_keys [Internal]
1073 * Registry initialisation, allocates some default keys.
1075 static void _allocate_default_keys(void) {
1076 HKEY hkey;
1077 char buf[200];
1079 TRACE("(void)\n");
1081 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1082 RegCloseKey(hkey);
1084 /* This was an Open, but since it is called before the real registries
1085 are loaded, it was changed to a Create - MTB 980507*/
1086 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1087 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1088 RegCloseKey(hkey);
1090 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1091 * CurrentVersion
1092 * CurrentBuildNumber
1093 * CurrentType
1094 * string RegisteredOwner
1095 * string RegisteredOrganization
1098 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1099 * string SysContact
1100 * string SysLocation
1101 * SysServices
1103 if (-1!=gethostname(buf,200)) {
1104 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1105 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1106 RegCloseKey(hkey);
1109 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1110 RegCloseKey(hkey);
1113 #define REG_DONTLOAD -1
1114 #define REG_WIN31 0
1115 #define REG_WIN95 1
1116 #define REG_WINNT 2
1118 /* return the type of native registry [Internal] */
1119 static int _get_reg_type(void)
1121 char windir[MAX_PATHNAME_LEN];
1122 char tmp[MAX_PATHNAME_LEN];
1123 int ret = REG_WIN31;
1125 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1127 /* test %windir%/system32/config/system --> winnt */
1128 strcpy(tmp, windir);
1129 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1130 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1131 ret = REG_WINNT;
1133 else
1135 /* test %windir%/system.dat --> win95 */
1136 strcpy(tmp, windir);
1137 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1138 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1139 ret = REG_WIN95;
1143 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
1144 MESSAGE("When you are running with a native NT directory specify\n");
1145 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1146 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1147 ret = REG_DONTLOAD;
1150 return ret;
1153 #define WINE_REG_VER_ERROR -1
1154 #define WINE_REG_VER_1 0
1155 #define WINE_REG_VER_2 1
1156 #define WINE_REG_VER_OLD 2
1157 #define WINE_REG_VER_UNKNOWN 3
1159 /* return the version of wine registry file [Internal] */
1160 static int _get_wine_registry_file_format_version(LPCSTR fn)
1162 FILE *f;
1163 char tmp[50];
1164 int ver;
1166 if ((f=fopen(fn,"rt")) == NULL) {
1167 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1168 return WINE_REG_VER_ERROR;
1171 if (fgets(tmp,50,f) == NULL) {
1172 WARN("Error reading %s: %s\n",fn,strerror(errno));
1173 fclose(f);
1174 return WINE_REG_VER_ERROR;
1176 fclose(f);
1178 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1179 switch (ver) {
1180 case 1:
1181 return WINE_REG_VER_1;
1182 break;
1183 case 2:
1184 return WINE_REG_VER_2;
1185 break;
1186 default:
1187 return WINE_REG_VER_UNKNOWN;
1191 /* load the registry file in wine format [Internal] */
1192 static void load_wine_registry(HKEY hkey,LPCSTR fn)
1194 int file_format;
1196 file_format = _get_wine_registry_file_format_version(fn);
1197 switch (file_format) {
1199 case WINE_REG_VER_1:
1200 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1201 break;
1203 case WINE_REG_VER_2: {
1204 HANDLE file;
1205 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1206 FILE_ATTRIBUTE_NORMAL, 0, TRUE, DRIVE_UNKNOWN )))
1208 SERVER_START_REQ( load_registry )
1210 req->hkey = hkey;
1211 req->file = file;
1212 wine_server_call( req );
1214 SERVER_END_REQ;
1215 CloseHandle( file );
1217 break;
1220 case WINE_REG_VER_UNKNOWN:
1221 WARN("Unable to load registry file %s: unknown format.\n",fn);
1222 break;
1224 case WINE_REG_VER_ERROR:
1225 break;
1229 /* generate and return the name of the tmp file and associated stream [Internal] */
1230 static LPSTR _get_tmp_fn(FILE **f)
1232 LPSTR ret;
1233 int tmp_fd,count;
1235 ret = _xmalloc(50);
1236 for (count = 0;;) {
1237 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1238 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1239 if (errno != EEXIST) {
1240 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1241 free(ret);
1242 *f = NULL;
1243 return NULL;
1247 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1248 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1249 close(tmp_fd);
1250 free(ret);
1251 return NULL;
1254 return ret;
1257 /* convert win95 native registry file to wine format [Internal] */
1258 static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1260 int fd;
1261 FILE *f;
1262 DOS_FULL_NAME full_name;
1263 void *base;
1264 LPSTR ret = NULL;
1265 struct stat st;
1267 _w95creg *creg;
1268 _w95rgkn *rgkn;
1269 _w95dke *dke, *root_dke;
1271 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1273 /* map the registry into the memory */
1274 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1275 if ((fstat(fd, &st) == -1)) goto error1;
1276 if (!st.st_size) goto error1;
1277 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1279 /* control signature */
1280 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1281 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1282 goto error;
1285 creg = base;
1286 /* load the header (rgkn) */
1287 rgkn = (_w95rgkn*)(creg + 1);
1288 if (rgkn->id != W95_REG_RGKN_ID) {
1289 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1290 goto error;
1292 if (rgkn->root_off != 0x20) {
1293 ERR("rgkn->root_off not 0x20, please report !\n");
1294 goto error;
1296 if (rgkn->last_dke > rgkn->size)
1298 ERR("registry file corrupt! last_dke > size!\n");
1299 goto error;
1301 /* verify last dke */
1302 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1303 if (dke->x1 != 0x80000000)
1304 { /* wrong magic */
1305 ERR("last dke invalid !\n");
1306 goto error;
1308 if (rgkn->size > creg->rgdb_off)
1310 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1311 goto error;
1313 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1314 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1316 ERR("registry file corrupt! invalid root dke !\n");
1317 goto error;
1320 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1321 fprintf(f,"WINE REGISTRY Version 2");
1322 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1323 fclose(f);
1325 error:
1326 if(ret == NULL) {
1327 ERR("Unable to load native win95 registry file %s.\n",fn);
1328 ERR("Please report this.\n");
1329 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1332 munmap(base, st.st_size);
1333 error1:
1334 close(fd);
1335 return ret;
1338 /* convert winnt native registry file to wine format [Internal] */
1339 static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1341 FILE *f;
1342 void *base;
1343 LPSTR ret = NULL;
1344 HANDLE hFile;
1345 HANDLE hMapping;
1347 nt_regf *regf;
1348 nt_hbin *hbin;
1349 nt_hbin_sub *hbin_sub;
1350 nt_nk *nk;
1352 TRACE("%s\n", fn);
1354 hFile = CreateFileA( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1355 if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
1356 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL );
1357 if (!hMapping) goto error1;
1358 base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1359 CloseHandle( hMapping );
1360 if (!base) goto error1;
1362 /* control signature */
1363 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1364 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1365 goto error;
1368 /* start block */
1369 regf = base;
1371 /* hbin block */
1372 hbin = (nt_hbin*)((char*) base + 0x1000);
1373 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1374 ERR( "hbin block invalid\n");
1375 goto error;
1378 /* hbin_sub block */
1379 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1380 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1381 ERR( "hbin_sub block invalid\n");
1382 goto error;
1385 /* nk block */
1386 nk = (nt_nk*)&(hbin_sub->data[0]);
1387 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1388 ERR( "special nk block not found\n");
1389 goto error;
1392 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1393 fprintf(f,"WINE REGISTRY Version 2");
1394 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1395 fclose(f);
1397 error:
1398 UnmapViewOfFile( base );
1399 error1:
1400 CloseHandle(hFile);
1401 return ret;
1404 /* convert native registry to wine format and load it via server call [Internal] */
1405 static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1407 LPSTR tmp = NULL;
1409 switch (reg_type) {
1410 case REG_WINNT:
1411 /* FIXME: following function doesn't really convert yet */
1412 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1413 break;
1414 case REG_WIN95:
1415 tmp = _convert_win95_registry_to_wine_format(fn,level);
1416 break;
1417 case REG_WIN31:
1418 ERR("Don't know how to convert native 3.1 registry yet.\n");
1419 break;
1420 default:
1421 ERR("Unknown registry format parameter (%d)\n",reg_type);
1422 break;
1425 if (tmp != NULL) {
1426 load_wine_registry(hkey,tmp);
1427 TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp);
1428 unlink(tmp);
1430 else WARN("Unable to convert %s (doesn't exist?)\n",fn);
1431 free(tmp);
1434 /* load all native windows registry files [Internal] */
1435 static void _load_windows_registry( HKEY hkey_users_default )
1437 int reg_type;
1438 char windir[MAX_PATHNAME_LEN];
1439 char path[MAX_PATHNAME_LEN];
1441 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1443 reg_type = _get_reg_type();
1444 switch (reg_type) {
1445 case REG_WINNT: {
1446 HKEY hkey;
1448 /* user specific ntuser.dat */
1449 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1450 strcat(path,"\\ntuser.dat");
1451 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1454 /* default user.dat */
1455 if (hkey_users_default) {
1456 strcpy(path,windir);
1457 strcat(path,"\\system32\\config\\default");
1458 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1462 * FIXME
1463 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1466 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1467 strcpy(path,windir);
1468 strcat(path,"\\system32\\config\\system");
1469 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1470 RegCloseKey(hkey);
1473 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1474 strcpy(path,windir);
1475 strcat(path,"\\system32\\config\\software");
1476 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1477 RegCloseKey(hkey);
1480 strcpy(path,windir);
1481 strcat(path,"\\system32\\config\\sam");
1482 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1484 strcpy(path,windir);
1485 strcat(path,"\\system32\\config\\security");
1486 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1488 /* this key is generated when the nt-core booted successfully */
1489 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1490 break;
1493 case REG_WIN95:
1494 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1496 strcpy(path,windir);
1497 strcat(path,"\\system.dat");
1498 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1500 strcpy(path,windir);
1501 strcat(path,"\\classes.dat");
1502 _convert_and_load_native_registry(path,HKEY_CLASSES_ROOT,REG_WIN95,0);
1504 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1505 /* user specific user.dat */
1506 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1507 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1509 /* default user.dat */
1510 if (hkey_users_default) {
1511 strcpy(path,windir);
1512 strcat(path,"\\user.dat");
1513 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1515 } else {
1516 strcpy(path,windir);
1517 strcat(path,"\\user.dat");
1518 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1520 break;
1522 case REG_WIN31:
1523 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1524 _w31_loadreg();
1525 break;
1527 case REG_DONTLOAD:
1528 TRACE("REG_DONTLOAD\n");
1529 break;
1531 default:
1532 ERR("switch: no match (%d)\n",reg_type);
1533 break;
1538 /* load global registry files (stored in /etc/wine) [Internal] */
1539 static void _load_global_registry(void)
1541 TRACE("(void)\n");
1543 /* Load the global HKU hive directly from sysconfdir */
1544 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1546 /* Load the global machine defaults directly from sysconfdir */
1547 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1550 /* load home registry files (stored in ~/.wine) [Internal] */
1551 static void _load_home_registry( HKEY hkey_users_default )
1553 LPCSTR confdir = wine_get_config_dir();
1554 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1556 strcpy(tmp,confdir);
1557 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1558 load_wine_registry(hkey_users_default,tmp);
1560 strcpy(tmp,confdir);
1561 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1562 load_wine_registry(HKEY_CURRENT_USER,tmp);
1564 strcpy(tmp,confdir);
1565 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1566 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1568 free(tmp);
1571 /* load all registry (native and global and home) */
1572 void SHELL_LoadRegistry( void )
1574 HKEY hkey_users_default;
1576 TRACE("(void)\n");
1578 if (!CLIENT_IsBootThread()) return; /* already loaded */
1580 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1582 ERR("Cannot create HKEY_USERS/.Default\n" );
1583 ExitProcess(1);
1586 _allocate_default_keys();
1587 _set_registry_levels(0,0,0);
1588 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1589 _load_windows_registry( hkey_users_default );
1590 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1591 _load_global_registry();
1592 _set_registry_levels(1,0,0);
1593 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1594 _load_home_registry( hkey_users_default );
1595 _init_registry_saving( hkey_users_default );
1596 RegCloseKey(hkey_users_default);
1599 /***************************************************************************/
1600 /* API FUNCTIONS */
1601 /***************************************************************************/
1603 /******************************************************************************
1604 * RegFlushKey [ADVAPI32.@]
1605 * Immediately writes key to registry.
1606 * Only returns after data has been written to disk.
1608 * FIXME: does it really wait until data is written ?
1610 * PARAMS
1611 * hkey [I] Handle of key to write
1613 * RETURNS
1614 * Success: ERROR_SUCCESS
1615 * Failure: Error code
1617 DWORD WINAPI RegFlushKey( HKEY hkey )
1619 FIXME( "(%x): stub\n", hkey );
1620 return ERROR_SUCCESS;
1624 /******************************************************************************
1625 * RegUnLoadKeyA [ADVAPI32.@]
1627 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1629 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
1630 return ERROR_SUCCESS;
1634 /******************************************************************************
1635 * RegReplaceKeyA [ADVAPI32.@]
1637 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1638 LPCSTR lpOldFile )
1640 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1641 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1642 return ERROR_SUCCESS;
1650 /* 16-bit functions */
1652 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1653 * some programs. Do not remove those cases. -MM
1655 static inline void fix_win16_hkey( HKEY *hkey )
1657 if (*hkey == 0 || *hkey == (HKEY)1) *hkey = HKEY_CLASSES_ROOT;
1660 /******************************************************************************
1661 * RegEnumKey [KERNEL.216]
1662 * RegEnumKey [SHELL.7]
1664 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1666 fix_win16_hkey( &hkey );
1667 return RegEnumKeyA( hkey, index, name, name_len );
1670 /******************************************************************************
1671 * RegOpenKey [KERNEL.217]
1672 * RegOpenKey [SHELL.1]
1674 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1676 fix_win16_hkey( &hkey );
1677 return RegOpenKeyA( hkey, name, retkey );
1680 /******************************************************************************
1681 * RegCreateKey [KERNEL.218]
1682 * RegCreateKey [SHELL.2]
1684 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1686 fix_win16_hkey( &hkey );
1687 return RegCreateKeyA( hkey, name, retkey );
1690 /******************************************************************************
1691 * RegDeleteKey [KERNEL.219]
1692 * RegDeleteKey [SHELL.4]
1694 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1696 fix_win16_hkey( &hkey );
1697 return RegDeleteKeyA( hkey, name );
1700 /******************************************************************************
1701 * RegCloseKey [KERNEL.220]
1702 * RegCloseKey [SHELL.3]
1704 DWORD WINAPI RegCloseKey16( HKEY hkey )
1706 fix_win16_hkey( &hkey );
1707 return RegCloseKey( hkey );
1710 /******************************************************************************
1711 * RegSetValue [KERNEL.221]
1712 * RegSetValue [SHELL.5]
1714 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1716 fix_win16_hkey( &hkey );
1717 return RegSetValueA( hkey, name, type, data, count );
1720 /******************************************************************************
1721 * RegDeleteValue [KERNEL.222]
1723 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1725 fix_win16_hkey( &hkey );
1726 return RegDeleteValueA( hkey, name );
1729 /******************************************************************************
1730 * RegEnumValue [KERNEL.223]
1732 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1733 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1735 fix_win16_hkey( &hkey );
1736 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1739 /******************************************************************************
1740 * RegQueryValue [KERNEL.224]
1741 * RegQueryValue [SHELL.6]
1743 * NOTES
1744 * Is this HACK still applicable?
1746 * HACK
1747 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1748 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1749 * Aldus FH4)
1751 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1753 fix_win16_hkey( &hkey );
1754 if (count) *count &= 0xffff;
1755 return RegQueryValueA( hkey, name, data, count );
1758 /******************************************************************************
1759 * RegQueryValueEx [KERNEL.225]
1761 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1762 LPBYTE data, LPDWORD count )
1764 fix_win16_hkey( &hkey );
1765 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1768 /******************************************************************************
1769 * RegSetValueEx [KERNEL.226]
1771 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1772 CONST BYTE *data, DWORD count )
1774 fix_win16_hkey( &hkey );
1775 if (!count && (type==REG_SZ)) count = strlen(data);
1776 return RegSetValueExA( hkey, name, reserved, type, data, count );
1779 /******************************************************************************
1780 * RegFlushKey [KERNEL.227]
1782 DWORD WINAPI RegFlushKey16( HKEY hkey )
1784 fix_win16_hkey( &hkey );
1785 return RegFlushKey( hkey );