blob: f39da22f98c90ace44399d391a8ab1aeb538e249 [file] [log] [blame]
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001/*
2 * Registry Functions
3 *
4 * Copyright 1996 Marcus Meissner
Alexandre Julliardf90efa91998-06-14 15:24:15 +00005 * Copyright 1998 Matthew Becker
Sylvain St.Germaine5332221999-04-10 16:46:15 +00006 * Copyright 1999 Sylvain St-Germain
Alexandre Julliard02e90081998-01-04 17:49:09 +00007 *
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.
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000011 *
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000012 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
15 *
16 * TODO
17 * Security access
Alexandre Julliardf90efa91998-06-14 15:24:15 +000018 * Option handling
Alexandre Julliard642d3131998-07-12 19:29:36 +000019 * Time for RegEnumKey*, RegQueryInfoKey*
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000020 */
21
Marcus Meissner31b9dab1999-10-24 22:08:33 +000022#include "config.h"
23
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000024#include <stdlib.h>
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000025#include <string.h>
Alexandre Julliard383da682000-02-10 22:15:21 +000026#include <stdio.h>
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000027#include <unistd.h>
Alexandre Julliard8664b891996-04-05 14:58:24 +000028#include <errno.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000029#include <sys/types.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000030#include <sys/stat.h>
Martin Pilka57f8eb72000-12-15 03:22:27 +000031#include <fcntl.h>
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000032#include "winerror.h"
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +000033#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000034#include "heap.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000035#include "debugtools.h"
Marcus Meissner6b9dd2e1999-03-18 17:39:57 +000036#include "options.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000037#include "winreg.h"
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +000038#include "server.h"
Martin Pilka57f8eb72000-12-15 03:22:27 +000039#ifdef HAVE_SYS_MMAN_H
40# include <sys/mman.h>
41#endif
42#include "winnt.h"
43
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000044
Alexandre Julliard383da682000-02-10 22:15:21 +000045DEFAULT_DEBUG_CHANNEL(reg);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000046
Martin Pilka57f8eb72000-12-15 03:22:27 +000047/* FIXME: following defines should be configured global */
48#define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
49#define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000050
51/* relative in ~user/.wine/ : */
Martin Pilka57f8eb72000-12-15 03:22:27 +000052#define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
53#define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
54#define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000055
Martin Pilka57f8eb72000-12-15 03:22:27 +000056/* _xmalloc [Internal] */
57static void *_xmalloc( size_t size )
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +000058{
59 void *res;
Martin Pilka57f8eb72000-12-15 03:22:27 +000060
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +000061 res = malloc (size ? size : 1);
62 if (res == NULL) {
63 WARN("Virtual memory exhausted.\n");
64 exit (1);
65 }
66 return res;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000067}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000068
Martin Pilka57f8eb72000-12-15 03:22:27 +000069/* _strdupnA [Internal] */
70static LPSTR _strdupnA(LPCSTR str,size_t len)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +000071{
72 LPSTR ret;
73
74 if (!str) return NULL;
Martin Pilka57f8eb72000-12-15 03:22:27 +000075 ret = _xmalloc( len + 1 );
Alexandre Julliardad28d392000-07-09 11:20:59 +000076 memcpy( ret, str, len );
Juergen Schmied9e6b1d11999-12-11 23:22:52 +000077 ret[len] = 0x00;
78 return ret;
79}
80
Martin Pilka57f8eb72000-12-15 03:22:27 +000081/* convert ansi string to unicode [Internal] */
82static LPWSTR _strdupnAtoW(LPCSTR strA,size_t lenA)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +000083{
Martin Pilka57f8eb72000-12-15 03:22:27 +000084 LPWSTR ret;
85 size_t lenW;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +000086
Martin Pilka57f8eb72000-12-15 03:22:27 +000087 if (!strA) return NULL;
88 lenW = MultiByteToWideChar(CP_ACP,0,strA,lenA,NULL,0);
89 ret = _xmalloc(lenW*sizeof(WCHAR)+sizeof(WCHAR));
90 MultiByteToWideChar(CP_ACP,0,strA,lenA,ret,lenW);
91 ret[lenW] = 0;
92 return ret;
93}
Juergen Schmied9e6b1d11999-12-11 23:22:52 +000094
Martin Pilka57f8eb72000-12-15 03:22:27 +000095/* dump a Unicode string with proper escaping [Internal] */
96/* FIXME: this code duplicates server/unicode.c */
97static int _dump_strW(const WCHAR *str,size_t len,FILE *f,char escape[2])
98{
99 static const char escapes[32] = ".......abtnvfr.............e....";
100 char buffer[256];
101 LPSTR pos = buffer;
102 int count = 0;
103
104 for (; len; str++, len--)
105 {
106 if (pos > buffer + sizeof(buffer) - 8)
Alexandre Julliardad28d392000-07-09 11:20:59 +0000107 {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000108 fwrite( buffer, pos - buffer, 1, f );
109 count += pos - buffer;
110 pos = buffer;
Alexandre Julliardad28d392000-07-09 11:20:59 +0000111 }
Martin Pilka57f8eb72000-12-15 03:22:27 +0000112 if (*str > 127) /* hex escape */
113 {
114 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
115 pos += sprintf( pos, "\\x%04x", *str );
116 else
117 pos += sprintf( pos, "\\x%x", *str );
118 continue;
119 }
120 if (*str < 32) /* octal or C escape */
121 {
122 if (!*str && len == 1) continue; /* do not output terminating NULL */
123 if (escapes[*str] != '.')
124 pos += sprintf( pos, "\\%c", escapes[*str] );
125 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
126 pos += sprintf( pos, "\\%03o", *str );
127 else
128 pos += sprintf( pos, "\\%o", *str );
129 continue;
130 }
131 if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\';
132 *pos++ = *str;
133 }
134 fwrite( buffer, pos - buffer, 1, f );
135 count += pos - buffer;
136 return count;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000137}
138
Martin Pilka57f8eb72000-12-15 03:22:27 +0000139/* convert ansi string to unicode and dump with proper escaping [Internal] */
140static int _dump_strAtoW(LPCSTR strA,size_t len,FILE *f,char escape[2])
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000141{
Martin Pilka57f8eb72000-12-15 03:22:27 +0000142 WCHAR *strW;
143 int ret;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000144
Martin Pilka57f8eb72000-12-15 03:22:27 +0000145 if (strA == NULL) return 0;
146 strW = _strdupnAtoW(strA,len);
147 ret = _dump_strW(strW,len,f,escape);
148 free(strW);
149 return ret;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000150}
151
Martin Pilka57f8eb72000-12-15 03:22:27 +0000152/* a key value */
153/* FIXME: this code duplicates server/registry.c */
154struct key_value {
155 WCHAR *nameW; /* value name */
156 int type; /* value type */
157 size_t len; /* value data length in bytes */
158 void *data; /* pointer to value data */
159};
160
161/* dump a value to a text file */
162/* FIXME: this code duplicates server/registry.c */
163static void _dump_value(struct key_value *value,FILE *f)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000164{
Martin Pilka57f8eb72000-12-15 03:22:27 +0000165 int i, count;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000166
Martin Pilka57f8eb72000-12-15 03:22:27 +0000167 if (value->nameW[0]) {
168 fputc( '\"', f );
169 count = 1 + _dump_strW(value->nameW,strlenW(value->nameW),f,"\"\"");
170 count += fprintf( f, "\"=" );
171 }
172 else count = fprintf( f, "@=" );
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000173
Martin Pilka57f8eb72000-12-15 03:22:27 +0000174 switch(value->type) {
175 case REG_SZ:
176 case REG_EXPAND_SZ:
177 case REG_MULTI_SZ:
178 if (value->type != REG_SZ) fprintf( f, "str(%d):", value->type );
179 fputc( '\"', f );
180 if (value->data) _dump_strW(value->data,value->len/sizeof(WCHAR),f,"\"\"");
181 fputc( '\"', f );
182 break;
183 case REG_DWORD:
184 if (value->len == sizeof(DWORD)) {
185 DWORD dw;
186 memcpy( &dw, value->data, sizeof(DWORD) );
187 fprintf( f, "dword:%08lx", dw );
188 break;
189 }
190 /* else fall through */
191 default:
192 if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
193 else count += fprintf( f, "hex(%x):", value->type );
194 for (i = 0; i < value->len; i++) {
195 count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
196 if (i < value->len-1) {
197 fputc( ',', f );
198 if (++count > 76) {
199 fprintf( f, "\\\n " );
200 count = 2;
201 }
202 }
203 }
204 break;
205 }
206 fputc( '\n', f );
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000207}
208
Martin Pilka57f8eb72000-12-15 03:22:27 +0000209/******************************************************************/
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000210/* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000211/*
212 reghack - windows 3.11 registry data format demo program.
213
214 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
215 a combined hash table and tree description, and finally a text table.
216
217 The header is obvious from the struct header. The taboff1 and taboff2
218 fields are always 0x20, and their usage is unknown.
219
220 The 8-byte entry table has various entry types.
221
222 tabent[0] is a root index. The second word has the index of the root of
223 the directory.
224 tabent[1..hashsize] is a hash table. The first word in the hash entry is
225 the index of the key/value that has that hash. Data with the same
226 hash value are on a circular list. The other three words in the
227 hash entry are always zero.
228 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
229 entry: dirent and keyent/valent. They are identified by context.
230 tabent[freeidx] is the first free entry. The first word in a free entry
231 is the index of the next free entry. The last has 0 as a link.
232 The other three words in the free list are probably irrelevant.
233
Francois Gouget519346a2000-12-02 20:18:08 +0000234 Entries in text table are preceded by a word at offset-2. This word
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000235 has the value (2*index)+1, where index is the referring keyent/valent
236 entry in the table. I have no suggestion for the 2* and the +1.
237 Following the word, there are N bytes of data, as per the keyent/valent
238 entry length. The offset of the keyent/valent entry is from the start
239 of the text table to the first data byte.
240
241 This information is not available from Microsoft. The data format is
242 deduced from the reg.dat file by me. Mistakes may
243 have been made. I claim no rights and give no guarantees for this program.
244
245 Tor Sjøwall, tor@sn.no
246*/
247
248/* reg.dat header format */
249struct _w31_header {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000250 char cookie[8]; /* 'SHCC3.10' */
251 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
252 unsigned long taboff2; /* offset of index table (??) = 0x20 */
253 unsigned long tabcnt; /* number of entries in index table */
254 unsigned long textoff; /* offset of text part */
255 unsigned long textsize; /* byte size of text part */
256 unsigned short hashsize; /* hash size */
257 unsigned short freeidx; /* free index */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000258};
259
260/* generic format of table entries */
261struct _w31_tabent {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000262 unsigned short w0, w1, w2, w3;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000263};
264
265/* directory tabent: */
266struct _w31_dirent {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000267 unsigned short sibling_idx; /* table index of sibling dirent */
268 unsigned short child_idx; /* table index of child dirent */
269 unsigned short key_idx; /* table index of key keyent */
270 unsigned short value_idx; /* table index of value valent */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000271};
272
273/* key tabent: */
274struct _w31_keyent {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000275 unsigned short hash_idx; /* hash chain index for string */
276 unsigned short refcnt; /* reference count */
277 unsigned short length; /* length of string */
278 unsigned short string_off; /* offset of string in text table */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000279};
280
281/* value tabent: */
282struct _w31_valent {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000283 unsigned short hash_idx; /* hash chain index for string */
284 unsigned short refcnt; /* reference count */
285 unsigned short length; /* length of string */
286 unsigned short string_off; /* offset of string in text table */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000287};
288
Martin Pilka57f8eb72000-12-15 03:22:27 +0000289/* recursive helper function to display a directory tree [Internal] */
290void _w31_dumptree(unsigned short idx,unsigned char *txt,struct _w31_tabent *tab,struct _w31_header *head,HKEY hkey,time_t lastmodified, int level)
291{
292 struct _w31_dirent *dir;
293 struct _w31_keyent *key;
294 struct _w31_valent *val;
295 HKEY subkey = 0;
296 static char tail[400];
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000297
Martin Pilka57f8eb72000-12-15 03:22:27 +0000298 while (idx!=0) {
299 dir=(struct _w31_dirent*)&tab[idx];
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000300
Martin Pilka57f8eb72000-12-15 03:22:27 +0000301 if (dir->key_idx) {
302 key = (struct _w31_keyent*)&tab[dir->key_idx];
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000303
Martin Pilka57f8eb72000-12-15 03:22:27 +0000304 memcpy(tail,&txt[key->string_off],key->length);
305 tail[key->length]='\0';
306 /* all toplevel entries AND the entries in the
307 * toplevel subdirectory belong to \SOFTWARE\Classes
308 */
309 if (!level && !strcmp(tail,".classes")) {
310 _w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
311 idx=dir->sibling_idx;
312 continue;
313 }
314 if (subkey) RegCloseKey( subkey );
315 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
316 /* only add if leaf node or valued node */
317 if (dir->value_idx!=0||dir->child_idx==0) {
318 if (dir->value_idx) {
319 val=(struct _w31_valent*)&tab[dir->value_idx];
320 memcpy(tail,&txt[val->string_off],val->length);
321 tail[val->length]='\0';
322 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
323 }
324 }
325 } else TRACE("strange: no directory key name, idx=%04x\n", idx);
326 _w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
327 idx=dir->sibling_idx;
328 }
329 if (subkey) RegCloseKey( subkey );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000330}
331
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000332
333/******************************************************************************
334 * _w31_loadreg [Internal]
335 */
Martin Pilka57f8eb72000-12-15 03:22:27 +0000336void _w31_loadreg(void)
337{
338 HFILE hf;
339 struct _w31_header head;
340 struct _w31_tabent *tab;
341 unsigned char *txt;
342 unsigned int len;
343 OFSTRUCT ofs;
344 BY_HANDLE_FILE_INFORMATION hfinfo;
345 time_t lastmodified;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000346
Martin Pilka57f8eb72000-12-15 03:22:27 +0000347 TRACE("(void)\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000348
Martin Pilka57f8eb72000-12-15 03:22:27 +0000349 hf = OpenFile("reg.dat",&ofs,OF_READ);
350 if (hf==HFILE_ERROR) return;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000351
Martin Pilka57f8eb72000-12-15 03:22:27 +0000352 /* read & dump header */
353 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
354 ERR("reg.dat is too short.\n");
355 _lclose(hf);
356 return;
357 }
358 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
359 ERR("reg.dat has bad signature.\n");
360 _lclose(hf);
361 return;
362 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000363
Martin Pilka57f8eb72000-12-15 03:22:27 +0000364 len = head.tabcnt * sizeof(struct _w31_tabent);
365 /* read and dump index table */
366 tab = _xmalloc(len);
367 if (len!=_lread(hf,tab,len)) {
368 ERR("couldn't read %d bytes.\n",len);
369 free(tab);
370 _lclose(hf);
371 return;
372 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000373
Martin Pilka57f8eb72000-12-15 03:22:27 +0000374 /* read text */
375 txt = _xmalloc(head.textsize);
376 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
377 ERR("couldn't seek to textblock.\n");
378 free(tab);
379 free(txt);
380 _lclose(hf);
381 return;
382 }
383 if (head.textsize!=_lread(hf,txt,head.textsize)) {
384 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
385 free(tab);
386 free(txt);
387 _lclose(hf);
388 return;
389 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000390
Martin Pilka57f8eb72000-12-15 03:22:27 +0000391 if (!GetFileInformationByHandle(hf,&hfinfo)) {
392 ERR("GetFileInformationByHandle failed?.\n");
393 free(tab);
394 free(txt);
395 _lclose(hf);
396 return;
397 }
398 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
399 _w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
400 free(tab);
401 free(txt);
402 _lclose(hf);
403 return;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000404}
405
Martin Pilka57f8eb72000-12-15 03:22:27 +0000406/***********************************************************************************/
407/* windows 95 registry loader */
408/***********************************************************************************/
Alexandre Julliardc9709042000-04-16 17:21:13 +0000409
Martin Pilka57f8eb72000-12-15 03:22:27 +0000410/* SECTION 1: main header
411 *
412 * once at offset 0
413 */
414#define W95_REG_CREG_ID 0x47455243
415
416typedef struct {
417 DWORD id; /* "CREG" = W95_REG_CREG_ID */
418 DWORD version; /* ???? 0x00010000 */
419 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
420 DWORD uk2; /* 0x0c */
421 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
422 WORD uk3;
423 DWORD uk[3];
424 /* rgkn */
425} _w95creg;
426
427/* SECTION 2: Directory information (tree structure)
428 *
429 * once on offset 0x20
430 *
431 * structure: [rgkn][dke]* (repeat till last_dke is reached)
432 */
433#define W95_REG_RGKN_ID 0x4e4b4752
434
435typedef struct {
436 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
437 DWORD size; /* Size of the RGKN-block */
438 DWORD root_off; /* Rel. Offset of the root-record */
439 DWORD last_dke; /* Offset to last DKE ? */
440 DWORD uk[4];
441} _w95rgkn;
442
443/* Disk Key Entry Structure
444 *
445 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
446 * hive itself. It looks the same like other keys. Even the ID-number can
447 * be any value.
448 *
449 * The "hash"-value is a value representing the key's name. Windows will not
450 * search for the name, but for a matching hash-value. if it finds one, it
451 * will compare the actual string info, otherwise continue with the next key.
452 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
453 * of the string which are smaller than 0x80 (128) to this D-Word.
454 *
455 * If you want to modify key names, also modify the hash-values, since they
456 * cannot be found again (although they would be displayed in REGEDIT)
457 * End of list-pointers are filled with 0xFFFFFFFF
458 *
459 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
460 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
461 * structure) and reading another RGDB_section.
462 *
463 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
464 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
465 * The remaining space between last_dke and the offset calculated from
466 * rgkn->size seems to be free for use for more dke:s.
467 * So it seems if more dke:s are added, they are added to that space and
468 * last_dke is grown, and in case that "free" space is out, the space
469 * gets grown and rgkn->size gets adjusted.
470 *
471 * there is a one to one relationship between dke and dkh
472 */
473 /* key struct, once per key */
474typedef struct {
475 DWORD x1; /* Free entry indicator(?) */
476 DWORD hash; /* sum of bytes of keyname */
477 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
478 DWORD prevlvl; /* offset of previous key */
479 DWORD nextsub; /* offset of child key */
480 DWORD next; /* offset of sibling key */
481 WORD nrLS; /* id inside the rgdb block */
482 WORD nrMS; /* number of the rgdb block */
483} _w95dke;
484
485/* SECTION 3: key information, values and data
486 *
487 * structure:
488 * section: [blocks]* (repeat creg->rgdb_num times)
489 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
490 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
491 *
492 * An interesting relationship exists in RGDB_section. The DWORD value
493 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
494 * I have no idea at the moment what this means. (Kevin Cozens)
495 */
496
497/* block header, once per block */
498#define W95_REG_RGDB_ID 0x42444752
499
500typedef struct {
501 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
502 DWORD size; /* 0x04 */
503 DWORD uk1; /* 0x08 */
504 DWORD uk2; /* 0x0c */
505 DWORD uk3; /* 0x10 */
506 DWORD uk4; /* 0x14 */
507 DWORD uk5; /* 0x18 */
508 DWORD uk6; /* 0x1c */
509 /* dkh */
510} _w95rgdb;
511
512/* Disk Key Header structure (RGDB part), once per key */
513typedef struct {
514 DWORD nextkeyoff; /* 0x00 offset to next dkh */
515 WORD nrLS; /* 0x04 id inside the rgdb block */
516 WORD nrMS; /* 0x06 number of the rgdb block */
517 DWORD bytesused; /* 0x08 */
518 WORD keynamelen; /* 0x0c len of name */
519 WORD values; /* 0x0e number of values */
520 DWORD xx1; /* 0x10 */
521 char name[1]; /* 0x14 */
522 /* dkv */ /* 0x14 + keynamelen */
523} _w95dkh;
524
525/* Disk Key Value structure, once per value */
526typedef struct {
527 DWORD type; /* 0x00 */
528 DWORD x1; /* 0x04 */
529 WORD valnamelen; /* 0x08 length of name, 0 is default key */
530 WORD valdatalen; /* 0x0A length of data */
531 char name[1]; /* 0x0c */
532 /* raw data */ /* 0x0c + valnamelen */
533} _w95dkv;
534
535/******************************************************************************
536 * _w95_lookup_dkh [Internal]
537 *
538 * seeks the dkh belonging to a dke
539 */
540static _w95dkh *_w95_lookup_dkh(_w95creg *creg,int nrLS,int nrMS)
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000541{
Martin Pilka57f8eb72000-12-15 03:22:27 +0000542 _w95rgdb * rgdb;
543 _w95dkh * dkh;
544 int i;
545
546 /* get the beginning of the rgdb datastore */
547 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
548
549 /* check: requested block < last_block) */
550 if (creg->rgdb_num <= nrMS) {
551 ERR("registry file corrupt! requested block no. beyond end.\n");
552 goto error;
553 }
554
555 /* find the right block */
556 for(i=0; i<nrMS ;i++) {
557 if(rgdb->id != W95_REG_RGDB_ID) { /* check the magic */
558 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
559 goto error;
560 }
561 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
562 }
563
564 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
565
566 do {
567 if(nrLS==dkh->nrLS ) return dkh;
568 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
569 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
570
571error:
572 return NULL;
573}
574
575/******************************************************************************
576 * _w95_dump_dkv [Internal]
577 */
578static int _w95_dump_dkv(_w95dkh *dkh,int nrLS,int nrMS,FILE *f)
579{
580 _w95dkv * dkv;
581 int i;
582
583 /* first value block */
584 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
585
Andreas Mohr99f2f392001-06-22 23:21:47 +0000586 /* loop through the values */
Martin Pilka57f8eb72000-12-15 03:22:27 +0000587 for (i=0; i< dkh->values; i++) {
588 struct key_value value;
589 WCHAR *pdata;
590
591 value.nameW = _strdupnAtoW(dkv->name,dkv->valnamelen);
592 value.type = dkv->type;
593 value.len = dkv->valdatalen;
594
595 value.data = &(dkv->name[dkv->valnamelen]);
596 pdata = NULL;
597 if ( (value.type==REG_SZ) || (value.type==REG_EXPAND_SZ) || (value.type==REG_MULTI_SZ) ) {
598 pdata = _strdupnAtoW(value.data,value.len);
599 value.len *= 2;
600 }
601 if (pdata != NULL) value.data = pdata;
602
603 _dump_value(&value,f);
604 free(value.nameW);
605 if (pdata != NULL) free(pdata);
606
607 /* next value */
608 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
609 }
610 return TRUE;
611}
612
613/******************************************************************************
614 * _w95_dump_dke [Internal]
615 */
616static int _w95_dump_dke(LPSTR key_name,_w95creg *creg,_w95rgkn *rgkn,_w95dke *dke,FILE *f,int level)
617{
618 _w95dkh * dkh;
619 LPSTR new_key_name = NULL;
620
621 /* special root key */
622 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000623 {
Martin Pilka57f8eb72000-12-15 03:22:27 +0000624 /* parse the one subkey */
625 if (dke->nextsub != 0xffffffff) return _w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level);
626 /* has no sibling keys */
627 return FALSE;
628 }
629
630 /* search subblock */
631 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS))) {
632 ERR("dke pointing to missing dkh !\n");
633 return FALSE;
634 }
635
636 if (level <= 0) {
637 /* create new subkey name */
638 new_key_name = _strdupnA(key_name,strlen(key_name)+dkh->keynamelen+1);
639 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
640 strncat(new_key_name,dkh->name,dkh->keynamelen);
641
642 /* walk sibling keys */
643 if (dke->next != 0xffffffff ) {
644 if (!_w95_dump_dke(key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next),f,level)) {
645 free(new_key_name);
646 return FALSE;
647 }
648 }
649
650 /* write the key path (something like [Software\\Microsoft\\..]) only if:
651 1) key has some values
652 2) key has no values and no subkeys
653 */
654 if (dkh->values > 0) {
655 /* there are some values */
656 fprintf(f,"\n[");
657 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
658 fprintf(f,"]\n");
659 if (!_w95_dump_dkv(dkh, dke->nrLS, dke->nrMS,f)) {
660 free(new_key_name);
661 return FALSE;
662 }
663 }
664 if ((dke->nextsub == 0xffffffff) && (dkh->values == 0)) {
665 /* no subkeys and no values */
666 fprintf(f,"\n[");
667 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
668 fprintf(f,"]\n");
669 }
670 } else new_key_name = _strdupnA(key_name,strlen(key_name));
671
672 /* next sub key */
673 if (dke->nextsub != 0xffffffff) {
674 if (!_w95_dump_dke(new_key_name, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub),f,level-1)) {
675 free(new_key_name);
676 return FALSE;
677 }
678 }
679
680 free(new_key_name);
681 return TRUE;
682}
683/* end windows 95 loader */
684
685/***********************************************************************************/
686/* windows NT registry loader */
687/***********************************************************************************/
688
689/* NT REGISTRY LOADER */
690
691#ifdef HAVE_SYS_MMAN_H
692# include <sys/mman.h>
693#endif
694
695#ifndef MAP_FAILED
696#define MAP_FAILED ((LPVOID)-1)
697#endif
698
699#define NT_REG_BLOCK_SIZE 0x1000
700
701#define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
702#define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
703#define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
704#define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
705
706/* subblocks of nk */
707#define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
708#define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
709#define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
710
711#define NT_REG_KEY_BLOCK_TYPE 0x20
712#define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
713
714typedef struct {
715 DWORD id; /* 0x66676572 'regf'*/
716 DWORD uk1; /* 0x04 */
717 DWORD uk2; /* 0x08 */
718 FILETIME DateModified; /* 0x0c */
719 DWORD uk3; /* 0x14 */
720 DWORD uk4; /* 0x18 */
721 DWORD uk5; /* 0x1c */
722 DWORD uk6; /* 0x20 */
723 DWORD RootKeyBlock; /* 0x24 */
724 DWORD BlockSize; /* 0x28 */
725 DWORD uk7[116];
726 DWORD Checksum; /* at offset 0x1FC */
727} nt_regf;
728
729typedef struct {
730 DWORD blocksize;
731 BYTE data[1];
732} nt_hbin_sub;
733
734typedef struct {
735 DWORD id; /* 0x6E696268 'hbin' */
736 DWORD off_prev;
737 DWORD off_next;
738 DWORD uk1;
739 DWORD uk2; /* 0x10 */
740 DWORD uk3; /* 0x14 */
741 DWORD uk4; /* 0x18 */
742 DWORD size; /* 0x1C */
743 nt_hbin_sub hbin_sub; /* 0x20 */
744} nt_hbin;
745
746/*
747 * the value_list consists of offsets to the values (vk)
748 */
749typedef struct {
750 WORD SubBlockId; /* 0x00 0x6B6E */
751 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
752 FILETIME writetime; /* 0x04 */
753 DWORD uk1; /* 0x0C */
754 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
755 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
756 DWORD uk8; /* 0x18 */
757 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
758 DWORD uk2; /* 0x20 */
759 DWORD nr_values; /* 0x24 number of values */
760 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
761 DWORD off_sk; /* 0x2c Offset of the sk-Record */
762 DWORD off_class; /* 0x30 Offset of the Class-Name */
763 DWORD uk3; /* 0x34 */
764 DWORD uk4; /* 0x38 */
765 DWORD uk5; /* 0x3c */
766 DWORD uk6; /* 0x40 */
767 DWORD uk7; /* 0x44 */
768 WORD name_len; /* 0x48 name-length */
769 WORD class_len; /* 0x4a class-name length */
770 char name[1]; /* 0x4c key-name */
771} nt_nk;
772
773typedef struct {
774 DWORD off_nk; /* 0x00 */
775 DWORD name; /* 0x04 */
776} hash_rec;
777
778typedef struct {
779 WORD id; /* 0x00 0x666c */
780 WORD nr_keys; /* 0x06 */
781 hash_rec hash_rec[1];
782} nt_lf;
783
784/*
785 list of subkeys without hash
786
787 li --+-->nk
788 |
789 +-->nk
790 */
791typedef struct {
792 WORD id; /* 0x00 0x696c */
793 WORD nr_keys;
794 DWORD off_nk[1];
795} nt_li;
796
797/*
798 this is a intermediate node
799
800 ri --+-->li--+-->nk
801 | +
802 | +-->nk
803 |
804 +-->li--+-->nk
805 +
806 +-->nk
807 */
808typedef struct {
809 WORD id; /* 0x00 0x6972 */
810 WORD nr_li; /* 0x02 number off offsets */
811 DWORD off_li[1]; /* 0x04 points to li */
812} nt_ri;
813
814typedef struct {
815 WORD id; /* 0x00 'vk' */
816 WORD nam_len;
817 DWORD data_len;
818 DWORD data_off;
819 DWORD type;
820 WORD flag;
821 WORD uk1;
822 char name[1];
823} nt_vk;
824
825/*
826 * gets a value
827 *
828 * vk->flag:
829 * 0 value is a default value
830 * 1 the value has a name
831 *
832 * vk->data_len
833 * len of the whole data block
834 * - reg_sz (unicode)
835 * bytes including the terminating \0 = 2*(number_of_chars+1)
836 * - reg_dword, reg_binary:
837 * if highest bit of data_len is set data_off contains the value
838 */
839static int _nt_dump_vk(LPSTR key_name, char *base, nt_vk *vk,FILE *f)
840{
841 BYTE *pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
842 struct key_value value;
843
844 if (vk->id != NT_REG_VALUE_BLOCK_ID) {
845 ERR("unknown block found (0x%04x), please report!\n", vk->id);
846 return FALSE;
847 }
848
849 value.nameW = _strdupnAtoW(vk->name,vk->nam_len);
850 value.type = vk->type;
851 value.len = (vk->data_len & 0x7fffffff);
852 value.data = (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata;
853
854 _dump_value(&value,f);
855 free(value.nameW);
856
857 return TRUE;
858}
859
860/* it's called from _nt_dump_lf() */
861static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level);
862
863/*
864 * get the subkeys
865 *
866 * this structure contains the hash of a keyname and points to all
867 * subkeys
868 *
869 * exception: if the id is 'il' there are no hash values and every
870 * dword is a offset
871 */
872static int _nt_dump_lf(LPSTR key_name, char *base, int subkeys, nt_lf *lf, FILE *f, int level)
873{
874 int i;
875
876 if (lf->id == NT_REG_HASH_BLOCK_ID) {
877 if (subkeys != lf->nr_keys) goto error1;
878
879 for (i=0; i<lf->nr_keys; i++)
880 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), f, level)) goto error;
881 } else if (lf->id == NT_REG_NOHASH_BLOCK_ID) {
882 nt_li * li = (nt_li*)lf;
883 if (subkeys != li->nr_keys) goto error1;
884
885 for (i=0; i<li->nr_keys; i++)
886 if (!_nt_dump_nk(key_name, base, (nt_nk*)(base+li->off_nk[i]+4), f, level)) goto error;
887 } else if (lf->id == NT_REG_RI_BLOCK_ID) { /* ri */
888 nt_ri * ri = (nt_ri*)lf;
889 int li_subkeys = 0;
890
891 /* count all subkeys */
892 for (i=0; i<ri->nr_li; i++) {
893 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
894 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
895 li_subkeys += li->nr_keys;
896 }
897
898 /* check number */
899 if (subkeys != li_subkeys) goto error1;
900
901 /* loop through the keys */
902 for (i=0; i<ri->nr_li; i++) {
903 nt_li *li = (nt_li*)(base+ri->off_li[i]+4);
904 if (!_nt_dump_lf(key_name, base, li->nr_keys, (nt_lf*)li, f, level)) goto error;
905 }
906 } else goto error2;
907
908 return TRUE;
909
910error2:
911 ERR("unknown node id 0x%04x, please report!\n", lf->id);
912 return TRUE;
913
914error1:
915 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
916 return FALSE;
917
918error:
919 ERR("error reading lf block\n");
920 return FALSE;
921}
922
923/* _nt_dump_nk [Internal] */
924static int _nt_dump_nk(LPSTR key_name,char *base,nt_nk *nk,FILE *f,int level)
925{
926 unsigned int n;
927 DWORD *vl;
928 LPSTR new_key_name = NULL;
929
930
931 if (nk->SubBlockId != NT_REG_KEY_BLOCK_ID) {
932 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
933 return FALSE;
934 }
935
936 if ((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) && (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) {
937 ERR("registry file corrupt!\n");
938 return FALSE;
939 }
940
941 /* create the new key */
942 if (level <= 0) {
943 /* create new subkey name */
944 new_key_name = _strdupnA(key_name,strlen(key_name)+nk->name_len+1);
945 if (strcmp(new_key_name,"") != 0) strcat(new_key_name,"\\");
946 strncat(new_key_name,nk->name,nk->name_len);
947
948 /* write the key path (something like [Software\\Microsoft\\..]) only if:
949 1) key has some values
950 2) key has no values and no subkeys
951 */
952 if (nk->nr_values > 0) {
953 /* there are some values */
954 fprintf(f,"\n[");
955 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
956 fprintf(f,"]\n");
957 }
958 if ((nk->nr_subkeys == 0) && (nk->nr_values == 0)) {
959 /* no subkeys and no values */
960 fprintf(f,"\n[");
961 _dump_strAtoW(new_key_name,strlen(new_key_name),f,"[]");
962 fprintf(f,"]\n");
963 }
964
965 /* loop trough the value list */
966 vl = (DWORD *)(base+nk->valuelist_off+4);
967 for (n=0; n<nk->nr_values; n++) {
968 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
969 if (!_nt_dump_vk(new_key_name, base, vk, f)) {
970 free(new_key_name);
971 return FALSE;
972 }
973 }
974 } else new_key_name = _strdupnA(key_name,strlen(key_name));
975
976 /* loop through the subkeys */
977 if (nk->nr_subkeys) {
978 nt_lf *lf = (nt_lf*)(base+nk->lf_off+4);
979 if (!_nt_dump_lf(new_key_name, base, nk->nr_subkeys, lf, f, level-1)) {
980 free(new_key_name);
981 return FALSE;
982 }
983 }
984
985 free(new_key_name);
986 return TRUE;
987}
988
989/* end nt loader */
990
991/**********************************************************************************
992 * _set_registry_levels [Internal]
993 *
994 * set level to 0 for loading system files
995 * set level to 1 for loading user files
996 */
997static void _set_registry_levels(int level,int saving,int period)
998{
Alexandre Julliard67a74992001-02-27 02:09:16 +0000999 SERVER_START_REQ( set_registry_levels )
Martin Pilka57f8eb72000-12-15 03:22:27 +00001000 {
Martin Pilka57f8eb72000-12-15 03:22:27 +00001001 req->current = level;
1002 req->saving = saving;
1003 req->period = period;
Alexandre Julliard67a74992001-02-27 02:09:16 +00001004 SERVER_CALL();
Martin Pilka57f8eb72000-12-15 03:22:27 +00001005 }
1006 SERVER_END_REQ;
1007}
1008
1009/* _save_at_exit [Internal] */
1010static void _save_at_exit(HKEY hkey,LPCSTR path)
1011{
1012 LPCSTR confdir = get_config_dir();
1013 size_t len = strlen(confdir) + strlen(path) + 2;
1014
1015 if (len > REQUEST_MAX_VAR_SIZE) {
Alexandre Julliard57f05e12000-10-15 00:40:25 +00001016 ERR( "config dir '%s' too long\n", confdir );
1017 return;
1018 }
Alexandre Julliard67a74992001-02-27 02:09:16 +00001019 SERVER_START_VAR_REQ( save_registry_atexit, len )
Alexandre Julliard57f05e12000-10-15 00:40:25 +00001020 {
Alexandre Julliard57f05e12000-10-15 00:40:25 +00001021 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1022 req->hkey = hkey;
Alexandre Julliard67a74992001-02-27 02:09:16 +00001023 SERVER_CALL();
Alexandre Julliard57f05e12000-10-15 00:40:25 +00001024 }
Alexandre Julliard67a74992001-02-27 02:09:16 +00001025 SERVER_END_VAR_REQ;
Alexandre Julliard57f05e12000-10-15 00:40:25 +00001026}
1027
Martin Pilka57f8eb72000-12-15 03:22:27 +00001028/* configure save files and start the periodic saving timer [Internal] */
1029static void _init_registry_saving( HKEY hkey_users_default )
Alexandre Julliardc9709042000-04-16 17:21:13 +00001030{
Martin Pilka57f8eb72000-12-15 03:22:27 +00001031 int all;
1032 int period;
1033
1034 all = PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1035 period = PROFILE_GetWineIniInt("registry","PeriodicSave",0);
Alexandre Julliardc9709042000-04-16 17:21:13 +00001036
1037 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
Martin Pilka57f8eb72000-12-15 03:22:27 +00001038 _set_registry_levels(1,!all,period*1000);
Alexandre Julliardc9709042000-04-16 17:21:13 +00001039
Martin Pilkaac0b8142001-01-26 21:00:48 +00001040 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
Alexandre Julliardc9709042000-04-16 17:21:13 +00001041 {
Martin Pilka57f8eb72000-12-15 03:22:27 +00001042 _save_at_exit(HKEY_CURRENT_USER,SAVE_LOCAL_REGBRANCH_CURRENT_USER );
1043 _save_at_exit(HKEY_LOCAL_MACHINE,SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1044 _save_at_exit(hkey_users_default,SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
Alexandre Julliardc9709042000-04-16 17:21:13 +00001045 }
Martin Pilka57f8eb72000-12-15 03:22:27 +00001046
Alexandre Julliardc9709042000-04-16 17:21:13 +00001047}
1048
Martin Pilka57f8eb72000-12-15 03:22:27 +00001049/******************************************************************************
1050 * _allocate_default_keys [Internal]
1051 * Registry initialisation, allocates some default keys.
Juergen Schmied271ba292000-01-15 23:42:50 +00001052 */
Martin Pilka57f8eb72000-12-15 03:22:27 +00001053static void _allocate_default_keys(void) {
1054 HKEY hkey;
1055 char buf[200];
Juergen Schmied271ba292000-01-15 23:42:50 +00001056
Martin Pilka57f8eb72000-12-15 03:22:27 +00001057 TRACE("(void)\n");
1058
1059 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
1060 RegCloseKey(hkey);
1061
1062 /* This was an Open, but since it is called before the real registries
1063 are loaded, it was changed to a Create - MTB 980507*/
1064 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
1065 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
1066 RegCloseKey(hkey);
1067
1068 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1069 * CurrentVersion
1070 * CurrentBuildNumber
1071 * CurrentType
1072 * string RegisteredOwner
1073 * string RegisteredOrganization
1074 *
1075 */
1076 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1077 * string SysContact
1078 * string SysLocation
1079 * SysServices
1080 */
1081 if (-1!=gethostname(buf,200)) {
1082 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
1083 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
1084 RegCloseKey(hkey);
1085 }
1086
1087 RegCreateKeyA(HKEY_USERS,".Default",&hkey);
1088 RegCloseKey(hkey);
Juergen Schmied271ba292000-01-15 23:42:50 +00001089}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001090
Juergen Schmied8573cc72000-01-30 03:03:23 +00001091#define REG_DONTLOAD -1
Martin Pilka57f8eb72000-12-15 03:22:27 +00001092#define REG_WIN31 0
1093#define REG_WIN95 1
1094#define REG_WINNT 2
Juergen Schmied8573cc72000-01-30 03:03:23 +00001095
Martin Pilka57f8eb72000-12-15 03:22:27 +00001096/* return the type of native registry [Internal] */
1097static int _get_reg_type(void)
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001098{
Martin Pilka57f8eb72000-12-15 03:22:27 +00001099 char windir[MAX_PATHNAME_LEN];
1100 char tmp[MAX_PATHNAME_LEN];
1101 int ret = REG_WIN31;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001102
Martin Pilka57f8eb72000-12-15 03:22:27 +00001103 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001104
Juergen Schmied8573cc72000-01-30 03:03:23 +00001105 /* test %windir%/system32/config/system --> winnt */
Martin Pilka57f8eb72000-12-15 03:22:27 +00001106 strcpy(tmp, windir);
1107 strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1108 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1109 ret = REG_WINNT;
Juergen Schmied8573cc72000-01-30 03:03:23 +00001110 }
1111 else
1112 {
1113 /* test %windir%/system.dat --> win95 */
Martin Pilka57f8eb72000-12-15 03:22:27 +00001114 strcpy(tmp, windir);
1115 strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1);
1116 if(GetFileAttributesA(tmp) != (DWORD)-1) {
1117 ret = REG_WIN95;
Juergen Schmied8573cc72000-01-30 03:03:23 +00001118 }
1119 }
1120
Martin Pilka57f8eb72000-12-15 03:22:27 +00001121 if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) {
Juergen Schmied8573cc72000-01-30 03:03:23 +00001122 MESSAGE("When you are running with a native NT directory specify\n");
1123 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1124 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
Martin Pilka57f8eb72000-12-15 03:22:27 +00001125 ret = REG_DONTLOAD;
Juergen Schmied8573cc72000-01-30 03:03:23 +00001126 }
Juergen Schmied8573cc72000-01-30 03:03:23 +00001127
Martin Pilka57f8eb72000-12-15 03:22:27 +00001128 return ret;
Alexandre Julliardfe085682000-03-18 21:56:10 +00001129}
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001130
Martin Pilka57f8eb72000-12-15 03:22:27 +00001131#define WINE_REG_VER_ERROR -1
1132#define WINE_REG_VER_1 0
1133#define WINE_REG_VER_2 1
1134#define WINE_REG_VER_OLD 2
1135#define WINE_REG_VER_UNKNOWN 3
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001136
Martin Pilka57f8eb72000-12-15 03:22:27 +00001137/* return the version of wine registry file [Internal] */
1138static int _get_wine_registry_file_format_version(LPCSTR fn)
1139{
1140 FILE *f;
1141 char tmp[50];
1142 int ver;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001143
Martin Pilka57f8eb72000-12-15 03:22:27 +00001144 if ((f=fopen(fn,"rt")) == NULL) {
1145 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno));
1146 return WINE_REG_VER_ERROR;
1147 }
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001148
Martin Pilka57f8eb72000-12-15 03:22:27 +00001149 if (fgets(tmp,50,f) == NULL) {
1150 WARN("Error reading %s: %s\n",fn,strerror(errno));
1151 fclose(f);
1152 return WINE_REG_VER_ERROR;
1153 }
1154 fclose(f);
1155
1156 if (sscanf(tmp,"WINE REGISTRY Version %d",&ver) != 1) return WINE_REG_VER_UNKNOWN;
1157 switch (ver) {
1158 case 1:
1159 return WINE_REG_VER_1;
1160 break;
1161 case 2:
1162 return WINE_REG_VER_2;
1163 break;
1164 default:
1165 return WINE_REG_VER_UNKNOWN;
1166 }
1167}
1168
1169/* load the registry file in wine format [Internal] */
1170static void load_wine_registry(HKEY hkey,LPCSTR fn)
1171{
1172 int file_format;
1173
1174 file_format = _get_wine_registry_file_format_version(fn);
1175 switch (file_format) {
1176
1177 case WINE_REG_VER_1:
1178 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn);
1179 break;
1180
1181 case WINE_REG_VER_2: {
1182 HANDLE file;
1183 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
Alexandre Julliard8081e5a2001-01-05 04:08:07 +00001184 FILE_ATTRIBUTE_NORMAL, 0, TRUE )))
Martin Pilka57f8eb72000-12-15 03:22:27 +00001185 {
Alexandre Julliard67a74992001-02-27 02:09:16 +00001186 SERVER_START_REQ( load_registry )
Martin Pilka57f8eb72000-12-15 03:22:27 +00001187 {
Martin Pilka57f8eb72000-12-15 03:22:27 +00001188 req->hkey = hkey;
1189 req->file = file;
Alexandre Julliard67a74992001-02-27 02:09:16 +00001190 SERVER_CALL();
Martin Pilka57f8eb72000-12-15 03:22:27 +00001191 }
1192 SERVER_END_REQ;
1193 CloseHandle( file );
1194 }
1195 break;
1196 }
1197
1198 case WINE_REG_VER_UNKNOWN:
1199 WARN("Unable to load registry file %s: unknown format.\n",fn);
1200 break;
1201
1202 case WINE_REG_VER_ERROR:
1203 break;
1204 }
1205}
1206
1207/* generate and return the name of the tmp file and associated stream [Internal] */
1208static LPSTR _get_tmp_fn(FILE **f)
1209{
1210 LPSTR ret;
1211 int tmp_fd,count;
1212
1213 ret = _xmalloc(50);
1214 for (count = 0;;) {
1215 sprintf(ret,"/tmp/reg%lx%04x.tmp",(long)getpid(),count++);
1216 if ((tmp_fd = open(ret,O_CREAT | O_EXCL | O_WRONLY,0666)) != -1) break;
1217 if (errno != EEXIST) {
1218 ERR("Unexpected error while open() call: %s\n",strerror(errno));
1219 free(ret);
1220 *f = NULL;
1221 return NULL;
1222 }
1223 }
1224
1225 if ((*f = fdopen(tmp_fd,"w")) == NULL) {
1226 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno));
1227 close(tmp_fd);
1228 free(ret);
1229 return NULL;
1230 }
1231
1232 return ret;
1233}
1234
1235/* convert win95 native registry file to wine format [Internal] */
1236static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level)
1237{
1238 int fd;
1239 FILE *f;
1240 DOS_FULL_NAME full_name;
1241 void *base;
1242 LPSTR ret = NULL;
1243 struct stat st;
1244
1245 _w95creg *creg;
1246 _w95rgkn *rgkn;
1247 _w95dke *dke, *root_dke;
1248
1249 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1250
1251 /* map the registry into the memory */
1252 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1253 if ((fstat(fd, &st) == -1)) goto error1;
1254 if (!st.st_size) goto error1;
1255 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1256
1257 /* control signature */
1258 if (*(LPDWORD)base != W95_REG_CREG_ID) {
1259 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn);
1260 goto error;
1261 }
1262
1263 creg = base;
1264 /* load the header (rgkn) */
1265 rgkn = (_w95rgkn*)(creg + 1);
1266 if (rgkn->id != W95_REG_RGKN_ID) {
1267 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1268 goto error;
1269 }
1270 if (rgkn->root_off != 0x20) {
1271 ERR("rgkn->root_off not 0x20, please report !\n");
1272 goto error;
1273 }
1274 if (rgkn->last_dke > rgkn->size)
1275 {
1276 ERR("registry file corrupt! last_dke > size!\n");
1277 goto error;
1278 }
1279 /* verify last dke */
1280 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1281 if (dke->x1 != 0x80000000)
1282 { /* wrong magic */
1283 ERR("last dke invalid !\n");
1284 goto error;
1285 }
1286 if (rgkn->size > creg->rgdb_off)
1287 {
1288 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1289 goto error;
1290 }
1291 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1292 if ( (root_dke->prevlvl != 0xffffffff) || (root_dke->next != 0xffffffff) )
1293 {
1294 ERR("registry file corrupt! invalid root dke !\n");
1295 goto error;
1296 }
1297
1298 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1299 fprintf(f,"WINE REGISTRY Version 2");
1300 _w95_dump_dke("",creg,rgkn,root_dke,f,level);
1301 fclose(f);
1302
1303error:
1304 if(ret == NULL) {
1305 ERR("Unable to load native win95 registry file %s.\n",fn);
1306 ERR("Please report to a.mohr@mailto.de.\n");
1307 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1308 }
1309
1310 munmap(base, st.st_size);
1311error1:
1312 close(fd);
1313 return ret;
1314}
1315
1316/* convert winnt native registry file to wine format [Internal] */
1317static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level)
1318{
1319 int fd;
1320 FILE *f;
1321 DOS_FULL_NAME full_name;
1322 void *base;
1323 LPSTR ret = NULL;
1324 struct stat st;
1325
1326 nt_regf *regf;
1327 nt_hbin *hbin;
1328 nt_hbin_sub *hbin_sub;
1329 nt_nk *nk;
1330
1331 if (!DOSFS_GetFullName( fn, 0, &full_name )) return NULL;
1332
1333 /* map the registry into the memory */
1334 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return NULL;
1335 if ((fstat(fd, &st) == -1)) goto error1;
1336 if (!st.st_size) goto error1;
1337 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
1338
1339 /* control signature */
1340 if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) {
1341 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn);
1342 goto error;
1343 }
1344
1345 /* start block */
1346 regf = base;
1347
1348 /* hbin block */
1349 hbin = (nt_hbin*)((char*) base + 0x1000);
1350 if (hbin->id != NT_REG_POOL_BLOCK_ID) {
1351 ERR( "hbin block invalid\n");
1352 goto error;
1353 }
1354
1355 /* hbin_sub block */
1356 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1357 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k')) {
1358 ERR( "hbin_sub block invalid\n");
1359 goto error;
1360 }
1361
1362 /* nk block */
1363 nk = (nt_nk*)&(hbin_sub->data[0]);
1364 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE) {
1365 ERR( "special nk block not found\n");
1366 goto error;
1367 }
1368
1369 if ( (ret = _get_tmp_fn(&f)) == NULL) goto error;
1370 fprintf(f,"WINE REGISTRY Version 2");
1371 _nt_dump_nk("",(char*)base+0x1000,nk,f,level);
1372 fclose(f);
1373
1374error:
1375 munmap(base,st.st_size);
1376error1:
1377 close(fd);
1378 return ret;
1379}
1380
Andreas Mohr99f2f392001-06-22 23:21:47 +00001381/* convert native registry to wine format and load it via server call [Internal] */
Martin Pilka57f8eb72000-12-15 03:22:27 +00001382static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level)
1383{
1384 LPSTR tmp = NULL;
1385
1386 switch (reg_type) {
1387 case REG_WINNT:
1388 /* FIXME: following function doesn't really convert yet */
1389 tmp = _convert_winnt_registry_to_wine_format(fn,level);
1390 break;
1391 case REG_WIN95:
1392 tmp = _convert_win95_registry_to_wine_format(fn,level);
1393 break;
1394 case REG_WIN31:
1395 ERR("Don't know how to convert native 3.1 registry yet.\n");
1396 break;
1397 default:
1398 ERR("Unknown registry format parameter (%d)\n",reg_type);
1399 break;
1400 }
1401
1402 if (tmp != NULL) {
1403 load_wine_registry(hkey,tmp);
Andreas Mohr99f2f392001-06-22 23:21:47 +00001404 TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp);
Martin Pilka57f8eb72000-12-15 03:22:27 +00001405 unlink(tmp);
1406 }
Andreas Mohr99f2f392001-06-22 23:21:47 +00001407 else WARN("Unable to convert %s (doesn't exist?)\n",fn);
Martin Pilka57f8eb72000-12-15 03:22:27 +00001408 free(tmp);
1409}
1410
1411/* load all native windows registry files [Internal] */
1412static void _load_windows_registry( HKEY hkey_users_default )
1413{
1414 int reg_type;
1415 char windir[MAX_PATHNAME_LEN];
1416 char path[MAX_PATHNAME_LEN];
1417
1418 GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN);
1419
1420 reg_type = _get_reg_type();
1421 switch (reg_type) {
1422 case REG_WINNT: {
1423 HKEY hkey;
1424
1425 /* user specific ntuser.dat */
1426 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) {
1427 strcat(path,"\\ntuser.dat");
1428 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
1429 }
1430
1431 /* default user.dat */
1432 if (hkey_users_default) {
1433 strcpy(path,windir);
1434 strcat(path,"\\system32\\config\\default");
1435 _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1);
1436 }
1437
1438 /*
1439 * FIXME
1440 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1441 */
1442
1443 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) {
1444 strcpy(path,windir);
1445 strcat(path,"\\system32\\config\\system");
1446 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1447 RegCloseKey(hkey);
1448 }
1449
1450 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) {
1451 strcpy(path,windir);
1452 strcat(path,"\\system32\\config\\software");
1453 _convert_and_load_native_registry(path,hkey,REG_WINNT,1);
1454 RegCloseKey(hkey);
1455 }
1456
1457 strcpy(path,windir);
1458 strcat(path,"\\system32\\config\\sam");
1459 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1460
1461 strcpy(path,windir);
1462 strcat(path,"\\system32\\config\\security");
1463 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0);
1464
1465 /* this key is generated when the nt-core booted successfully */
1466 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey)) RegCloseKey(hkey);
1467 break;
1468 }
1469
1470 case REG_WIN95:
1471 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0);
1472
1473 strcpy(path,windir);
1474 strcat(path,"\\system.dat");
1475 _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0);
1476
1477 if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) {
1478 /* user specific user.dat */
1479 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1480 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1481
1482 /* default user.dat */
1483 if (hkey_users_default) {
1484 strcpy(path,windir);
1485 strcat(path,"\\user.dat");
1486 _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1);
1487 }
1488 } else {
1489 strcpy(path,windir);
1490 strcat(path,"\\user.dat");
1491 _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
1492 }
1493 break;
1494
1495 case REG_WIN31:
1496 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1497 _w31_loadreg();
1498 break;
1499
1500 case REG_DONTLOAD:
1501 TRACE("REG_DONTLOAD\n");
1502 break;
1503
1504 default:
1505 ERR("switch: no match (%d)\n",reg_type);
1506 break;
1507
1508 }
1509}
1510
1511/* load global registry files (stored in /etc/wine) [Internal] */
1512static void _load_global_registry(void)
1513{
1514 TRACE("(void)\n");
1515
1516 /* Load the global HKU hive directly from sysconfdir */
1517 load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
1518
1519 /* Load the global machine defaults directly from sysconfdir */
1520 load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
1521}
1522
1523/* load home registry files (stored in ~/.wine) [Internal] */
1524static void _load_home_registry( HKEY hkey_users_default )
1525{
1526 LPCSTR confdir = get_config_dir();
1527 LPSTR tmp = _xmalloc(strlen(confdir)+20);
1528
1529 strcpy(tmp,confdir);
1530 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
1531 load_wine_registry(hkey_users_default,tmp);
1532
1533 strcpy(tmp,confdir);
1534 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
1535 load_wine_registry(HKEY_CURRENT_USER,tmp);
1536
1537 strcpy(tmp,confdir);
1538 strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
1539 load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
1540
1541 free(tmp);
1542}
1543
1544/* load all registry (native and global and home) */
1545void SHELL_LoadRegistry( void )
1546{
1547 HKEY hkey_users_default;
1548
1549 TRACE("(void)\n");
1550
1551 if (!CLIENT_IsBootThread()) return; /* already loaded */
1552
Alexandre Julliard306fc9c2001-01-25 21:48:24 +00001553 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey_users_default))
1554 {
1555 ERR("Cannot create HKEY_USERS/.Default\n" );
1556 ExitProcess(1);
1557 }
Martin Pilka57f8eb72000-12-15 03:22:27 +00001558
1559 _allocate_default_keys();
1560 _set_registry_levels(0,0,0);
1561 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1562 _load_windows_registry( hkey_users_default );
1563 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1564 _load_global_registry();
1565 _set_registry_levels(1,0,0);
1566 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1567 _load_home_registry( hkey_users_default );
1568 _init_registry_saving( hkey_users_default );
1569 RegCloseKey(hkey_users_default);
1570}
1571
1572/***************************************************************************/
1573/* API FUNCTIONS */
1574/***************************************************************************/
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001575
1576/******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001577 * RegFlushKey [ADVAPI32.@]
Andreas Mohrd4b13da1999-08-07 14:17:10 +00001578 * Immediately writes key to registry.
1579 * Only returns after data has been written to disk.
1580 *
1581 * FIXME: does it really wait until data is written ?
1582 *
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001583 * PARAMS
1584 * hkey [I] Handle of key to write
1585 *
1586 * RETURNS
1587 * Success: ERROR_SUCCESS
1588 * Failure: Error code
1589 */
1590DWORD WINAPI RegFlushKey( HKEY hkey )
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001591{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001592 FIXME( "(%x): stub\n", hkey );
1593 return ERROR_SUCCESS;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001594}
1595
Alexandre Julliarda845b881998-06-01 10:44:35 +00001596
1597/******************************************************************************
Patrik Stridvalld0a41772001-02-14 23:11:17 +00001598 * RegUnLoadKeyA [ADVAPI32.@]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001599 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001600LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001601{
Alexandre Julliard5ce23292000-11-30 20:31:41 +00001602 FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
Alexandre Julliarda845b881998-06-01 10:44:35 +00001603 return ERROR_SUCCESS;
1604}
1605
1606
1607/******************************************************************************
Patrik Stridvalld0a41772001-02-14 23:11:17 +00001608 * RegRestoreKeyW [ADVAPI32.@]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001609 *
1610 * PARAMS
1611 * hkey [I] Handle of key where restore begins
1612 * lpFile [I] Address of filename containing saved tree
1613 * dwFlags [I] Optional flags
Alexandre Julliarda845b881998-06-01 10:44:35 +00001614 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001615LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001616{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001617 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001618
1619 /* It seems to do this check before the hkey check */
1620 if (!lpFile || !*lpFile)
1621 return ERROR_INVALID_PARAMETER;
1622
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001623 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001624
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001625 /* Check for file existence */
1626
Alexandre Julliarda845b881998-06-01 10:44:35 +00001627 return ERROR_SUCCESS;
1628}
1629
1630
1631/******************************************************************************
Patrik Stridvalld0a41772001-02-14 23:11:17 +00001632 * RegRestoreKeyA [ADVAPI32.@]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001633 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001634LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001635{
Alexandre Julliardad28d392000-07-09 11:20:59 +00001636 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1637 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1638 HeapFree( GetProcessHeap(), 0, lpFileW );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001639 return ret;
1640}
1641
1642
1643/******************************************************************************
Patrik Stridvalld0a41772001-02-14 23:11:17 +00001644 * RegReplaceKeyA [ADVAPI32.@]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001645 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001646LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
Alexandre Julliarda845b881998-06-01 10:44:35 +00001647 LPCSTR lpOldFile )
1648{
Alexandre Julliard5ce23292000-11-30 20:31:41 +00001649 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
1650 debugstr_a(lpNewFile),debugstr_a(lpOldFile));
1651 return ERROR_SUCCESS;
Alexandre Julliarda845b881998-06-01 10:44:35 +00001652}
1653
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001654
1655
1656
1657
1658
1659/* 16-bit functions */
1660
1661/* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1662 * some programs. Do not remove those cases. -MM
1663 */
1664static inline void fix_win16_hkey( HKEY *hkey )
1665{
1666 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1667}
1668
1669/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001670 * RegEnumKey [KERNEL.216]
1671 * RegEnumKey [SHELL.7]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001672 */
1673DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1674{
1675 fix_win16_hkey( &hkey );
1676 return RegEnumKeyA( hkey, index, name, name_len );
1677}
1678
1679/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001680 * RegOpenKey [KERNEL.217]
1681 * RegOpenKey [SHELL.1]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001682 */
1683DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1684{
1685 fix_win16_hkey( &hkey );
1686 return RegOpenKeyA( hkey, name, retkey );
1687}
1688
1689/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001690 * RegCreateKey [KERNEL.218]
1691 * RegCreateKey [SHELL.2]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001692 */
1693DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1694{
1695 fix_win16_hkey( &hkey );
1696 return RegCreateKeyA( hkey, name, retkey );
1697}
1698
1699/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001700 * RegDeleteKey [KERNEL.219]
1701 * RegDeleteKey [SHELL.4]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001702 */
1703DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1704{
1705 fix_win16_hkey( &hkey );
1706 return RegDeleteKeyA( hkey, name );
1707}
1708
1709/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001710 * RegCloseKey [KERNEL.220]
1711 * RegCloseKey [SHELL.3]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001712 */
1713DWORD WINAPI RegCloseKey16( HKEY hkey )
1714{
1715 fix_win16_hkey( &hkey );
1716 return RegCloseKey( hkey );
1717}
1718
1719/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001720 * RegSetValue [KERNEL.221]
1721 * RegSetValue [SHELL.5]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001722 */
1723DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1724{
1725 fix_win16_hkey( &hkey );
1726 return RegSetValueA( hkey, name, type, data, count );
1727}
1728
1729/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001730 * RegDeleteValue [KERNEL.222]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001731 */
1732DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1733{
1734 fix_win16_hkey( &hkey );
1735 return RegDeleteValueA( hkey, name );
1736}
1737
1738/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001739 * RegEnumValue [KERNEL.223]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001740 */
1741DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1742 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1743{
1744 fix_win16_hkey( &hkey );
1745 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1746}
1747
1748/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001749 * RegQueryValue [KERNEL.224]
1750 * RegQueryValue [SHELL.6]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001751 *
1752 * NOTES
1753 * Is this HACK still applicable?
1754 *
1755 * HACK
1756 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1757 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1758 * Aldus FH4)
1759 */
1760DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1761{
1762 fix_win16_hkey( &hkey );
1763 if (count) *count &= 0xffff;
1764 return RegQueryValueA( hkey, name, data, count );
1765}
1766
1767/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001768 * RegQueryValueEx [KERNEL.225]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001769 */
1770DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1771 LPBYTE data, LPDWORD count )
1772{
1773 fix_win16_hkey( &hkey );
1774 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1775}
1776
1777/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001778 * RegSetValueEx [KERNEL.226]
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001779 */
1780DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1781 CONST BYTE *data, DWORD count )
1782{
1783 fix_win16_hkey( &hkey );
Marcus Meissner8f1e39f2000-11-15 22:13:11 +00001784 if (!count && (type==REG_SZ)) count = strlen(data);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001785 return RegSetValueExA( hkey, name, reserved, type, data, count );
1786}
Patrik Stridvall7a4e5992000-12-01 23:53:46 +00001787
1788/******************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001789 * RegFlushKey [KERNEL.227]
Patrik Stridvall7a4e5992000-12-01 23:53:46 +00001790 */
1791DWORD WINAPI RegFlushKey16( HKEY hkey )
1792{
1793 fix_win16_hkey( &hkey );
1794 return RegFlushKey( hkey );
1795}