blob: a7eb4bdf04b3a3f4c00909d507217c02575e397c [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>
Ove Kaavenb43b9d92000-04-14 14:05:43 +000028#include <limits.h>
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000029#include <ctype.h>
Alexandre Julliard8664b891996-04-05 14:58:24 +000030#include <errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000031#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000032#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000033#endif
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000034#include <sys/types.h>
Patrik Stridvall6afc68a2000-01-04 00:32:38 +000035#include <fcntl.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000036#include <sys/fcntl.h>
37#include <sys/stat.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000038#include <time.h>
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000039#include "windef.h"
40#include "winbase.h"
Alexandre Julliardad28d392000-07-09 11:20:59 +000041#include "winnls.h"
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000042#include "wine/winbase16.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000043#include "winerror.h"
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +000044#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000045#include "heap.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000046#include "debugtools.h"
Marcus Meissner6b9dd2e1999-03-18 17:39:57 +000047#include "options.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000048#include "winreg.h"
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +000049#include "server.h"
Alexandre Julliard705686e1999-11-24 19:34:32 +000050#include "services.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000051
Alexandre Julliard383da682000-02-10 22:15:21 +000052DEFAULT_DEBUG_CHANNEL(reg);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000053
Juergen Schmiedebc2b771998-11-14 18:59:30 +000054static void REGISTRY_Init(void);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000055/* FIXME: following defines should be configured global ... */
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000056
Marcus Meissneradf8a0c1999-06-12 08:18:38 +000057#define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
58#define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000059
60/* relative in ~user/.wine/ : */
Sylvain St.Germaine5332221999-04-10 16:46:15 +000061#define SAVE_CURRENT_USER "user.reg"
Alexandre Julliarda01004d2000-05-14 22:57:57 +000062#define SAVE_DEFAULT_USER "userdef.reg"
Sylvain St.Germaine5332221999-04-10 16:46:15 +000063#define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64#define SAVE_LOCAL_MACHINE "system.reg"
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000065
Alexandre Julliarde658d821997-11-30 17:45:40 +000066
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +000067static void *xmalloc( size_t size )
68{
69 void *res;
70
71 res = malloc (size ? size : 1);
72 if (res == NULL) {
73 WARN("Virtual memory exhausted.\n");
74 exit (1);
75 }
76 return res;
77}
Alexandre Julliardf90efa91998-06-14 15:24:15 +000078
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000079
80/******************************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +000081 * REGISTRY_Init [Internal]
82 * Registry initialisation, allocates some default keys.
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000083 */
Juergen Schmiedebc2b771998-11-14 18:59:30 +000084static void REGISTRY_Init(void) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +000085 HKEY hkey;
86 char buf[200];
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000087
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +000088 TRACE("(void)\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000089
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +000090 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000091 RegCloseKey(hkey);
Alexandre Julliarda11d7b11998-03-01 20:05:02 +000092
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000093 /* This was an Open, but since it is called before the real registries
94 are loaded, it was changed to a Create - MTB 980507*/
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +000095 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
Alexandre Julliarda3960291999-02-26 11:11:13 +000096 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000097 RegCloseKey(hkey);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000098
Andreas Mohr2e011a52000-06-01 23:28:25 +000099 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000100 * CurrentVersion
101 * CurrentBuildNumber
102 * CurrentType
103 * string RegisteredOwner
104 * string RegisteredOrganization
105 *
106 */
107 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
108 * string SysContact
109 * string SysLocation
110 * SysServices
Huw D M Daviesf49cb521999-11-12 00:58:15 +0000111 */
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000112 if (-1!=gethostname(buf,200)) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000113 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
114 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000115 RegCloseKey(hkey);
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000116 }
117}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000118
119
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000120/************************ LOAD Registry Function ****************************/
121
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000122
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000123
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000124/******************************************************************************
125 * _find_or_add_key [Internal]
126 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000127static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000128{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000129 HKEY subkey;
130 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
131 if (keyname) free( keyname );
132 return subkey;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000133}
134
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000135/******************************************************************************
136 * _find_or_add_value [Internal]
137 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000138static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000139{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000140 RegSetValueExW( hkey, name, 0, type, data, len );
141 if (name) free( name );
142 if (data) free( data );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000143}
144
145
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000146/******************************************************************************
147 * _wine_read_line [Internal]
148 *
149 * reads a line including dynamically enlarging the readbuffer and throwing
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000150 * away comments
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000151 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000152static int _wine_read_line( FILE *F, char **buf, int *len )
153{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000154 char *s,*curread;
155 int mylen,curoff;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000156
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000157 curread = *buf;
158 mylen = *len;
159 **buf = '\0';
160 while (1) {
161 while (1) {
162 s=fgets(curread,mylen,F);
163 if (s==NULL)
164 return 0; /* EOF */
165 if (NULL==(s=strchr(curread,'\n'))) {
166 /* buffer wasn't large enough */
167 curoff = strlen(*buf);
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000168 curread = realloc(*buf,*len*2);
169 if(curread == NULL) {
170 WARN("Out of memory");
171 return 0;
172 }
173 *buf = curread;
174 curread+= curoff;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000175 mylen = *len; /* we filled up the buffer and
176 * got new '*len' bytes to fill
177 */
178 *len = *len * 2;
179 } else {
180 *s='\0';
181 break;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000182 }
183 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000184 /* throw away comments */
185 if (**buf=='#' || **buf==';') {
186 curread = *buf;
187 mylen = *len;
188 continue;
189 }
190 if (s) /* got end of line */
191 break;
192 }
193 return 1;
194}
195
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000196
197/******************************************************************************
198 * _wine_read_USTRING [Internal]
199 *
200 * converts a char* into a UNICODE string (up to a special char)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000201 * and returns the position exactly after that string
202 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000203static char* _wine_read_USTRING( char *buf, LPWSTR *str )
204{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000205 char *s;
206 LPWSTR ws;
207
208 /* read up to "=" or "\0" or "\n" */
209 s = buf;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000210 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
211 ws = *str;
212 while (*s && (*s!='\n') && (*s!='=')) {
213 if (*s!='\\')
214 *ws++=*((unsigned char*)s++);
215 else {
216 s++;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000217 if (!*s) {
218 /* Dangling \ ... may only happen if a registry
Andreas Mohr2e011a52000-06-01 23:28:25 +0000219 * write was short. FIXME: What to do?
Alexandre Julliard638f1691999-01-17 16:32:32 +0000220 */
221 break;
222 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000223 if (*s=='\\') {
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000224 *ws++='\\';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000225 s++;
226 continue;
227 }
228 if (*s!='u') {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000229 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000230 *ws++='\\';
231 *ws++=*s++;
232 } else {
233 char xbuf[5];
234 int wc;
235
236 s++;
237 memcpy(xbuf,s,4);xbuf[4]='\0';
238 if (!sscanf(xbuf,"%x",&wc))
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000239 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000240 s+=4;
241 *ws++ =(unsigned short)wc;
242 }
243 }
244 }
245 *ws = 0;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000246 return s;
247}
248
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000249
250/******************************************************************************
251 * _wine_loadsubkey [Internal]
252 *
253 * NOTES
254 * It seems like this is returning a boolean. Should it?
255 *
256 * RETURNS
257 * Success: 1
258 * Failure: 0
259 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000260static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000261{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000262 HKEY subkey;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000263 int i;
264 char *s;
265 LPWSTR name;
266
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000267 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000268
269 /* Good. We already got a line here ... so parse it */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000270 subkey = 0;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000271 while (1) {
272 i=0;s=*buf;
273 while (*s=='\t') {
274 s++;
275 i++;
276 }
277 if (i>level) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000278 if (!subkey) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000279 WARN("Got a subhierarchy without resp. key?\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000280 return 0;
281 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000282 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
Eric Pouechc0bcf261999-11-04 01:38:11 +0000283 if (!_wine_read_line(F,buf,buflen))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000284 goto done;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000285 continue;
286 }
287
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000288 /* let the caller handle this line */
289 if (i<level || **buf=='\0')
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000290 goto done;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000291
292 /* it can be: a value or a keyname. Parse the name first */
293 s=_wine_read_USTRING(s,&name);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000294
295 /* switch() default: hack to avoid gotos */
296 switch (0) {
297 default:
298 if (*s=='\0') {
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000299 if (subkey) RegCloseKey( subkey );
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000300 subkey=_find_or_add_key(hkey,name);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000301 } else {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000302 LPBYTE data;
303 int len,lastmodified,type;
304
305 if (*s!='=') {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000306 WARN("Unexpected character: %c\n",*s);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000307 break;
308 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000309 s++;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000310 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000311 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000312 break;
313 }
314 /* skip the 2 , */
315 s=strchr(s,',');s++;
Eric Pouechc0bcf261999-11-04 01:38:11 +0000316 s=strchr(s,',');
317 if (!s++) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000318 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
Eric Pouechc0bcf261999-11-04 01:38:11 +0000319 break;
320 }
Juergen Schmiedf74fa4e1999-01-31 09:19:46 +0000321 if (type == REG_SZ || type == REG_EXPAND_SZ) {
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000322 s=_wine_read_USTRING(s,(LPWSTR*)&data);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000323 len = lstrlenW((LPWSTR)data)*2+2;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000324 } else {
325 len=strlen(s)/2;
326 data = (LPBYTE)xmalloc(len+1);
327 for (i=0;i<len;i++) {
328 data[i]=0;
329 if (*s>='0' && *s<='9')
330 data[i]=(*s-'0')<<4;
331 if (*s>='a' && *s<='f')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000332 data[i]=(*s-'a'+'\xa')<<4;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000333 if (*s>='A' && *s<='F')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000334 data[i]=(*s-'A'+'\xa')<<4;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000335 s++;
336 if (*s>='0' && *s<='9')
337 data[i]|=*s-'0';
338 if (*s>='a' && *s<='f')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000339 data[i]|=*s-'a'+'\xa';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000340 if (*s>='A' && *s<='F')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000341 data[i]|=*s-'A'+'\xa';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000342 s++;
343 }
344 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000345 _find_or_add_value(hkey,name,type,data,len);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000346 }
347 }
348 /* read the next line */
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000349 if (!_wine_read_line(F,buf,buflen))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000350 goto done;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000351 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000352 done:
353 if (subkey) RegCloseKey( subkey );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000354 return 1;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000355}
356
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000357
358/******************************************************************************
359 * _wine_loadsubreg [Internal]
360 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000361static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000362{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000363 int ver;
364 char *buf;
365 int buflen;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000366
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000367 buf=xmalloc(10);buflen=10;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000368 if (!_wine_read_line(F,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000369 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000370 return 0;
371 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000372 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
373 free(buf);
374 return 0;
375 }
Alexandre Julliardc9709042000-04-16 17:21:13 +0000376 if (ver!=1) {
Alexandre Julliard53f3a831999-11-24 04:19:43 +0000377 if (ver == 2) /* new version */
378 {
379 HANDLE file;
380 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000381 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
Alexandre Julliard53f3a831999-11-24 04:19:43 +0000382 {
383 struct load_registry_request *req = get_req_buffer();
384 req->hkey = hkey;
385 req->file = file;
386 req->name[0] = 0;
387 server_call( REQ_LOAD_REGISTRY );
388 CloseHandle( file );
389 }
390 free( buf );
391 return 1;
392 }
393 else
394 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000395 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000396 free(buf);
397 return 0;
Alexandre Julliard53f3a831999-11-24 04:19:43 +0000398 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000399 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000400 if (!_wine_read_line(F,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000401 free(buf);
402 return 0;
403 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000404 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000405 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000406 return 0;
407 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000408 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000409 return 1;
410}
411
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000412
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000413/******************************************************************************
414 * _wine_loadreg [Internal]
415 */
Alexandre Julliarda01004d2000-05-14 22:57:57 +0000416static int _wine_loadreg( HKEY hkey, char *fn )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000417{
418 FILE *F;
419
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000420 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000421
422 F = fopen(fn,"rb");
423 if (F==NULL) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000424 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
Alexandre Julliarda01004d2000-05-14 22:57:57 +0000425 return -1;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000426 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000427 _wine_loadsubreg(F,hkey,fn);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000428 fclose(F);
Alexandre Julliarda01004d2000-05-14 22:57:57 +0000429 return 0;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000430}
431
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000432/* NT REGISTRY LOADER */
Patrik Stridvall6afc68a2000-01-04 00:32:38 +0000433
434#ifdef HAVE_SYS_MMAN_H
435# include <sys/mman.h>
436#endif
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000437
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000438#ifndef MAP_FAILED
439#define MAP_FAILED ((LPVOID)-1)
440#endif
441
Juergen Schmied271ba292000-01-15 23:42:50 +0000442#define NT_REG_BLOCK_SIZE 0x1000
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000443
Juergen Schmied271ba292000-01-15 23:42:50 +0000444#define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
445#define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000446#define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
447#define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
448
449/* subblocks of nk */
450#define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
451#define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
452#define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
453
Juergen Schmied271ba292000-01-15 23:42:50 +0000454#define NT_REG_KEY_BLOCK_TYPE 0x20
455#define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000456
457typedef struct
458{
459 DWORD id; /* 0x66676572 'regf'*/
460 DWORD uk1; /* 0x04 */
461 DWORD uk2; /* 0x08 */
462 FILETIME DateModified; /* 0x0c */
463 DWORD uk3; /* 0x14 */
464 DWORD uk4; /* 0x18 */
465 DWORD uk5; /* 0x1c */
466 DWORD uk6; /* 0x20 */
467 DWORD RootKeyBlock; /* 0x24 */
468 DWORD BlockSize; /* 0x28 */
469 DWORD uk7[116];
470 DWORD Checksum; /* at offset 0x1FC */
471} nt_regf;
472
473typedef struct
474{
475 DWORD blocksize;
476 BYTE data[1];
477} nt_hbin_sub;
478
479typedef struct
480{
481 DWORD id; /* 0x6E696268 'hbin' */
482 DWORD off_prev;
483 DWORD off_next;
484 DWORD uk1;
485 DWORD uk2; /* 0x10 */
486 DWORD uk3; /* 0x14 */
487 DWORD uk4; /* 0x18 */
488 DWORD size; /* 0x1C */
489 nt_hbin_sub hbin_sub; /* 0x20 */
490} nt_hbin;
491
492/*
493 * the value_list consists of offsets to the values (vk)
494 */
495typedef struct
496{
497 WORD SubBlockId; /* 0x00 0x6B6E */
498 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
499 FILETIME writetime; /* 0x04 */
500 DWORD uk1; /* 0x0C */
501 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
502 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
503 DWORD uk8; /* 0x18 */
504 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
505 DWORD uk2; /* 0x20 */
506 DWORD nr_values; /* 0x24 number of values */
507 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
508 DWORD off_sk; /* 0x2c Offset of the sk-Record */
509 DWORD off_class; /* 0x30 Offset of the Class-Name */
510 DWORD uk3; /* 0x34 */
511 DWORD uk4; /* 0x38 */
512 DWORD uk5; /* 0x3c */
513 DWORD uk6; /* 0x40 */
514 DWORD uk7; /* 0x44 */
515 WORD name_len; /* 0x48 name-length */
516 WORD class_len; /* 0x4a class-name length */
517 char name[1]; /* 0x4c key-name */
518} nt_nk;
519
520typedef struct
521{
522 DWORD off_nk; /* 0x00 */
523 DWORD name; /* 0x04 */
524} hash_rec;
525
526typedef struct
527{
528 WORD id; /* 0x00 0x666c */
529 WORD nr_keys; /* 0x06 */
530 hash_rec hash_rec[1];
531} nt_lf;
532
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000533/*
534 list of subkeys without hash
535
536 li --+-->nk
537 |
538 +-->nk
539 */
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000540typedef struct
541{
542 WORD id; /* 0x00 0x696c */
543 WORD nr_keys;
544 DWORD off_nk[1];
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000545} nt_li;
546
547/*
548 this is a intermediate node
549
550 ri --+-->li--+-->nk
551 | +
552 | +-->nk
553 |
554 +-->li--+-->nk
555 +
556 +-->nk
557 */
558typedef struct
559{
560 WORD id; /* 0x00 0x6972 */
561 WORD nr_li; /* 0x02 number off offsets */
562 DWORD off_li[1]; /* 0x04 points to li */
563} nt_ri;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000564
565typedef struct
566{
567 WORD id; /* 0x00 'vk' */
568 WORD nam_len;
569 DWORD data_len;
570 DWORD data_off;
571 DWORD type;
572 WORD flag;
573 WORD uk1;
574 char name[1];
575} nt_vk;
576
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000577LPSTR _strdupnA( LPCSTR str, int len )
578{
579 LPSTR ret;
580
581 if (!str) return NULL;
Alexandre Julliardad28d392000-07-09 11:20:59 +0000582 ret = xmalloc( len + 1 );
583 memcpy( ret, str, len );
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000584 ret[len] = 0x00;
585 return ret;
586}
587
Juergen Schmied271ba292000-01-15 23:42:50 +0000588static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
589static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000590static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000591
592
593/*
594 * gets a value
595 *
596 * vk->flag:
597 * 0 value is a default value
598 * 1 the value has a name
599 *
600 * vk->data_len
601 * len of the whole data block
602 * - reg_sz (unicode)
603 * bytes including the terminating \0 = 2*(number_of_chars+1)
604 * - reg_dword, reg_binary:
605 * if highest bit of data_len is set data_off contains the value
606 */
Juergen Schmied271ba292000-01-15 23:42:50 +0000607static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000608{
609 WCHAR name [256];
Alexandre Julliardad28d392000-07-09 11:20:59 +0000610 DWORD len, ret;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000611 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
612
Juergen Schmied271ba292000-01-15 23:42:50 +0000613 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000614
Alexandre Julliardad28d392000-07-09 11:20:59 +0000615 if (!(len = MultiByteToWideChar( CP_ACP, 0, vk->name, vk->nam_len, name, 256 )) && vk->nam_len)
616 {
617 ERR("name too large '%.*s' (%d)\n", vk->nam_len, vk->name, vk->nam_len );
618 return FALSE;
619 }
620 name[len] = 0;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000621
Juergen Schmiedc35cce21999-12-20 03:58:44 +0000622 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000623 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
Juergen Schmiedc35cce21999-12-20 03:58:44 +0000624 (vk->data_len & 0x7fffffff) );
625 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000626 return TRUE;
627error:
Alexandre Julliardad28d392000-07-09 11:20:59 +0000628 ERR("unknown block found (0x%04x), please report!\n", vk->id);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000629 return FALSE;
630}
631
632/*
633 * get the subkeys
634 *
635 * this structure contains the hash of a keyname and points to all
636 * subkeys
637 *
638 * exception: if the id is 'il' there are no hash values and every
639 * dword is a offset
640 */
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000641static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000642{
643 int i;
644
Juergen Schmied271ba292000-01-15 23:42:50 +0000645 if (lf->id == NT_REG_HASH_BLOCK_ID)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000646 {
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000647 if (subkeys != lf->nr_keys) goto error1;
648
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000649 for (i=0; i<lf->nr_keys; i++)
650 {
651 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
652 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000653 }
Juergen Schmied271ba292000-01-15 23:42:50 +0000654 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000655 {
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000656 nt_li * li = (nt_li*)lf;
657 if (subkeys != li->nr_keys) goto error1;
658
659 for (i=0; i<li->nr_keys; i++)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000660 {
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000661 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000662 }
663 }
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000664 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
665 {
666 nt_ri * ri = (nt_ri*)lf;
667 int li_subkeys = 0;
668
669 /* count all subkeys */
670 for (i=0; i<ri->nr_li; i++)
671 {
672 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
673 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
674 li_subkeys += li->nr_keys;
675 }
676
677 /* check number */
678 if (subkeys != li_subkeys) goto error1;
679
680 /* loop through the keys */
681 for (i=0; i<ri->nr_li; i++)
682 {
683 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
684 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
685 }
686 }
687 else
688 {
689 goto error2;
690 }
691 return TRUE;
692
693error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000694 return TRUE;
695
Alexandre Julliardad28d392000-07-09 11:20:59 +0000696error1: ERR("registry file corrupt! (inconsistent number of subkeys)\n");
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000697 return FALSE;
698
Alexandre Julliardad28d392000-07-09 11:20:59 +0000699error: ERR("error reading lf block\n");
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000700 return FALSE;
701}
702
Juergen Schmied271ba292000-01-15 23:42:50 +0000703static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000704{
705 char * name;
706 int i;
707 DWORD * vl;
Juergen Schmied271ba292000-01-15 23:42:50 +0000708 HKEY subkey = hkey;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000709
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000710 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
711 {
712 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
713 goto error;
714 }
715
Juergen Schmied271ba292000-01-15 23:42:50 +0000716 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000717 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
718 {
Alexandre Julliardad28d392000-07-09 11:20:59 +0000719 ERR("registry file corrupt!\n");
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000720 goto error;
721 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000722
723 /* create the new key */
Juergen Schmied271ba292000-01-15 23:42:50 +0000724 if(level <= 0)
725 {
Alexandre Julliardad28d392000-07-09 11:20:59 +0000726 name = _strdupnA( nk->name, nk->name_len);
Juergen Schmied271ba292000-01-15 23:42:50 +0000727 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
728 free(name);
729 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000730
731 /* loop through the subkeys */
732 if (nk->nr_subkeys)
733 {
734 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000735 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000736 }
737
738 /* loop trough the value list */
739 vl = (DWORD *)(base+nk->valuelist_off+4);
740 for (i=0; i<nk->nr_values; i++)
741 {
742 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
Juergen Schmied271ba292000-01-15 23:42:50 +0000743 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000744 }
745
746 RegCloseKey(subkey);
747 return TRUE;
748
749error1: RegCloseKey(subkey);
Juergen Schmiedbd1dcd72000-02-13 15:05:39 +0000750error: return FALSE;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000751}
752
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000753/* end nt loader */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000754
Juergen Schmied271ba292000-01-15 23:42:50 +0000755/* windows 95 registry loader */
756
757/* SECTION 1: main header
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000758 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000759 * once at offset 0
760 */
761#define W95_REG_CREG_ID 0x47455243
762
763typedef struct
764{
765 DWORD id; /* "CREG" = W95_REG_CREG_ID */
766 DWORD version; /* ???? 0x00010000 */
767 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
768 DWORD uk2; /* 0x0c */
769 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
770 WORD uk3;
771 DWORD uk[3];
772 /* rgkn */
773} _w95creg;
774
775/* SECTION 2: Directory information (tree structure)
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000776 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000777 * once on offset 0x20
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000778 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000779 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
780 */
781#define W95_REG_RGKN_ID 0x4e4b4752
782
783typedef struct
784{
785 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
786 DWORD size; /* Size of the RGKN-block */
787 DWORD root_off; /* Rel. Offset of the root-record */
788 DWORD uk[5];
789} _w95rgkn;
790
791/* Disk Key Entry Structure
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000792 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000793 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
794 * hive itself. It looks the same like other keys. Even the ID-number can
795 * be any value.
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000796 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000797 * The "hash"-value is a value representing the key's name. Windows will not
798 * search for the name, but for a matching hash-value. if it finds one, it
799 * will compare the actual string info, otherwise continue with the next key.
800 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
801 * of the string which are smaller than 0x80 (128) to this D-Word.
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000802 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000803 * If you want to modify key names, also modify the hash-values, since they
804 * cannot be found again (although they would be displayed in REGEDIT)
805 * End of list-pointers are filled with 0xFFFFFFFF
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000806 *
807 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
808 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
809 * structure) and reading another RGDB_section.
Juergen Schmied271ba292000-01-15 23:42:50 +0000810 *
811 * there is a one to one relationship between dke and dkh
812 */
813 /* key struct, once per key */
814typedef struct
815{
816 DWORD x1; /* Free entry indicator(?) */
817 DWORD hash; /* sum of bytes of keyname */
818 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
819 DWORD prevlvl; /* offset of previous key */
820 DWORD nextsub; /* offset of child key */
821 DWORD next; /* offset of sibling key */
822 WORD nrLS; /* id inside the rgdb block */
823 WORD nrMS; /* number of the rgdb block */
824} _w95dke;
825
826/* SECTION 3: key information, values and data
827 *
828 * structure:
829 * section: [blocks]* (repeat creg->rgdb_num times)
830 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
831 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000832 *
Alexandre Julliard02e90081998-01-04 17:49:09 +0000833 * An interesting relationship exists in RGDB_section. The value at offset
834 * 10 equals the value at offset 4 minus the value at offset 8. I have no
835 * idea at the moment what this means. (Kevin Cozens)
Juergen Schmied271ba292000-01-15 23:42:50 +0000836 */
837
838/* block header, once per block */
839#define W95_REG_RGDB_ID 0x42444752
840
841typedef struct
842{
843 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
844 DWORD size; /* 0x04 */
845 DWORD uk1; /* 0x08 */
846 DWORD uk2; /* 0x0c */
847 DWORD uk3; /* 0x10 */
848 DWORD uk4; /* 0x14 */
849 DWORD uk5; /* 0x18 */
850 DWORD uk6; /* 0x1c */
851 /* dkh */
852} _w95rgdb;
853
854/* Disk Key Header structure (RGDB part), once per key */
855typedef struct
856{
857 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
858 WORD nrLS; /* 0x04 id inside the rgdb block */
859 WORD nrMS; /* 0x06 number of the rgdb block */
860 DWORD bytesused; /* 0x08 */
861 WORD keynamelen; /* 0x0c len of name */
862 WORD values; /* 0x0e number of values */
863 DWORD xx1; /* 0x10 */
864 char name[1]; /* 0x14 */
865 /* dkv */ /* 0x14 + keynamelen */
866} _w95dkh;
867
868/* Disk Key Value structure, once per value */
869typedef struct
870{
871 DWORD type; /* 0x00 */
872 DWORD x1; /* 0x04 */
873 WORD valnamelen; /* 0x08 length of name, 0 is default key */
874 WORD valdatalen; /* 0x0A length of data */
875 char name[1]; /* 0x0c */
876 /* raw data */ /* 0x0c + valnamelen */
877} _w95dkv;
878
879/******************************************************************************
880 * _w95_lookup_dkh [Internal]
Alexandre Julliard02e90081998-01-04 17:49:09 +0000881 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000882 * seeks the dkh belonging to a dke
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000883 */
Juergen Schmied271ba292000-01-15 23:42:50 +0000884static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000885{
Juergen Schmied271ba292000-01-15 23:42:50 +0000886 _w95rgdb * rgdb;
887 _w95dkh * dkh;
888 int i;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000889
Juergen Schmied6889c682000-04-28 19:59:48 +0000890 /* get the beginning of the rgdb datastore */
891 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
892
893 /* check: requested block < last_block) */
894 if (creg->rgdb_num <= nrMS)
895 {
896 ERR("registry file corrupt! requested block no. beyond end.\n");
897 goto error;
898 }
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000899
Juergen Schmied271ba292000-01-15 23:42:50 +0000900 /* find the right block */
901 for(i=0; i<nrMS ;i++)
902 {
Juergen Schmied6889c682000-04-28 19:59:48 +0000903 if(rgdb->id != W95_REG_RGDB_ID) /* check the magic */
904 {
905 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
906 goto error;
907 }
Juergen Schmied271ba292000-01-15 23:42:50 +0000908 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000909 }
910
Juergen Schmied271ba292000-01-15 23:42:50 +0000911 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000912
Juergen Schmied271ba292000-01-15 23:42:50 +0000913 do
914 {
915 if(nrLS==dkh->nrLS ) return dkh;
916 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
917 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000918
Juergen Schmied6889c682000-04-28 19:59:48 +0000919error: return NULL;
Juergen Schmied271ba292000-01-15 23:42:50 +0000920}
921
922/******************************************************************************
923 * _w95_parse_dkv [Internal]
924 */
925static int _w95_parse_dkv (
926 HKEY hkey,
927 _w95dkh * dkh,
928 int nrLS,
929 int nrMS )
930{
931 _w95dkv * dkv;
932 int i;
933 DWORD ret;
934 char * name;
935
936 /* first value block */
937 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000938
Juergen Schmied271ba292000-01-15 23:42:50 +0000939 /* loop trought the values */
940 for (i=0; i< dkh->values; i++)
941 {
Alexandre Julliardad28d392000-07-09 11:20:59 +0000942 name = _strdupnA(dkv->name, dkv->valnamelen);
Juergen Schmied271ba292000-01-15 23:42:50 +0000943 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
Juergen Schmied6889c682000-04-28 19:59:48 +0000944 if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
Juergen Schmied271ba292000-01-15 23:42:50 +0000945 free (name);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000946
Juergen Schmied271ba292000-01-15 23:42:50 +0000947 /* next value */
948 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000949 }
Juergen Schmied271ba292000-01-15 23:42:50 +0000950 return TRUE;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000951}
952
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000953/******************************************************************************
Juergen Schmied271ba292000-01-15 23:42:50 +0000954 * _w95_parse_dke [Internal]
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000955 */
Juergen Schmied271ba292000-01-15 23:42:50 +0000956static int _w95_parse_dke(
957 HKEY hkey,
958 _w95creg * creg,
959 _w95rgkn *rgkn,
960 _w95dke * dke,
961 int level )
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000962{
Juergen Schmied271ba292000-01-15 23:42:50 +0000963 _w95dkh * dkh;
964 HKEY hsubkey = hkey;
965 char * name;
966 int ret = FALSE;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000967
Juergen Schmied271ba292000-01-15 23:42:50 +0000968 /* get start address of root key block */
969 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
970
Juergen Schmied0311eb32000-01-17 22:23:10 +0000971 /* special root key */
972 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
Juergen Schmied271ba292000-01-15 23:42:50 +0000973 {
Juergen Schmied0311eb32000-01-17 22:23:10 +0000974 /* parse the one subkey*/
975 if (dke->nextsub != 0xffffffff)
Juergen Schmied271ba292000-01-15 23:42:50 +0000976 {
Juergen Schmied0311eb32000-01-17 22:23:10 +0000977 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
Juergen Schmied271ba292000-01-15 23:42:50 +0000978 }
Juergen Schmied0311eb32000-01-17 22:23:10 +0000979 /* has no sibling keys */
980 goto error;
Juergen Schmied271ba292000-01-15 23:42:50 +0000981 }
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000982
Juergen Schmied0311eb32000-01-17 22:23:10 +0000983 /* search subblock */
984 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
985 {
986 fprintf(stderr, "dke pointing to missing dkh !\n");
987 goto error;
988 }
989
990 if ( level <= 0 )
991 {
992 /* walk sibling keys */
993 if (dke->next != 0xffffffff )
994 {
995 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
996 }
997
998 /* create subkey and insert values */
Alexandre Julliardad28d392000-07-09 11:20:59 +0000999 name = _strdupnA( dkh->name, dkh->keynamelen);
Juergen Schmied0311eb32000-01-17 22:23:10 +00001000 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1001 free(name);
1002 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1003 }
1004
1005 /* next sub key */
Juergen Schmied271ba292000-01-15 23:42:50 +00001006 if (dke->nextsub != 0xffffffff)
1007 {
Juergen Schmied0311eb32000-01-17 22:23:10 +00001008 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
Juergen Schmied271ba292000-01-15 23:42:50 +00001009 }
Juergen Schmied0311eb32000-01-17 22:23:10 +00001010
Juergen Schmied271ba292000-01-15 23:42:50 +00001011 ret = TRUE;
Juergen Schmied0311eb32000-01-17 22:23:10 +00001012error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
Juergen Schmied271ba292000-01-15 23:42:50 +00001013error: return ret;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001014}
Juergen Schmied271ba292000-01-15 23:42:50 +00001015/* end windows 95 loader */
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001016
1017/******************************************************************************
Juergen Schmied271ba292000-01-15 23:42:50 +00001018 * NativeRegLoadKey [Internal]
1019 *
1020 * Loads a native registry file (win95/nt)
1021 * hkey root key
1022 * fn filename
1023 * level number of levels to cut away (eg. ".Default" in user.dat)
1024 *
1025 * this function intentionally uses unix file functions to make it possible
1026 * to move it to a seperate registry helper programm
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001027 */
Juergen Schmied271ba292000-01-15 23:42:50 +00001028static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001029{
Juergen Schmied271ba292000-01-15 23:42:50 +00001030 int fd = 0;
1031 struct stat st;
1032 DOS_FULL_NAME full_name;
1033 int ret = FALSE;
1034 void * base;
1035
1036 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1037
1038 /* map the registry into the memory */
1039 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1040 if ((fstat(fd, &st) == -1)) goto error;
Bertho Stultiens5b8eb2d2000-05-03 17:35:10 +00001041 if (!st.st_size) goto error;
Juergen Schmied271ba292000-01-15 23:42:50 +00001042 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001043
Juergen Schmied271ba292000-01-15 23:42:50 +00001044 switch (*(LPDWORD)base)
1045 {
1046 /* windows 95 'creg' */
1047 case W95_REG_CREG_ID:
1048 {
1049 _w95creg * creg;
1050 _w95rgkn * rgkn;
1051 creg = base;
Alexandre Julliardad28d392000-07-09 11:20:59 +00001052 TRACE("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
Juergen Schmied271ba292000-01-15 23:42:50 +00001053
1054 /* load the header (rgkn) */
1055 rgkn = (_w95rgkn*)(creg + 1);
1056 if (rgkn->id != W95_REG_RGKN_ID)
1057 {
1058 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1059 goto error1;
1060 }
1061
1062 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1063 }
1064 break;
1065 /* nt 'regf'*/
1066 case NT_REG_HEADER_BLOCK_ID:
1067 {
1068 nt_regf * regf;
1069 nt_hbin * hbin;
1070 nt_hbin_sub * hbin_sub;
1071 nt_nk* nk;
1072
Alexandre Julliardad28d392000-07-09 11:20:59 +00001073 TRACE("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
Juergen Schmied271ba292000-01-15 23:42:50 +00001074
1075 /* start block */
1076 regf = base;
1077
1078 /* hbin block */
Juergen Schmied6889c682000-04-28 19:59:48 +00001079 hbin = (nt_hbin*)((char*) base + 0x1000);
Juergen Schmied271ba292000-01-15 23:42:50 +00001080 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1081 {
Alexandre Julliardad28d392000-07-09 11:20:59 +00001082 ERR( "%s hbin block invalid\n", fn);
Juergen Schmied271ba292000-01-15 23:42:50 +00001083 goto error1;
1084 }
1085
1086 /* hbin_sub block */
1087 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1088 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1089 {
Alexandre Julliardad28d392000-07-09 11:20:59 +00001090 ERR( "%s hbin_sub block invalid\n", fn);
Juergen Schmied271ba292000-01-15 23:42:50 +00001091 goto error1;
1092 }
1093
1094 /* nk block */
1095 nk = (nt_nk*)&(hbin_sub->data[0]);
1096 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1097 {
Alexandre Julliardad28d392000-07-09 11:20:59 +00001098 ERR( "%s special nk block not found\n", fn);
Juergen Schmied271ba292000-01-15 23:42:50 +00001099 goto error1;
1100 }
1101
Patrik Stridvall0ee98cc2000-02-26 13:17:55 +00001102 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
Juergen Schmied271ba292000-01-15 23:42:50 +00001103 }
1104 break;
1105 default:
1106 {
1107 ERR("unknown signature in registry file %s.\n",fn);
1108 goto error1;
1109 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001110 }
Juergen Schmied0311eb32000-01-17 22:23:10 +00001111 if(!ret) ERR("error loading registry file %s\n", fn);
Juergen Schmied271ba292000-01-15 23:42:50 +00001112error1: munmap(base, st.st_size);
1113error: close(fd);
1114 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001115}
1116
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001117/* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001118/*
1119 reghack - windows 3.11 registry data format demo program.
1120
1121 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1122 a combined hash table and tree description, and finally a text table.
1123
1124 The header is obvious from the struct header. The taboff1 and taboff2
1125 fields are always 0x20, and their usage is unknown.
1126
1127 The 8-byte entry table has various entry types.
1128
1129 tabent[0] is a root index. The second word has the index of the root of
1130 the directory.
1131 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1132 the index of the key/value that has that hash. Data with the same
1133 hash value are on a circular list. The other three words in the
1134 hash entry are always zero.
1135 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1136 entry: dirent and keyent/valent. They are identified by context.
1137 tabent[freeidx] is the first free entry. The first word in a free entry
1138 is the index of the next free entry. The last has 0 as a link.
1139 The other three words in the free list are probably irrelevant.
1140
1141 Entries in text table are preceeded by a word at offset-2. This word
1142 has the value (2*index)+1, where index is the referring keyent/valent
1143 entry in the table. I have no suggestion for the 2* and the +1.
1144 Following the word, there are N bytes of data, as per the keyent/valent
1145 entry length. The offset of the keyent/valent entry is from the start
1146 of the text table to the first data byte.
1147
1148 This information is not available from Microsoft. The data format is
1149 deduced from the reg.dat file by me. Mistakes may
1150 have been made. I claim no rights and give no guarantees for this program.
1151
1152 Tor Sjøwall, tor@sn.no
1153*/
1154
1155/* reg.dat header format */
1156struct _w31_header {
1157 char cookie[8]; /* 'SHCC3.10' */
1158 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1159 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1160 unsigned long tabcnt; /* number of entries in index table */
1161 unsigned long textoff; /* offset of text part */
1162 unsigned long textsize; /* byte size of text part */
1163 unsigned short hashsize; /* hash size */
1164 unsigned short freeidx; /* free index */
1165};
1166
1167/* generic format of table entries */
1168struct _w31_tabent {
1169 unsigned short w0, w1, w2, w3;
1170};
1171
1172/* directory tabent: */
1173struct _w31_dirent {
1174 unsigned short sibling_idx; /* table index of sibling dirent */
1175 unsigned short child_idx; /* table index of child dirent */
1176 unsigned short key_idx; /* table index of key keyent */
1177 unsigned short value_idx; /* table index of value valent */
1178};
1179
1180/* key tabent: */
1181struct _w31_keyent {
1182 unsigned short hash_idx; /* hash chain index for string */
1183 unsigned short refcnt; /* reference count */
1184 unsigned short length; /* length of string */
1185 unsigned short string_off; /* offset of string in text table */
1186};
1187
1188/* value tabent: */
1189struct _w31_valent {
1190 unsigned short hash_idx; /* hash chain index for string */
1191 unsigned short refcnt; /* reference count */
1192 unsigned short length; /* length of string */
1193 unsigned short string_off; /* offset of string in text table */
1194};
1195
1196/* recursive helper function to display a directory tree */
1197void
1198__w31_dumptree( unsigned short idx,
1199 unsigned char *txt,
1200 struct _w31_tabent *tab,
1201 struct _w31_header *head,
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001202 HKEY hkey,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001203 time_t lastmodified,
1204 int level
1205) {
1206 struct _w31_dirent *dir;
1207 struct _w31_keyent *key;
1208 struct _w31_valent *val;
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001209 HKEY subkey = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001210 static char tail[400];
1211
1212 while (idx!=0) {
1213 dir=(struct _w31_dirent*)&tab[idx];
1214
1215 if (dir->key_idx) {
1216 key = (struct _w31_keyent*)&tab[dir->key_idx];
1217
1218 memcpy(tail,&txt[key->string_off],key->length);
1219 tail[key->length]='\0';
1220 /* all toplevel entries AND the entries in the
1221 * toplevel subdirectory belong to \SOFTWARE\Classes
1222 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001223 if (!level && !lstrcmpA(tail,".classes")) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001224 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001225 idx=dir->sibling_idx;
1226 continue;
1227 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001228 if (subkey) RegCloseKey( subkey );
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001229 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001230 /* only add if leaf node or valued node */
1231 if (dir->value_idx!=0||dir->child_idx==0) {
1232 if (dir->value_idx) {
1233 val=(struct _w31_valent*)&tab[dir->value_idx];
1234 memcpy(tail,&txt[val->string_off],val->length);
1235 tail[val->length]='\0';
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001236 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001237 }
1238 }
1239 } else {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001240 TRACE("strange: no directory key name, idx=%04x\n", idx);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001241 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001242 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001243 idx=dir->sibling_idx;
1244 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001245 if (subkey) RegCloseKey( subkey );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001246}
1247
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001248
1249/******************************************************************************
1250 * _w31_loadreg [Internal]
1251 */
Juergen Schmiedebc2b771998-11-14 18:59:30 +00001252void _w31_loadreg(void) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001253 HFILE hf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001254 struct _w31_header head;
1255 struct _w31_tabent *tab;
1256 unsigned char *txt;
1257 int len;
1258 OFSTRUCT ofs;
1259 BY_HANDLE_FILE_INFORMATION hfinfo;
1260 time_t lastmodified;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001261
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001262 TRACE("(void)\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001263
Alexandre Julliarda3960291999-02-26 11:11:13 +00001264 hf = OpenFile("reg.dat",&ofs,OF_READ);
1265 if (hf==HFILE_ERROR)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001266 return;
1267
1268 /* read & dump header */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001269 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001270 ERR("reg.dat is too short.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +00001271 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272 return;
1273 }
1274 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001275 ERR("reg.dat has bad signature.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +00001276 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001277 return;
1278 }
1279
1280 len = head.tabcnt * sizeof(struct _w31_tabent);
1281 /* read and dump index table */
1282 tab = xmalloc(len);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001283 if (len!=_lread(hf,tab,len)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001284 ERR("couldn't read %d bytes.\n",len);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001285 free(tab);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001286 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001287 return;
1288 }
1289
1290 /* read text */
1291 txt = xmalloc(head.textsize);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001292 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001293 ERR("couldn't seek to textblock.\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001294 free(tab);
1295 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001296 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001297 return;
1298 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001299 if (head.textsize!=_lread(hf,txt,head.textsize)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001300 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001301 free(tab);
1302 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001303 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001304 return;
1305 }
1306
1307 if (!GetFileInformationByHandle(hf,&hfinfo)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001308 ERR("GetFileInformationByHandle failed?.\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001309 free(tab);
1310 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001311 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001312 return;
1313 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001314 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001315 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001316 free(tab);
1317 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001318 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001319 return;
1320}
1321
Alexandre Julliardc9709042000-04-16 17:21:13 +00001322
1323/* configure save files and start the periodic saving timer */
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001324static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
Alexandre Julliardc9709042000-04-16 17:21:13 +00001325{
1326 struct set_registry_levels_request *req = get_req_buffer();
1327
1328 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
Alexandre Julliardc9709042000-04-16 17:21:13 +00001329 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1330
1331 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1332 req->current = 1;
1333 req->saving = !all;
Alexandre Julliardc9709042000-04-16 17:21:13 +00001334 req->period = period * 1000;
1335 server_call( REQ_SET_REGISTRY_LEVELS );
1336
1337 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1338 {
1339 struct save_registry_atexit_request *req = get_req_buffer();
1340 const char *confdir = get_config_dir();
1341 char *str = req->file + strlen(confdir);
1342
1343 if (str + 20 > req->file + server_remaining(req->file))
1344 {
1345 ERR("config dir '%s' too long\n", confdir );
1346 return;
1347 }
1348
1349 strcpy( req->file, confdir );
1350 strcpy( str, "/" SAVE_CURRENT_USER );
1351 req->hkey = HKEY_CURRENT_USER;
1352 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1353
1354 strcpy( req->file, confdir );
1355 strcpy( str, "/" SAVE_LOCAL_MACHINE );
1356 req->hkey = HKEY_LOCAL_MACHINE;
1357 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1358
1359 strcpy( req->file, confdir );
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001360 strcpy( str, "/" SAVE_DEFAULT_USER );
1361 req->hkey = hkey_users_default;
1362 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1363
1364 strcpy( req->file, confdir );
Alexandre Julliardc9709042000-04-16 17:21:13 +00001365 strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1366 req->hkey = HKEY_USERS;
1367 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1368 }
1369}
1370
1371
Juergen Schmied271ba292000-01-15 23:42:50 +00001372/**********************************************************************************
1373 * SetLoadLevel [Internal]
1374 *
1375 * set level to 0 for loading system files
1376 * set level to 1 for loading user files
1377 */
1378static void SetLoadLevel(int level)
1379{
1380 struct set_registry_levels_request *req = get_req_buffer();
1381
1382 req->current = level;
1383 req->saving = 0;
Alexandre Julliardc9709042000-04-16 17:21:13 +00001384 req->period = 0;
Juergen Schmied271ba292000-01-15 23:42:50 +00001385 server_call( REQ_SET_REGISTRY_LEVELS );
1386}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001387
1388/**********************************************************************************
1389 * SHELL_LoadRegistry [Internal]
1390 */
Juergen Schmied8573cc72000-01-30 03:03:23 +00001391#define REG_DONTLOAD -1
1392#define REG_WIN31 0
1393#define REG_WIN95 1
1394#define REG_WINNT 2
1395
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001396void SHELL_LoadRegistry( void )
1397{
Juergen Schmied271ba292000-01-15 23:42:50 +00001398 HKEY hkey;
Juergen Schmied8573cc72000-01-30 03:03:23 +00001399 char windir[MAX_PATHNAME_LEN];
1400 char path[MAX_PATHNAME_LEN];
1401 int systemtype = REG_WIN31;
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001402 HKEY hkey_users_default;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001403
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001404 TRACE("(void)\n");
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001405
Alexandre Julliard2fe57772000-01-25 01:40:27 +00001406 if (!CLIENT_IsBootThread()) return; /* already loaded */
1407
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001408 REGISTRY_Init();
Juergen Schmied271ba292000-01-15 23:42:50 +00001409 SetLoadLevel(0);
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001410
Andreas Mohr2e011a52000-06-01 23:28:25 +00001411 if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default))
1412 hkey_users_default = 0;
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001413
Juergen Schmied8573cc72000-01-30 03:03:23 +00001414 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1415
1416 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1417 {
1418 /* test %windir%/system32/config/system --> winnt */
1419 strcpy(path, windir);
1420 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1421 if(GetFileAttributesA(path) != -1)
1422 {
1423 systemtype = REG_WINNT;
1424 }
1425 else
1426 {
1427 /* test %windir%/system.dat --> win95 */
1428 strcpy(path, windir);
1429 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1430 if(GetFileAttributesA(path) != -1)
1431 {
1432 systemtype = REG_WIN95;
1433 }
1434 }
1435
1436 if ((systemtype==REG_WINNT)
1437 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1438 {
1439 MESSAGE("When you are running with a native NT directory specify\n");
1440 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1441 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1442 systemtype = REG_DONTLOAD;
1443 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001444 }
Juergen Schmied8573cc72000-01-30 03:03:23 +00001445 else
1446 {
1447 /* only wine registry */
1448 systemtype = REG_DONTLOAD;
1449 }
1450
1451 switch (systemtype)
1452 {
1453 case REG_WIN31:
1454 _w31_loadreg();
1455 break;
1456
1457 case REG_WIN95:
Nathaniel7bf36ad1999-10-24 19:35:47 +00001458 /* Load windows 95 entries */
Juergen Schmied271ba292000-01-15 23:42:50 +00001459 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
Juergen Schmied8573cc72000-01-30 03:03:23 +00001460
1461 strcpy(path, windir);
1462 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1463 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1464
1465 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001466 {
Juergen Schmied8573cc72000-01-30 03:03:23 +00001467 /* user specific user.dat */
1468 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1469 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1470 {
1471 MESSAGE("can't load win95 user-registry %s\n", path);
1472 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1473 }
1474 /* default user.dat */
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001475 if (hkey_users_default)
Juergen Schmied8573cc72000-01-30 03:03:23 +00001476 {
1477 strcpy(path, windir);
1478 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001479 NativeRegLoadKey(hkey_users_default, path, 1);
Juergen Schmied8573cc72000-01-30 03:03:23 +00001480 }
1481 }
1482 else
1483 {
1484 /* global user.dat */
1485 strcpy(path, windir);
1486 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1487 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1488 }
1489 break;
1490
1491 case REG_WINNT:
1492 /* default user.dat */
1493 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1494 {
1495 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1496 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1497 {
1498 MESSAGE("can't load NT user-registry %s\n", path);
1499 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1500 }
1501 }
1502
1503 /* default user.dat */
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001504 if (hkey_users_default)
Juergen Schmied8573cc72000-01-30 03:03:23 +00001505 {
1506 strcpy(path, windir);
1507 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001508 NativeRegLoadKey(hkey_users_default, path, 1);
Juergen Schmied8573cc72000-01-30 03:03:23 +00001509 }
1510
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001511 /*
1512 * FIXME
1513 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1514 */
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001515
Huw D M Daviese5565ff2000-05-05 18:19:03 +00001516 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1517 {
1518 strcpy(path, windir);
1519 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1520 NativeRegLoadKey(hkey, path, 1);
1521 RegCloseKey(hkey);
1522 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001523
Huw D M Daviese5565ff2000-05-05 18:19:03 +00001524 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1525 {
1526 strcpy(path, windir);
1527 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1528 NativeRegLoadKey(hkey, path, 1);
1529 RegCloseKey(hkey);
1530 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001531
Juergen Schmied8573cc72000-01-30 03:03:23 +00001532 strcpy(path, windir);
1533 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1534 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001535
Juergen Schmied8573cc72000-01-30 03:03:23 +00001536 strcpy(path, windir);
1537 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1538 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001539
Juergen Schmiedc35cce21999-12-20 03:58:44 +00001540 /* this key is generated when the nt-core booted successfully */
1541 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1542 RegCloseKey(hkey);
Juergen Schmied8573cc72000-01-30 03:03:23 +00001543 break;
1544 } /* switch */
1545
Nathaniel7bf36ad1999-10-24 19:35:47 +00001546 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1547 {
1548 /*
1549 * Load the global HKU hive directly from sysconfdir
1550 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001551 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001552
Nathaniel7bf36ad1999-10-24 19:35:47 +00001553 /*
Andreas Mohr2e011a52000-06-01 23:28:25 +00001554 * Load the global machine defaults directly from sysconfdir
Nathaniel7bf36ad1999-10-24 19:35:47 +00001555 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001556 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001557 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001558
Juergen Schmied271ba292000-01-15 23:42:50 +00001559 SetLoadLevel(1);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001560
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001561 /*
1562 * Load the user saved registries
1563 */
Alexandre Julliard08b289d2000-04-06 20:37:37 +00001564 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001565 {
Alexandre Julliard08b289d2000-04-06 20:37:37 +00001566 const char *confdir = get_config_dir();
1567 int len = strlen(confdir) + 20;
1568 char *fn = path;
1569
1570 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001571 /*
1572 * Load user's personal versions of global HKU/.Default keys
1573 */
Alexandre Julliard08b289d2000-04-06 20:37:37 +00001574 if (fn)
1575 {
1576 char *str;
1577 strcpy( fn, confdir );
1578 str = fn + strlen(fn);
1579 *str++ = '/';
Nathan Zorichbd3771c1999-03-14 15:12:48 +00001580
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001581 /* try to load HKU\.Default key only */
1582 strcpy( str, SAVE_DEFAULT_USER );
1583 if (_wine_loadreg( hkey_users_default, fn ))
1584 {
1585 /* if not found load old file containing both HKU\.Default and HKU\user */
1586 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1587 _wine_loadreg( HKEY_USERS, fn );
1588 }
Nathan Zorichbd3771c1999-03-14 15:12:48 +00001589
Alexandre Julliard08b289d2000-04-06 20:37:37 +00001590 strcpy( str, SAVE_CURRENT_USER );
1591 _wine_loadreg( HKEY_CURRENT_USER, fn );
1592
1593 strcpy( str, SAVE_LOCAL_MACHINE );
1594 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1595
1596 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1597 }
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001598 }
Alexandre Julliarda01004d2000-05-14 22:57:57 +00001599 SHELL_InitRegistrySaving( hkey_users_default );
1600 RegCloseKey( hkey_users_default );
Alexandre Julliardfe085682000-03-18 21:56:10 +00001601}
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001602
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001603/********************* API FUNCTIONS ***************************************/
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001604
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001605
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001606
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001607
1608/******************************************************************************
1609 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
Andreas Mohrd4b13da1999-08-07 14:17:10 +00001610 * Immediately writes key to registry.
1611 * Only returns after data has been written to disk.
1612 *
1613 * FIXME: does it really wait until data is written ?
1614 *
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001615 * PARAMS
1616 * hkey [I] Handle of key to write
1617 *
1618 * RETURNS
1619 * Success: ERROR_SUCCESS
1620 * Failure: Error code
1621 */
1622DWORD WINAPI RegFlushKey( HKEY hkey )
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001623{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001624 FIXME( "(%x): stub\n", hkey );
1625 return ERROR_SUCCESS;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001626}
1627
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001628/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001629 * RegConnectRegistryW [ADVAPI32.128]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001630 *
1631 * PARAMS
1632 * lpMachineName [I] Address of name of remote computer
1633 * hHey [I] Predefined registry handle
1634 * phkResult [I] Address of buffer for remote registry handle
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001635 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001636LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001637 LPHKEY phkResult )
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001638{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001639 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001640
1641 if (!lpMachineName || !*lpMachineName) {
1642 /* Use the local machine name */
1643 return RegOpenKey16( hKey, "", phkResult );
1644 }
1645
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001646 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001647 return ERROR_BAD_NETPATH;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001648}
1649
1650
1651/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001652 * RegConnectRegistryA [ADVAPI32.127]
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001653 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001654LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001655{
Alexandre Julliardad28d392000-07-09 11:20:59 +00001656 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1657 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1658 HeapFree( GetProcessHeap(), 0, machineW );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001659 return ret;
Alexandre Julliard01d63461997-01-20 19:43:45 +00001660}
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001661
1662
1663/******************************************************************************
1664 * RegGetKeySecurity [ADVAPI32.144]
1665 * Retrieves a copy of security descriptor protecting the registry key
1666 *
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001667 * PARAMS
1668 * hkey [I] Open handle of key to set
1669 * SecurityInformation [I] Descriptor contents
1670 * pSecurityDescriptor [O] Address of descriptor for key
1671 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1672 *
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001673 * RETURNS
1674 * Success: ERROR_SUCCESS
1675 * Failure: Error code
1676 */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001677LONG WINAPI RegGetKeySecurity( HKEY hkey,
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001678 SECURITY_INFORMATION SecurityInformation,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001679 PSECURITY_DESCRIPTOR pSecurityDescriptor,
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001680 LPDWORD lpcbSecurityDescriptor )
1681{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001682 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001683 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001684
Alexandre Julliard642d3131998-07-12 19:29:36 +00001685 /* FIXME: Check for valid SecurityInformation values */
1686
Alexandre Julliardb24fc081999-02-25 16:36:07 +00001687 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001688 return ERROR_INSUFFICIENT_BUFFER;
1689
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001690 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001691 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1692
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001693 return ERROR_SUCCESS;
1694}
1695
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001696
1697/******************************************************************************
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001698 * RegNotifyChangeKeyValue [ADVAPI32.???]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001699 *
1700 * PARAMS
1701 * hkey [I] Handle of key to watch
1702 * fWatchSubTree [I] Flag for subkey notification
1703 * fdwNotifyFilter [I] Changes to be reported
1704 * hEvent [I] Handle of signaled event
1705 * fAsync [I] Flag for asynchronous reporting
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001706 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001707LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1708 DWORD fdwNotifyFilter, HANDLE hEvent,
1709 BOOL fAsync )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001710{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001711 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001712 hEvent,fAsync);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001713 return ERROR_SUCCESS;
1714}
1715
Alexandre Julliarda845b881998-06-01 10:44:35 +00001716
1717/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001718 * RegUnLoadKeyW [ADVAPI32.173]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001719 *
1720 * PARAMS
1721 * hkey [I] Handle of open key
1722 * lpSubKey [I] Address of name of subkey to unload
Alexandre Julliarda845b881998-06-01 10:44:35 +00001723 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001724LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001725{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001726 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
Alexandre Julliarda845b881998-06-01 10:44:35 +00001727 return ERROR_SUCCESS;
1728}
1729
1730
1731/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001732 * RegUnLoadKeyA [ADVAPI32.172]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001733 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001734LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001735{
Alexandre Julliardad28d392000-07-09 11:20:59 +00001736 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1737 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1738 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001739 return ret;
1740}
1741
1742
1743/******************************************************************************
1744 * RegSetKeySecurity [ADVAPI32.167]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001745 *
1746 * PARAMS
1747 * hkey [I] Open handle of key to set
1748 * SecurityInfo [I] Descriptor contents
1749 * pSecurityDesc [I] Address of descriptor for key
Alexandre Julliarda845b881998-06-01 10:44:35 +00001750 */
1751LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001752 PSECURITY_DESCRIPTOR pSecurityDesc )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001753{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001754 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001755
1756 /* It seems to perform this check before the hkey check */
1757 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1758 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1759 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1760 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1761 /* Param OK */
1762 } else
1763 return ERROR_INVALID_PARAMETER;
1764
1765 if (!pSecurityDesc)
1766 return ERROR_INVALID_PARAMETER;
1767
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001768 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001769
Alexandre Julliarda845b881998-06-01 10:44:35 +00001770 return ERROR_SUCCESS;
1771}
1772
1773
1774/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001775 * RegRestoreKeyW [ADVAPI32.164]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001776 *
1777 * PARAMS
1778 * hkey [I] Handle of key where restore begins
1779 * lpFile [I] Address of filename containing saved tree
1780 * dwFlags [I] Optional flags
Alexandre Julliarda845b881998-06-01 10:44:35 +00001781 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001782LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001783{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001784 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001785
1786 /* It seems to do this check before the hkey check */
1787 if (!lpFile || !*lpFile)
1788 return ERROR_INVALID_PARAMETER;
1789
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001790 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001791
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001792 /* Check for file existence */
1793
Alexandre Julliarda845b881998-06-01 10:44:35 +00001794 return ERROR_SUCCESS;
1795}
1796
1797
1798/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001799 * RegRestoreKeyA [ADVAPI32.163]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001800 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001801LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001802{
Alexandre Julliardad28d392000-07-09 11:20:59 +00001803 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1804 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1805 HeapFree( GetProcessHeap(), 0, lpFileW );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001806 return ret;
1807}
1808
1809
1810/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001811 * RegReplaceKeyW [ADVAPI32.162]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001812 *
1813 * PARAMS
1814 * hkey [I] Handle of open key
1815 * lpSubKey [I] Address of name of subkey
1816 * lpNewFile [I] Address of filename for file with new data
1817 * lpOldFile [I] Address of filename for backup file
Alexandre Julliarda845b881998-06-01 10:44:35 +00001818 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001819LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
Alexandre Julliarda845b881998-06-01 10:44:35 +00001820 LPCWSTR lpOldFile )
1821{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001822 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
Alexandre Julliard642d3131998-07-12 19:29:36 +00001823 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
Alexandre Julliarda845b881998-06-01 10:44:35 +00001824 return ERROR_SUCCESS;
1825}
1826
1827
1828/******************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001829 * RegReplaceKeyA [ADVAPI32.161]
Alexandre Julliarda845b881998-06-01 10:44:35 +00001830 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001831LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
Alexandre Julliarda845b881998-06-01 10:44:35 +00001832 LPCSTR lpOldFile )
1833{
Alexandre Julliardad28d392000-07-09 11:20:59 +00001834 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1835 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1836 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1837 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1838 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1839 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1840 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001841 return ret;
1842}
1843
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001844
1845
1846
1847
1848
1849/* 16-bit functions */
1850
1851/* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1852 * some programs. Do not remove those cases. -MM
1853 */
1854static inline void fix_win16_hkey( HKEY *hkey )
1855{
1856 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1857}
1858
1859/******************************************************************************
1860 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1861 */
1862DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1863{
1864 fix_win16_hkey( &hkey );
1865 return RegEnumKeyA( hkey, index, name, name_len );
1866}
1867
1868/******************************************************************************
1869 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1870 */
1871DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1872{
1873 fix_win16_hkey( &hkey );
1874 return RegOpenKeyA( hkey, name, retkey );
1875}
1876
1877/******************************************************************************
1878 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1879 */
1880DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1881{
1882 fix_win16_hkey( &hkey );
1883 return RegCreateKeyA( hkey, name, retkey );
1884}
1885
1886/******************************************************************************
1887 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1888 */
1889DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1890{
1891 fix_win16_hkey( &hkey );
1892 return RegDeleteKeyA( hkey, name );
1893}
1894
1895/******************************************************************************
1896 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1897 */
1898DWORD WINAPI RegCloseKey16( HKEY hkey )
1899{
1900 fix_win16_hkey( &hkey );
1901 return RegCloseKey( hkey );
1902}
1903
1904/******************************************************************************
1905 * RegSetValue16 [KERNEL.221] [SHELL.5]
1906 */
1907DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1908{
1909 fix_win16_hkey( &hkey );
1910 return RegSetValueA( hkey, name, type, data, count );
1911}
1912
1913/******************************************************************************
1914 * RegDeleteValue16 [KERNEL.222]
1915 */
1916DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1917{
1918 fix_win16_hkey( &hkey );
1919 return RegDeleteValueA( hkey, name );
1920}
1921
1922/******************************************************************************
1923 * RegEnumValue16 [KERNEL.223]
1924 */
1925DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1926 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1927{
1928 fix_win16_hkey( &hkey );
1929 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1930}
1931
1932/******************************************************************************
1933 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1934 *
1935 * NOTES
1936 * Is this HACK still applicable?
1937 *
1938 * HACK
1939 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1940 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1941 * Aldus FH4)
1942 */
1943DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1944{
1945 fix_win16_hkey( &hkey );
1946 if (count) *count &= 0xffff;
1947 return RegQueryValueA( hkey, name, data, count );
1948}
1949
1950/******************************************************************************
1951 * RegQueryValueEx16 [KERNEL.225]
1952 */
1953DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1954 LPBYTE data, LPDWORD count )
1955{
1956 fix_win16_hkey( &hkey );
1957 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1958}
1959
1960/******************************************************************************
1961 * RegSetValueEx16 [KERNEL.226]
1962 */
1963DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1964 CONST BYTE *data, DWORD count )
1965{
1966 fix_win16_hkey( &hkey );
1967 return RegSetValueExA( hkey, name, reserved, type, data, count );
1968}