blob: e6c9b1765150927a80903e15c4f3b2e8a53391be [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>
26#include <unistd.h>
27#include <ctype.h>
Alexandre Julliard8664b891996-04-05 14:58:24 +000028#include <errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000029#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000030#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000031#endif
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000032#include <sys/types.h>
Patrik Stridvall6afc68a2000-01-04 00:32:38 +000033#include <fcntl.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000034#include <sys/fcntl.h>
35#include <sys/stat.h>
Alexandre Julliard0623a6f1998-01-18 18:01:49 +000036#include <assert.h>
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000037#include <time.h>
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000038#include "windef.h"
39#include "winbase.h"
40#include "wine/winbase16.h"
41#include "wine/winestring.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000042#include "winerror.h"
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +000043#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000044#include "heap.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000045#include "debugtools.h"
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000046#include "xmalloc.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 Julliard2fab2ef1999-11-23 19:41:34 +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
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000057/* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
Sylvain St.Germaine5332221999-04-10 16:46:15 +000058#define WINE_PREFIX "/.wine"
Marcus Meissneradf8a0c1999-06-12 08:18:38 +000059#define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
60#define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000061
62/* relative in ~user/.wine/ : */
Sylvain St.Germaine5332221999-04-10 16:46:15 +000063#define SAVE_CURRENT_USER "user.reg"
64#define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
65#define SAVE_LOCAL_MACHINE "system.reg"
Alexandre Julliardcdcdede1996-04-21 14:57:41 +000066
Sylvain St.Germaine5332221999-04-10 16:46:15 +000067#define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
68#define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000069
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000070
71/* what valuetypes do we need to convert? */
72#define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
73
Alexandre Julliarde658d821997-11-30 17:45:40 +000074
Alexandre Julliardf90efa91998-06-14 15:24:15 +000075
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000076/*
Alexandre Julliardf90efa91998-06-14 15:24:15 +000077 * QUESTION
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000078 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
Alexandre Julliarda845b881998-06-01 10:44:35 +000080 * ANSWER
81 * No, the memory handling functions are called very often in here,
82 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
83 * loading 100 times slower. -MM
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000084 */
Alexandre Julliarde658d821997-11-30 17:45:40 +000085static LPWSTR strdupA2W(LPCSTR src)
86{
Alexandre Julliardf90efa91998-06-14 15:24:15 +000087 if(src) {
Alexandre Julliarde658d821997-11-30 17:45:40 +000088 LPWSTR dest=xmalloc(2*strlen(src)+2);
89 lstrcpyAtoW(dest,src);
90 return dest;
Alexandre Julliardf90efa91998-06-14 15:24:15 +000091 }
92 return NULL;
Alexandre Julliarde658d821997-11-30 17:45:40 +000093}
94
Alexandre Julliardf90efa91998-06-14 15:24:15 +000095LPWSTR strcvtA2W(LPCSTR src, int nchars)
96
97{
98 LPWSTR dest = xmalloc (2 * nchars + 2);
99
100 lstrcpynAtoW(dest,src,nchars+1);
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000101 return dest;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000102}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000103
104
105
106/******************************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +0000107 * REGISTRY_Init [Internal]
108 * Registry initialisation, allocates some default keys.
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000109 */
Juergen Schmiedebc2b771998-11-14 18:59:30 +0000110static void REGISTRY_Init(void) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000111 HKEY hkey;
112 char buf[200];
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000113
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000114 TRACE("(void)\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000115
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000116 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000117 RegCloseKey(hkey);
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000118
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000119 /* This was an Open, but since it is called before the real registries
120 are loaded, it was changed to a Create - MTB 980507*/
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000121 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000122 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000123 RegCloseKey(hkey);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000124
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000125 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
126 * CurrentVersion
127 * CurrentBuildNumber
128 * CurrentType
129 * string RegisteredOwner
130 * string RegisteredOrganization
131 *
132 */
133 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
134 * string SysContact
135 * string SysLocation
136 * SysServices
Huw D M Daviesf49cb521999-11-12 00:58:15 +0000137 */
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000138 if (-1!=gethostname(buf,200)) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000139 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
140 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000141 RegCloseKey(hkey);
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000142 }
143}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000144
145
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000146/************************ SAVE Registry Function ****************************/
147
148#define REGISTRY_SAVE_VERSION 0x00000001
149
150/* Registry saveformat:
151 * If you change it, increase above number by 1, which will flush
152 * old registry database files.
153 *
154 * Global:
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000155 * "WINE REGISTRY Version %d"
156 * subkeys....
157 * Subkeys:
158 * keyname
159 * valuename=lastmodified,type,data
160 * ...
161 * subkeys
162 * ...
163 * keyname,valuename,stringdata:
164 * the usual ascii characters from 0x00-0xff (well, not 0x00)
165 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
166 * ( "=\\\t" escaped in \uXXXX form.)
167 * type,lastmodified:
168 * int
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000169 *
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000170 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000171 *
172 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
173 * SaveOnlyUpdatedKeys=yes
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000174 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000175
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000176/* Same as RegSaveKey but with Unix pathnames */
177static void save_key( HKEY hkey, const char *filename )
178{
179 struct save_registry_request *req = get_req_buffer();
180 int count = 0;
181 DWORD ret;
182 HANDLE handle;
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000183 char *p;
184 char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000185
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000186 if (!name) return;
187 strcpy( name, filename );
188 if ((p = strrchr( name, '/' ))) p++;
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000189 else p = name;
190
191 for (;;)
192 {
193 sprintf( p, "reg%04x.tmp", count++ );
194 handle = FILE_CreateFile( name, GENERIC_WRITE, 0, NULL,
195 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
196 if (handle != INVALID_HANDLE_VALUE) break;
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000197 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) break;
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000198 }
199
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000200 if (handle != INVALID_HANDLE_VALUE)
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000201 {
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000202 req->hkey = hkey;
203 req->file = handle;
204 ret = server_call_noerr( REQ_SAVE_REGISTRY );
205 CloseHandle( handle );
206 if (ret) unlink( name );
207 else if (rename( name, filename ) == -1)
208 {
209 ERR( "Failed to move %s to %s: ", name, filename );
210 perror( "rename" );
211 unlink( name );
212 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000213 }
Alexandre Julliard6b34fed1999-11-25 22:15:11 +0000214 HeapFree( GetProcessHeap(), 0, name );
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000215}
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000216
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000217
218/******************************************************************************
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000219 * SHELL_SaveRegistryBranch [Internal]
220 *
221 * Saves main registry branch specified by hkey.
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000222 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000223static void SHELL_SaveRegistryBranch(HKEY hkey)
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000224{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000225 char *fn, *home;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000226
Nathaniel7bf36ad1999-10-24 19:35:47 +0000227 /* Find out what to save to, get from config file */
228 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
229 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
230
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000231 /* FIXME: does this check apply to all keys written below ? */
Alexandre Julliard154c99b1999-04-25 12:41:36 +0000232 if (!(home = getenv( "HOME" )))
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000233 ERR("Failed to get homedirectory of UID %ld.\n",(long) getuid());
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000234
Nathaniel7bf36ad1999-10-24 19:35:47 +0000235 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
236 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000237
Nathaniel7bf36ad1999-10-24 19:35:47 +0000238 switch (hkey)
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000239 {
Nathaniel7bf36ad1999-10-24 19:35:47 +0000240 case HKEY_CURRENT_USER:
241 fn = xmalloc( MAX_PATHNAME_LEN );
242 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
243 fn, MAX_PATHNAME_LEN - 1))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000244 save_key( HKEY_CURRENT_USER, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000245 free (fn);
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000246
Nathaniel7bf36ad1999-10-24 19:35:47 +0000247 if (home && writeToHome)
248 {
249 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
250 strlen(SAVE_CURRENT_USER) + 2 );
251 strcpy(fn,home);
252 strcat(fn,WINE_PREFIX);
Alexandre Julliard154c99b1999-04-25 12:41:36 +0000253
Nathaniel7bf36ad1999-10-24 19:35:47 +0000254 /* create the directory. don't care about errorcodes. */
255 mkdir(fn,0755); /* drwxr-xr-x */
256 strcat(fn,"/"SAVE_CURRENT_USER);
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000257 save_key( HKEY_CURRENT_USER, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000258 free(fn);
Alexandre Julliard154c99b1999-04-25 12:41:36 +0000259 }
Nathaniel7bf36ad1999-10-24 19:35:47 +0000260 break;
261 case HKEY_LOCAL_MACHINE:
262 /* Try first saving according to the defined location in .winerc */
263 fn = xmalloc ( MAX_PATHNAME_LEN);
264 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
265 fn, MAX_PATHNAME_LEN - 1))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000266 save_key( HKEY_LOCAL_MACHINE, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000267 free (fn);
Nathan Zorichbd3771c1999-03-14 15:12:48 +0000268
Nathaniel7bf36ad1999-10-24 19:35:47 +0000269 if (home && writeToHome)
270 {
271 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
272 strlen(SAVE_LOCAL_MACHINE) + 2);
273 strcpy(fn,home);
274 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000275 save_key( HKEY_LOCAL_MACHINE, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000276 free(fn);
Alexandre Julliard154c99b1999-04-25 12:41:36 +0000277 }
Nathaniel7bf36ad1999-10-24 19:35:47 +0000278 break;
279 case HKEY_USERS:
280 fn = xmalloc( MAX_PATHNAME_LEN );
281 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
282 fn, MAX_PATHNAME_LEN - 1))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000283 save_key( HKEY_USERS, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000284 free (fn);
Nathan Zorichbd3771c1999-03-14 15:12:48 +0000285
Nathaniel7bf36ad1999-10-24 19:35:47 +0000286 if (home && writeToHome)
287 {
288 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
289 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
290 strcpy(fn,home);
291 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000292 save_key( HKEY_USERS, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +0000293 free(fn);
Alexandre Julliard154c99b1999-04-25 12:41:36 +0000294 }
Nathaniel7bf36ad1999-10-24 19:35:47 +0000295 break;
296 default:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000297 ERR("unknown/invalid key handle !\n");
Nathaniel7bf36ad1999-10-24 19:35:47 +0000298 break;
Sylvain St.Germaine5332221999-04-10 16:46:15 +0000299 }
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000300}
301
302
303/******************************************************************************
304 * SHELL_SaveRegistry [Internal]
305 */
306void SHELL_SaveRegistry( void )
307{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000308 struct set_registry_levels_request *req = get_req_buffer();
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000309 char buf[4];
310 HKEY hkey;
311 int all;
312
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000313 TRACE("(void)\n");
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000314
315 all=0;
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000316 if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000317 {
318 strcpy(buf,"yes");
319 }
320 else
321 {
322 DWORD len,junk,type;
323
324 len=4;
325 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
326 VAL_SAVEUPDATED,
327 &junk,
328 &type,
329 buf,
330 &len)) || (type!=REG_SZ))
331 {
332 strcpy(buf,"yes");
333 }
334 RegCloseKey(hkey);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000335 }
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000336
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000337 if (lstrcmpiA(buf,"yes")) all = 1;
Andreas Mohrd4b13da1999-08-07 14:17:10 +0000338
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000339 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
340 req->current = 1;
341 req->saving = !all;
Alexandre Julliard705686e1999-11-24 19:34:32 +0000342 req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000343 server_call( REQ_SET_REGISTRY_LEVELS );
344
345 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
346 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
347 SHELL_SaveRegistryBranch(HKEY_USERS);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000348}
349
Alexandre Julliard705686e1999-11-24 19:34:32 +0000350/* Periodic save callback */
351static void CALLBACK periodic_save( ULONG_PTR dummy )
352{
353 SHELL_SaveRegistry();
354}
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000355
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000356/************************ LOAD Registry Function ****************************/
357
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000358
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000359
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000360/******************************************************************************
361 * _find_or_add_key [Internal]
362 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000363static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000364{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000365 HKEY subkey;
366 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
367 if (keyname) free( keyname );
368 return subkey;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000369}
370
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000371/******************************************************************************
372 * _find_or_add_value [Internal]
373 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000374static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000375{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000376 RegSetValueExW( hkey, name, 0, type, data, len );
377 if (name) free( name );
378 if (data) free( data );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000379}
380
381
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000382/******************************************************************************
383 * _wine_read_line [Internal]
384 *
385 * reads a line including dynamically enlarging the readbuffer and throwing
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000386 * away comments
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000387 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000388static int _wine_read_line( FILE *F, char **buf, int *len )
389{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000390 char *s,*curread;
391 int mylen,curoff;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000392
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000393 curread = *buf;
394 mylen = *len;
395 **buf = '\0';
396 while (1) {
397 while (1) {
398 s=fgets(curread,mylen,F);
399 if (s==NULL)
400 return 0; /* EOF */
401 if (NULL==(s=strchr(curread,'\n'))) {
402 /* buffer wasn't large enough */
403 curoff = strlen(*buf);
404 *buf = xrealloc(*buf,*len*2);
405 curread = *buf + curoff;
406 mylen = *len; /* we filled up the buffer and
407 * got new '*len' bytes to fill
408 */
409 *len = *len * 2;
410 } else {
411 *s='\0';
412 break;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000413 }
414 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000415 /* throw away comments */
416 if (**buf=='#' || **buf==';') {
417 curread = *buf;
418 mylen = *len;
419 continue;
420 }
421 if (s) /* got end of line */
422 break;
423 }
424 return 1;
425}
426
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000427
428/******************************************************************************
429 * _wine_read_USTRING [Internal]
430 *
431 * converts a char* into a UNICODE string (up to a special char)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000432 * and returns the position exactly after that string
433 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000434static char* _wine_read_USTRING( char *buf, LPWSTR *str )
435{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000436 char *s;
437 LPWSTR ws;
438
439 /* read up to "=" or "\0" or "\n" */
440 s = buf;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000441 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
442 ws = *str;
443 while (*s && (*s!='\n') && (*s!='=')) {
444 if (*s!='\\')
445 *ws++=*((unsigned char*)s++);
446 else {
447 s++;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000448 if (!*s) {
449 /* Dangling \ ... may only happen if a registry
450 * write was short. FIXME: What do to?
451 */
452 break;
453 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000454 if (*s=='\\') {
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000455 *ws++='\\';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000456 s++;
457 continue;
458 }
459 if (*s!='u') {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000460 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000461 *ws++='\\';
462 *ws++=*s++;
463 } else {
464 char xbuf[5];
465 int wc;
466
467 s++;
468 memcpy(xbuf,s,4);xbuf[4]='\0';
469 if (!sscanf(xbuf,"%x",&wc))
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000470 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000471 s+=4;
472 *ws++ =(unsigned short)wc;
473 }
474 }
475 }
476 *ws = 0;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000477 return s;
478}
479
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000480
481/******************************************************************************
482 * _wine_loadsubkey [Internal]
483 *
484 * NOTES
485 * It seems like this is returning a boolean. Should it?
486 *
487 * RETURNS
488 * Success: 1
489 * Failure: 0
490 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000491static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000492{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000493 HKEY subkey;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000494 int i;
495 char *s;
496 LPWSTR name;
497
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000498 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000499
500 /* Good. We already got a line here ... so parse it */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000501 subkey = 0;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000502 while (1) {
503 i=0;s=*buf;
504 while (*s=='\t') {
505 s++;
506 i++;
507 }
508 if (i>level) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000509 if (!subkey) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000510 WARN("Got a subhierarchy without resp. key?\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000511 return 0;
512 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000513 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
Eric Pouechc0bcf261999-11-04 01:38:11 +0000514 if (!_wine_read_line(F,buf,buflen))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000515 goto done;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000516 continue;
517 }
518
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000519 /* let the caller handle this line */
520 if (i<level || **buf=='\0')
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000521 goto done;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000522
523 /* it can be: a value or a keyname. Parse the name first */
524 s=_wine_read_USTRING(s,&name);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000525
526 /* switch() default: hack to avoid gotos */
527 switch (0) {
528 default:
529 if (*s=='\0') {
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000530 if (subkey) RegCloseKey( subkey );
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000531 subkey=_find_or_add_key(hkey,name);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000532 } else {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000533 LPBYTE data;
534 int len,lastmodified,type;
535
536 if (*s!='=') {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000537 WARN("Unexpected character: %c\n",*s);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000538 break;
539 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000540 s++;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000541 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000542 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000543 break;
544 }
545 /* skip the 2 , */
546 s=strchr(s,',');s++;
Eric Pouechc0bcf261999-11-04 01:38:11 +0000547 s=strchr(s,',');
548 if (!s++) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000549 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
Eric Pouechc0bcf261999-11-04 01:38:11 +0000550 break;
551 }
Juergen Schmiedf74fa4e1999-01-31 09:19:46 +0000552 if (type == REG_SZ || type == REG_EXPAND_SZ) {
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000553 s=_wine_read_USTRING(s,(LPWSTR*)&data);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000554 len = lstrlenW((LPWSTR)data)*2+2;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000555 } else {
556 len=strlen(s)/2;
557 data = (LPBYTE)xmalloc(len+1);
558 for (i=0;i<len;i++) {
559 data[i]=0;
560 if (*s>='0' && *s<='9')
561 data[i]=(*s-'0')<<4;
562 if (*s>='a' && *s<='f')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000563 data[i]=(*s-'a'+'\xa')<<4;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000564 if (*s>='A' && *s<='F')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000565 data[i]=(*s-'A'+'\xa')<<4;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000566 s++;
567 if (*s>='0' && *s<='9')
568 data[i]|=*s-'0';
569 if (*s>='a' && *s<='f')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000570 data[i]|=*s-'a'+'\xa';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000571 if (*s>='A' && *s<='F')
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000572 data[i]|=*s-'A'+'\xa';
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000573 s++;
574 }
575 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000576 _find_or_add_value(hkey,name,type,data,len);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000577 }
578 }
579 /* read the next line */
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000580 if (!_wine_read_line(F,buf,buflen))
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000581 goto done;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000582 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +0000583 done:
584 if (subkey) RegCloseKey( subkey );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000585 return 1;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000586}
587
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000588
589/******************************************************************************
590 * _wine_loadsubreg [Internal]
591 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000592static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000593{
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000594 int ver;
595 char *buf;
596 int buflen;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000597
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000598 buf=xmalloc(10);buflen=10;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000599 if (!_wine_read_line(F,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000600 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000601 return 0;
602 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000603 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
604 free(buf);
605 return 0;
606 }
607 if (ver!=REGISTRY_SAVE_VERSION) {
Alexandre Julliard53f3a831999-11-24 04:19:43 +0000608 if (ver == 2) /* new version */
609 {
610 HANDLE file;
611 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
612 FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
613 {
614 struct load_registry_request *req = get_req_buffer();
615 req->hkey = hkey;
616 req->file = file;
617 req->name[0] = 0;
618 server_call( REQ_LOAD_REGISTRY );
619 CloseHandle( file );
620 }
621 free( buf );
622 return 1;
623 }
624 else
625 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000626 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000627 free(buf);
628 return 0;
Alexandre Julliard53f3a831999-11-24 04:19:43 +0000629 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000630 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000631 if (!_wine_read_line(F,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000632 free(buf);
633 return 0;
634 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000635 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000636 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000637 return 0;
638 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000639 free(buf);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000640 return 1;
641}
642
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000643
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000644/******************************************************************************
645 * _wine_loadreg [Internal]
646 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000647static void _wine_loadreg( HKEY hkey, char *fn )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000648{
649 FILE *F;
650
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000651 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000652
653 F = fopen(fn,"rb");
654 if (F==NULL) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000655 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000656 return;
657 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +0000658 _wine_loadsubreg(F,hkey,fn);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000659 fclose(F);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000660}
661
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000662/* NT REGISTRY LOADER */
Patrik Stridvall6afc68a2000-01-04 00:32:38 +0000663
664#ifdef HAVE_SYS_MMAN_H
665# include <sys/mman.h>
666#endif
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000667
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000668#ifndef MAP_FAILED
669#define MAP_FAILED ((LPVOID)-1)
670#endif
671
Juergen Schmied271ba292000-01-15 23:42:50 +0000672#define NT_REG_BLOCK_SIZE 0x1000
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000673
Juergen Schmied271ba292000-01-15 23:42:50 +0000674#define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
675#define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
676#define NT_REG_KEY_BLOCK_ID 0x6b6e
677#define NT_REG_VALUE_BLOCK_ID 0x6b76
678#define NT_REG_HASH_BLOCK_ID 0x666c
679#define NT_REG_NOHASH_BLOCK_ID 0x696c
680#define NT_REG_KEY_BLOCK_TYPE 0x20
681#define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000682
683typedef struct
684{
685 DWORD id; /* 0x66676572 'regf'*/
686 DWORD uk1; /* 0x04 */
687 DWORD uk2; /* 0x08 */
688 FILETIME DateModified; /* 0x0c */
689 DWORD uk3; /* 0x14 */
690 DWORD uk4; /* 0x18 */
691 DWORD uk5; /* 0x1c */
692 DWORD uk6; /* 0x20 */
693 DWORD RootKeyBlock; /* 0x24 */
694 DWORD BlockSize; /* 0x28 */
695 DWORD uk7[116];
696 DWORD Checksum; /* at offset 0x1FC */
697} nt_regf;
698
699typedef struct
700{
701 DWORD blocksize;
702 BYTE data[1];
703} nt_hbin_sub;
704
705typedef struct
706{
707 DWORD id; /* 0x6E696268 'hbin' */
708 DWORD off_prev;
709 DWORD off_next;
710 DWORD uk1;
711 DWORD uk2; /* 0x10 */
712 DWORD uk3; /* 0x14 */
713 DWORD uk4; /* 0x18 */
714 DWORD size; /* 0x1C */
715 nt_hbin_sub hbin_sub; /* 0x20 */
716} nt_hbin;
717
718/*
719 * the value_list consists of offsets to the values (vk)
720 */
721typedef struct
722{
723 WORD SubBlockId; /* 0x00 0x6B6E */
724 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
725 FILETIME writetime; /* 0x04 */
726 DWORD uk1; /* 0x0C */
727 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
728 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
729 DWORD uk8; /* 0x18 */
730 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
731 DWORD uk2; /* 0x20 */
732 DWORD nr_values; /* 0x24 number of values */
733 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
734 DWORD off_sk; /* 0x2c Offset of the sk-Record */
735 DWORD off_class; /* 0x30 Offset of the Class-Name */
736 DWORD uk3; /* 0x34 */
737 DWORD uk4; /* 0x38 */
738 DWORD uk5; /* 0x3c */
739 DWORD uk6; /* 0x40 */
740 DWORD uk7; /* 0x44 */
741 WORD name_len; /* 0x48 name-length */
742 WORD class_len; /* 0x4a class-name length */
743 char name[1]; /* 0x4c key-name */
744} nt_nk;
745
746typedef struct
747{
748 DWORD off_nk; /* 0x00 */
749 DWORD name; /* 0x04 */
750} hash_rec;
751
752typedef struct
753{
754 WORD id; /* 0x00 0x666c */
755 WORD nr_keys; /* 0x06 */
756 hash_rec hash_rec[1];
757} nt_lf;
758
759typedef struct
760{
761 WORD id; /* 0x00 0x696c */
762 WORD nr_keys;
763 DWORD off_nk[1];
764} nt_il;
765
766typedef struct
767{
768 WORD id; /* 0x00 'vk' */
769 WORD nam_len;
770 DWORD data_len;
771 DWORD data_off;
772 DWORD type;
773 WORD flag;
774 WORD uk1;
775 char name[1];
776} nt_vk;
777
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000778LPSTR _strdupnA( LPCSTR str, int len )
779{
780 LPSTR ret;
781
782 if (!str) return NULL;
783 ret = malloc( len + 1 );
784 lstrcpynA( ret, str, len );
785 ret[len] = 0x00;
786 return ret;
787}
788
Juergen Schmied271ba292000-01-15 23:42:50 +0000789static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
790static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
791static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000792
793
794/*
795 * gets a value
796 *
797 * vk->flag:
798 * 0 value is a default value
799 * 1 the value has a name
800 *
801 * vk->data_len
802 * len of the whole data block
803 * - reg_sz (unicode)
804 * bytes including the terminating \0 = 2*(number_of_chars+1)
805 * - reg_dword, reg_binary:
806 * if highest bit of data_len is set data_off contains the value
807 */
Juergen Schmied271ba292000-01-15 23:42:50 +0000808static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000809{
810 WCHAR name [256];
Juergen Schmiedc35cce21999-12-20 03:58:44 +0000811 DWORD ret;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000812 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
813
Juergen Schmied271ba292000-01-15 23:42:50 +0000814 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000815
816 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
817
Juergen Schmiedc35cce21999-12-20 03:58:44 +0000818 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000819 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
Juergen Schmiedc35cce21999-12-20 03:58:44 +0000820 (vk->data_len & 0x7fffffff) );
821 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000822 return TRUE;
823error:
824 ERR_(reg)("vk block invalid\n");
825 return FALSE;
826}
827
828/*
829 * get the subkeys
830 *
831 * this structure contains the hash of a keyname and points to all
832 * subkeys
833 *
834 * exception: if the id is 'il' there are no hash values and every
835 * dword is a offset
836 */
Juergen Schmied271ba292000-01-15 23:42:50 +0000837static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000838{
839 int i;
840
Juergen Schmied271ba292000-01-15 23:42:50 +0000841 if (lf->id == NT_REG_HASH_BLOCK_ID)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000842 {
843 for (i=0; i<lf->nr_keys; i++)
844 {
845 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
846 }
847
848 }
Juergen Schmied271ba292000-01-15 23:42:50 +0000849 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000850 {
851 for (i=0; i<lf->nr_keys; i++)
852 {
853 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
854 }
855 }
856 return TRUE;
857
858error: ERR_(reg)("error reading lf block\n");
859 return FALSE;
860}
861
Juergen Schmied271ba292000-01-15 23:42:50 +0000862static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000863{
864 char * name;
865 int i;
866 DWORD * vl;
Juergen Schmied271ba292000-01-15 23:42:50 +0000867 HKEY subkey = hkey;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000868
Juergen Schmied271ba292000-01-15 23:42:50 +0000869 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID) goto error;
870 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
871 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) goto error;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000872
873 /* create the new key */
Juergen Schmied271ba292000-01-15 23:42:50 +0000874 if(level <= 0)
875 {
876 name = _strdupnA( nk->name, nk->name_len+1);
877 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
878 free(name);
879 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000880
881 /* loop through the subkeys */
882 if (nk->nr_subkeys)
883 {
884 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
885 if (nk->nr_subkeys != lf->nr_keys) goto error1;
Juergen Schmied271ba292000-01-15 23:42:50 +0000886 if (!_nt_parse_lf(subkey, base, lf, level-1)) goto error1;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000887 }
888
889 /* loop trough the value list */
890 vl = (DWORD *)(base+nk->valuelist_off+4);
891 for (i=0; i<nk->nr_values; i++)
892 {
893 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
Juergen Schmied271ba292000-01-15 23:42:50 +0000894 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000895 }
896
897 RegCloseKey(subkey);
898 return TRUE;
899
900error1: RegCloseKey(subkey);
901error: ERR_(reg)("error reading nk block\n");
902 return FALSE;
903}
904
Juergen Schmied9e6b1d11999-12-11 23:22:52 +0000905/* end nt loader */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000906
Juergen Schmied271ba292000-01-15 23:42:50 +0000907/* windows 95 registry loader */
908
909/* SECTION 1: main header
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000910 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000911 * once at offset 0
912 */
913#define W95_REG_CREG_ID 0x47455243
914
915typedef struct
916{
917 DWORD id; /* "CREG" = W95_REG_CREG_ID */
918 DWORD version; /* ???? 0x00010000 */
919 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
920 DWORD uk2; /* 0x0c */
921 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
922 WORD uk3;
923 DWORD uk[3];
924 /* rgkn */
925} _w95creg;
926
927/* SECTION 2: Directory information (tree structure)
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000928 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000929 * once on offset 0x20
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000930 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000931 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
932 */
933#define W95_REG_RGKN_ID 0x4e4b4752
934
935typedef struct
936{
937 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
938 DWORD size; /* Size of the RGKN-block */
939 DWORD root_off; /* Rel. Offset of the root-record */
940 DWORD uk[5];
941} _w95rgkn;
942
943/* Disk Key Entry Structure
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000944 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000945 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
946 * hive itself. It looks the same like other keys. Even the ID-number can
947 * be any value.
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000948 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000949 * The "hash"-value is a value representing the key's name. Windows will not
950 * search for the name, but for a matching hash-value. if it finds one, it
951 * will compare the actual string info, otherwise continue with the next key.
952 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
953 * of the string which are smaller than 0x80 (128) to this D-Word.
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000954 *
Juergen Schmied271ba292000-01-15 23:42:50 +0000955 * If you want to modify key names, also modify the hash-values, since they
956 * cannot be found again (although they would be displayed in REGEDIT)
957 * End of list-pointers are filled with 0xFFFFFFFF
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000958 *
959 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
960 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
961 * structure) and reading another RGDB_section.
Juergen Schmied271ba292000-01-15 23:42:50 +0000962 *
963 * there is a one to one relationship between dke and dkh
964 */
965 /* key struct, once per key */
966typedef struct
967{
968 DWORD x1; /* Free entry indicator(?) */
969 DWORD hash; /* sum of bytes of keyname */
970 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
971 DWORD prevlvl; /* offset of previous key */
972 DWORD nextsub; /* offset of child key */
973 DWORD next; /* offset of sibling key */
974 WORD nrLS; /* id inside the rgdb block */
975 WORD nrMS; /* number of the rgdb block */
976} _w95dke;
977
978/* SECTION 3: key information, values and data
979 *
980 * structure:
981 * section: [blocks]* (repeat creg->rgdb_num times)
982 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
983 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000984 *
Alexandre Julliard02e90081998-01-04 17:49:09 +0000985 * An interesting relationship exists in RGDB_section. The value at offset
986 * 10 equals the value at offset 4 minus the value at offset 8. I have no
987 * idea at the moment what this means. (Kevin Cozens)
Juergen Schmied271ba292000-01-15 23:42:50 +0000988 */
989
990/* block header, once per block */
991#define W95_REG_RGDB_ID 0x42444752
992
993typedef struct
994{
995 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
996 DWORD size; /* 0x04 */
997 DWORD uk1; /* 0x08 */
998 DWORD uk2; /* 0x0c */
999 DWORD uk3; /* 0x10 */
1000 DWORD uk4; /* 0x14 */
1001 DWORD uk5; /* 0x18 */
1002 DWORD uk6; /* 0x1c */
1003 /* dkh */
1004} _w95rgdb;
1005
1006/* Disk Key Header structure (RGDB part), once per key */
1007typedef struct
1008{
1009 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
1010 WORD nrLS; /* 0x04 id inside the rgdb block */
1011 WORD nrMS; /* 0x06 number of the rgdb block */
1012 DWORD bytesused; /* 0x08 */
1013 WORD keynamelen; /* 0x0c len of name */
1014 WORD values; /* 0x0e number of values */
1015 DWORD xx1; /* 0x10 */
1016 char name[1]; /* 0x14 */
1017 /* dkv */ /* 0x14 + keynamelen */
1018} _w95dkh;
1019
1020/* Disk Key Value structure, once per value */
1021typedef struct
1022{
1023 DWORD type; /* 0x00 */
1024 DWORD x1; /* 0x04 */
1025 WORD valnamelen; /* 0x08 length of name, 0 is default key */
1026 WORD valdatalen; /* 0x0A length of data */
1027 char name[1]; /* 0x0c */
1028 /* raw data */ /* 0x0c + valnamelen */
1029} _w95dkv;
1030
1031/******************************************************************************
1032 * _w95_lookup_dkh [Internal]
Alexandre Julliard02e90081998-01-04 17:49:09 +00001033 *
Juergen Schmied271ba292000-01-15 23:42:50 +00001034 * seeks the dkh belonging to a dke
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001035 */
Juergen Schmied271ba292000-01-15 23:42:50 +00001036static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001037{
Juergen Schmied271ba292000-01-15 23:42:50 +00001038 _w95rgdb * rgdb;
1039 _w95dkh * dkh;
1040 int i;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001041
Juergen Schmied271ba292000-01-15 23:42:50 +00001042 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
1043 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001044
Juergen Schmied271ba292000-01-15 23:42:50 +00001045 /* find the right block */
1046 for(i=0; i<nrMS ;i++)
1047 {
1048 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
1049 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001050 }
1051
Juergen Schmied271ba292000-01-15 23:42:50 +00001052 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001053
Juergen Schmied271ba292000-01-15 23:42:50 +00001054 do
1055 {
1056 if(nrLS==dkh->nrLS ) return dkh;
1057 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
1058 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001059
Juergen Schmied271ba292000-01-15 23:42:50 +00001060 return NULL;
1061}
1062
1063/******************************************************************************
1064 * _w95_parse_dkv [Internal]
1065 */
1066static int _w95_parse_dkv (
1067 HKEY hkey,
1068 _w95dkh * dkh,
1069 int nrLS,
1070 int nrMS )
1071{
1072 _w95dkv * dkv;
1073 int i;
1074 DWORD ret;
1075 char * name;
1076
1077 /* first value block */
1078 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001079
Juergen Schmied271ba292000-01-15 23:42:50 +00001080 /* loop trought the values */
1081 for (i=0; i< dkh->values; i++)
1082 {
1083 name = _strdupnA(dkv->name, dkv->valnamelen+1);
1084 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
1085 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1086 free (name);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001087
Juergen Schmied271ba292000-01-15 23:42:50 +00001088 /* next value */
1089 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001090 }
Juergen Schmied271ba292000-01-15 23:42:50 +00001091 return TRUE;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001092}
1093
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001094/******************************************************************************
Juergen Schmied271ba292000-01-15 23:42:50 +00001095 * _w95_parse_dke [Internal]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001096 */
Juergen Schmied271ba292000-01-15 23:42:50 +00001097static int _w95_parse_dke(
1098 HKEY hkey,
1099 _w95creg * creg,
1100 _w95rgkn *rgkn,
1101 _w95dke * dke,
1102 int level )
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001103{
Juergen Schmied271ba292000-01-15 23:42:50 +00001104 _w95dkh * dkh;
1105 HKEY hsubkey = hkey;
1106 char * name;
1107 int ret = FALSE;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001108
Juergen Schmied271ba292000-01-15 23:42:50 +00001109 /* get start address of root key block */
1110 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1111
Juergen Schmied0311eb32000-01-17 22:23:10 +00001112 /* special root key */
1113 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
Juergen Schmied271ba292000-01-15 23:42:50 +00001114 {
Juergen Schmied0311eb32000-01-17 22:23:10 +00001115 /* parse the one subkey*/
1116 if (dke->nextsub != 0xffffffff)
Juergen Schmied271ba292000-01-15 23:42:50 +00001117 {
Juergen Schmied0311eb32000-01-17 22:23:10 +00001118 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
Juergen Schmied271ba292000-01-15 23:42:50 +00001119 }
Juergen Schmied0311eb32000-01-17 22:23:10 +00001120 /* has no sibling keys */
1121 goto error;
Juergen Schmied271ba292000-01-15 23:42:50 +00001122 }
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001123
Juergen Schmied0311eb32000-01-17 22:23:10 +00001124 /* search subblock */
1125 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1126 {
1127 fprintf(stderr, "dke pointing to missing dkh !\n");
1128 goto error;
1129 }
1130
1131 if ( level <= 0 )
1132 {
1133 /* walk sibling keys */
1134 if (dke->next != 0xffffffff )
1135 {
1136 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1137 }
1138
1139 /* create subkey and insert values */
1140 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1141 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1142 free(name);
1143 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1144 }
1145
1146 /* next sub key */
Juergen Schmied271ba292000-01-15 23:42:50 +00001147 if (dke->nextsub != 0xffffffff)
1148 {
Juergen Schmied0311eb32000-01-17 22:23:10 +00001149 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
Juergen Schmied271ba292000-01-15 23:42:50 +00001150 }
Juergen Schmied0311eb32000-01-17 22:23:10 +00001151
Juergen Schmied271ba292000-01-15 23:42:50 +00001152 ret = TRUE;
Juergen Schmied0311eb32000-01-17 22:23:10 +00001153error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
Juergen Schmied271ba292000-01-15 23:42:50 +00001154error: return ret;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001155}
Juergen Schmied271ba292000-01-15 23:42:50 +00001156/* end windows 95 loader */
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001157
1158/******************************************************************************
Juergen Schmied271ba292000-01-15 23:42:50 +00001159 * NativeRegLoadKey [Internal]
1160 *
1161 * Loads a native registry file (win95/nt)
1162 * hkey root key
1163 * fn filename
1164 * level number of levels to cut away (eg. ".Default" in user.dat)
1165 *
1166 * this function intentionally uses unix file functions to make it possible
1167 * to move it to a seperate registry helper programm
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001168 */
Juergen Schmied271ba292000-01-15 23:42:50 +00001169static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001170{
Juergen Schmied271ba292000-01-15 23:42:50 +00001171 int fd = 0;
1172 struct stat st;
1173 DOS_FULL_NAME full_name;
1174 int ret = FALSE;
1175 void * base;
1176
1177 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1178
1179 /* map the registry into the memory */
1180 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1181 if ((fstat(fd, &st) == -1)) goto error;
1182 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001183
Juergen Schmied271ba292000-01-15 23:42:50 +00001184 switch (*(LPDWORD)base)
1185 {
1186 /* windows 95 'creg' */
1187 case W95_REG_CREG_ID:
1188 {
1189 _w95creg * creg;
1190 _w95rgkn * rgkn;
1191 creg = base;
1192 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1193
1194 /* load the header (rgkn) */
1195 rgkn = (_w95rgkn*)(creg + 1);
1196 if (rgkn->id != W95_REG_RGKN_ID)
1197 {
1198 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1199 goto error1;
1200 }
1201
1202 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1203 }
1204 break;
1205 /* nt 'regf'*/
1206 case NT_REG_HEADER_BLOCK_ID:
1207 {
1208 nt_regf * regf;
1209 nt_hbin * hbin;
1210 nt_hbin_sub * hbin_sub;
1211 nt_nk* nk;
1212
1213 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1214
1215 /* start block */
1216 regf = base;
1217
1218 /* hbin block */
1219 hbin = base + 0x1000;
1220 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1221 {
1222 ERR_(reg)( "%s hbin block invalid\n", fn);
1223 goto error1;
1224 }
1225
1226 /* hbin_sub block */
1227 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1228 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1229 {
1230 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1231 goto error1;
1232 }
1233
1234 /* nk block */
1235 nk = (nt_nk*)&(hbin_sub->data[0]);
1236 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1237 {
1238 ERR_(reg)( "%s special nk block not found\n", fn);
1239 goto error1;
1240 }
1241
1242 ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
1243 }
1244 break;
1245 default:
1246 {
1247 ERR("unknown signature in registry file %s.\n",fn);
1248 goto error1;
1249 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001250 }
Juergen Schmied0311eb32000-01-17 22:23:10 +00001251 if(!ret) ERR("error loading registry file %s\n", fn);
Juergen Schmied271ba292000-01-15 23:42:50 +00001252error1: munmap(base, st.st_size);
1253error: close(fd);
1254 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001255}
1256
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001257/* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001258/*
1259 reghack - windows 3.11 registry data format demo program.
1260
1261 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1262 a combined hash table and tree description, and finally a text table.
1263
1264 The header is obvious from the struct header. The taboff1 and taboff2
1265 fields are always 0x20, and their usage is unknown.
1266
1267 The 8-byte entry table has various entry types.
1268
1269 tabent[0] is a root index. The second word has the index of the root of
1270 the directory.
1271 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1272 the index of the key/value that has that hash. Data with the same
1273 hash value are on a circular list. The other three words in the
1274 hash entry are always zero.
1275 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1276 entry: dirent and keyent/valent. They are identified by context.
1277 tabent[freeidx] is the first free entry. The first word in a free entry
1278 is the index of the next free entry. The last has 0 as a link.
1279 The other three words in the free list are probably irrelevant.
1280
1281 Entries in text table are preceeded by a word at offset-2. This word
1282 has the value (2*index)+1, where index is the referring keyent/valent
1283 entry in the table. I have no suggestion for the 2* and the +1.
1284 Following the word, there are N bytes of data, as per the keyent/valent
1285 entry length. The offset of the keyent/valent entry is from the start
1286 of the text table to the first data byte.
1287
1288 This information is not available from Microsoft. The data format is
1289 deduced from the reg.dat file by me. Mistakes may
1290 have been made. I claim no rights and give no guarantees for this program.
1291
1292 Tor Sjøwall, tor@sn.no
1293*/
1294
1295/* reg.dat header format */
1296struct _w31_header {
1297 char cookie[8]; /* 'SHCC3.10' */
1298 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1299 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1300 unsigned long tabcnt; /* number of entries in index table */
1301 unsigned long textoff; /* offset of text part */
1302 unsigned long textsize; /* byte size of text part */
1303 unsigned short hashsize; /* hash size */
1304 unsigned short freeidx; /* free index */
1305};
1306
1307/* generic format of table entries */
1308struct _w31_tabent {
1309 unsigned short w0, w1, w2, w3;
1310};
1311
1312/* directory tabent: */
1313struct _w31_dirent {
1314 unsigned short sibling_idx; /* table index of sibling dirent */
1315 unsigned short child_idx; /* table index of child dirent */
1316 unsigned short key_idx; /* table index of key keyent */
1317 unsigned short value_idx; /* table index of value valent */
1318};
1319
1320/* key tabent: */
1321struct _w31_keyent {
1322 unsigned short hash_idx; /* hash chain index for string */
1323 unsigned short refcnt; /* reference count */
1324 unsigned short length; /* length of string */
1325 unsigned short string_off; /* offset of string in text table */
1326};
1327
1328/* value tabent: */
1329struct _w31_valent {
1330 unsigned short hash_idx; /* hash chain index for string */
1331 unsigned short refcnt; /* reference count */
1332 unsigned short length; /* length of string */
1333 unsigned short string_off; /* offset of string in text table */
1334};
1335
1336/* recursive helper function to display a directory tree */
1337void
1338__w31_dumptree( unsigned short idx,
1339 unsigned char *txt,
1340 struct _w31_tabent *tab,
1341 struct _w31_header *head,
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001342 HKEY hkey,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001343 time_t lastmodified,
1344 int level
1345) {
1346 struct _w31_dirent *dir;
1347 struct _w31_keyent *key;
1348 struct _w31_valent *val;
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001349 HKEY subkey = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001350 static char tail[400];
1351
1352 while (idx!=0) {
1353 dir=(struct _w31_dirent*)&tab[idx];
1354
1355 if (dir->key_idx) {
1356 key = (struct _w31_keyent*)&tab[dir->key_idx];
1357
1358 memcpy(tail,&txt[key->string_off],key->length);
1359 tail[key->length]='\0';
1360 /* all toplevel entries AND the entries in the
1361 * toplevel subdirectory belong to \SOFTWARE\Classes
1362 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001363 if (!level && !lstrcmpA(tail,".classes")) {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001364 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001365 idx=dir->sibling_idx;
1366 continue;
1367 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001368 if (subkey) RegCloseKey( subkey );
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001369 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001370 /* only add if leaf node or valued node */
1371 if (dir->value_idx!=0||dir->child_idx==0) {
1372 if (dir->value_idx) {
1373 val=(struct _w31_valent*)&tab[dir->value_idx];
1374 memcpy(tail,&txt[val->string_off],val->length);
1375 tail[val->length]='\0';
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001376 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001377 }
1378 }
1379 } else {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001380 TRACE("strange: no directory key name, idx=%04x\n", idx);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001381 }
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001382 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001383 idx=dir->sibling_idx;
1384 }
Alexandre Julliardb3d90e41999-11-24 02:46:27 +00001385 if (subkey) RegCloseKey( subkey );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001386}
1387
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001388
1389/******************************************************************************
1390 * _w31_loadreg [Internal]
1391 */
Juergen Schmiedebc2b771998-11-14 18:59:30 +00001392void _w31_loadreg(void) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001393 HFILE hf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001394 struct _w31_header head;
1395 struct _w31_tabent *tab;
1396 unsigned char *txt;
1397 int len;
1398 OFSTRUCT ofs;
1399 BY_HANDLE_FILE_INFORMATION hfinfo;
1400 time_t lastmodified;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001401
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001402 TRACE("(void)\n");
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001403
Alexandre Julliarda3960291999-02-26 11:11:13 +00001404 hf = OpenFile("reg.dat",&ofs,OF_READ);
1405 if (hf==HFILE_ERROR)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001406 return;
1407
1408 /* read & dump header */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001409 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001410 ERR("reg.dat is too short.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +00001411 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001412 return;
1413 }
1414 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001415 ERR("reg.dat has bad signature.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +00001416 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001417 return;
1418 }
1419
1420 len = head.tabcnt * sizeof(struct _w31_tabent);
1421 /* read and dump index table */
1422 tab = xmalloc(len);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001423 if (len!=_lread(hf,tab,len)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001424 ERR("couldn't read %d bytes.\n",len);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001425 free(tab);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001426 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001427 return;
1428 }
1429
1430 /* read text */
1431 txt = xmalloc(head.textsize);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001432 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001433 ERR("couldn't seek to textblock.\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001434 free(tab);
1435 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001436 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001437 return;
1438 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001439 if (head.textsize!=_lread(hf,txt,head.textsize)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001440 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001441 free(tab);
1442 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001443 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001444 return;
1445 }
1446
1447 if (!GetFileInformationByHandle(hf,&hfinfo)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001448 ERR("GetFileInformationByHandle failed?.\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001449 free(tab);
1450 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001451 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001452 return;
1453 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001454 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001455 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001456 free(tab);
1457 free(txt);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001458 _lclose(hf);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001459 return;
1460}
1461
Juergen Schmied271ba292000-01-15 23:42:50 +00001462/**********************************************************************************
1463 * SetLoadLevel [Internal]
1464 *
1465 * set level to 0 for loading system files
1466 * set level to 1 for loading user files
1467 */
1468static void SetLoadLevel(int level)
1469{
1470 struct set_registry_levels_request *req = get_req_buffer();
1471
1472 req->current = level;
1473 req->saving = 0;
1474 req->version = 1;
1475 server_call( REQ_SET_REGISTRY_LEVELS );
1476}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001477
1478/**********************************************************************************
1479 * SHELL_LoadRegistry [Internal]
1480 */
1481void SHELL_LoadRegistry( void )
1482{
Juergen Schmied271ba292000-01-15 23:42:50 +00001483 int save_timeout;
1484 char *fn, *home;
1485 HKEY hkey;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001486
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001487 TRACE("(void)\n");
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001488
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001489 REGISTRY_Init();
Juergen Schmied271ba292000-01-15 23:42:50 +00001490 SetLoadLevel(0);
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001491
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001492 if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1))
Nathaniel7bf36ad1999-10-24 19:35:47 +00001493 {
1494 /* Load windows 3.1 entries */
1495 _w31_loadreg();
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001496 }
1497 if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1))
1498 {
Nathaniel7bf36ad1999-10-24 19:35:47 +00001499 /* Load windows 95 entries */
Juergen Schmied271ba292000-01-15 23:42:50 +00001500 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1501 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "system.dat", 0);
1502 NativeRegLoadKey(HKEY_CURRENT_USER, "user.dat", 1);
Nathaniel7bf36ad1999-10-24 19:35:47 +00001503 }
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001504 if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1))
1505 {
1506 fn = xmalloc( MAX_PATHNAME_LEN );
1507 home = xmalloc ( MAX_PATHNAME_LEN );
1508 if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1))
1509 {
1510 GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1511 strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1512 strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1513 strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
Juergen Schmied271ba292000-01-15 23:42:50 +00001514 NativeRegLoadKey( HKEY_CURRENT_USER, fn, 1 );
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001515 }
1516 /*
1517 * FIXME
1518 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1519 */
1520 GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1521
1522 strcpy(home, fn);
1523 strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
Juergen Schmied271ba292000-01-15 23:42:50 +00001524 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001525
1526 strcpy(home, fn);
1527 strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
Juergen Schmied271ba292000-01-15 23:42:50 +00001528 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001529
1530 strcpy(home, fn);
1531 strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
Juergen Schmied271ba292000-01-15 23:42:50 +00001532 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001533
1534 strcpy(home, fn);
1535 strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
Juergen Schmied271ba292000-01-15 23:42:50 +00001536 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
Juergen Schmied9e6b1d11999-12-11 23:22:52 +00001537
1538 free (home);
1539 free (fn);
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 Schmied9e6b1d11999-12-11 23:22:52 +00001543 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001544
Nathaniel7bf36ad1999-10-24 19:35:47 +00001545 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1546 {
1547 /*
1548 * Load the global HKU hive directly from sysconfdir
1549 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001550 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001551
Nathaniel7bf36ad1999-10-24 19:35:47 +00001552 /*
1553 * Load the global machine defaults directly form sysconfdir
1554 */
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001555 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001556 }
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001557
Juergen Schmied271ba292000-01-15 23:42:50 +00001558 SetLoadLevel(1);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001559
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001560 /*
1561 * Load the user saved registries
1562 */
Nathaniel7bf36ad1999-10-24 19:35:47 +00001563 if (!(home = getenv( "HOME" )))
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001564 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
Marcus Meissner31b9dab1999-10-24 22:08:33 +00001565 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001566 {
Nathaniel7bf36ad1999-10-24 19:35:47 +00001567 /*
1568 * Load user's personal versions of global HKU/.Default keys
1569 */
1570 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1571 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1572 strcpy(fn, home);
1573 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001574 _wine_loadreg( HKEY_USERS, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001575 free(fn);
Nathan Zorichbd3771c1999-03-14 15:12:48 +00001576
Nathaniel7bf36ad1999-10-24 19:35:47 +00001577 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1578 strcpy(fn, home);
1579 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001580 _wine_loadreg( HKEY_CURRENT_USER, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001581 free(fn);
Nathan Zorichbd3771c1999-03-14 15:12:48 +00001582
Nathaniel7bf36ad1999-10-24 19:35:47 +00001583 /*
1584 * Load HKLM, attempt to get the registry location from the config
1585 * file first, if exist, load and keep going.
1586 */
1587 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1588 strcpy(fn,home);
1589 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001590 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001591 free(fn);
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001592 }
Nathaniel7bf36ad1999-10-24 19:35:47 +00001593
1594 /*
1595 * Load HKCU, get the registry location from the config
1596 * file, if exist, load and keep going.
1597 */
1598 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001599 {
Nathaniel7bf36ad1999-10-24 19:35:47 +00001600 fn = xmalloc( MAX_PATHNAME_LEN );
1601 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1602 fn, MAX_PATHNAME_LEN - 1))
1603 {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001604 _wine_loadreg( HKEY_CURRENT_USER, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001605 }
1606 free (fn);
1607 /*
1608 * Load HKU, get the registry location from the config
1609 * file, if exist, load and keep going.
1610 */
1611 fn = xmalloc ( MAX_PATHNAME_LEN );
1612 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1613 fn, MAX_PATHNAME_LEN - 1))
1614 {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001615 _wine_loadreg( HKEY_USERS, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001616 }
1617 free (fn);
1618 /*
1619 * Load HKLM, get the registry location from the config
1620 * file, if exist, load and keep going.
1621 */
1622 fn = xmalloc ( MAX_PATHNAME_LEN );
1623 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1624 fn, MAX_PATHNAME_LEN - 1))
1625 {
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001626 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
Nathaniel7bf36ad1999-10-24 19:35:47 +00001627 }
1628 free (fn);
Alexandre Julliard154c99b1999-04-25 12:41:36 +00001629 }
Juergen Schmied5d0ae2d2000-01-09 21:07:01 +00001630
Sylvain St.Germaine5332221999-04-10 16:46:15 +00001631 /*
1632 * Make sure the update mode is there
1633 */
1634 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1635 {
1636 DWORD junk,type,len;
1637 char data[5];
1638
1639 len=4;
1640 if (( RegQueryValueExA(
1641 hkey,
1642 VAL_SAVEUPDATED,
1643 &junk,
1644 &type,
1645 data,
1646 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1647 {
1648 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1649 }
1650
1651 RegCloseKey(hkey);
1652 }
Alexandre Julliard705686e1999-11-24 19:34:32 +00001653
1654 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1655 {
1656 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1657 }
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001658}
1659
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001660
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001661/********************* API FUNCTIONS ***************************************/
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001662
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001663
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001664
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001665
1666/******************************************************************************
1667 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
Andreas Mohrd4b13da1999-08-07 14:17:10 +00001668 * Immediately writes key to registry.
1669 * Only returns after data has been written to disk.
1670 *
1671 * FIXME: does it really wait until data is written ?
1672 *
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001673 * PARAMS
1674 * hkey [I] Handle of key to write
1675 *
1676 * RETURNS
1677 * Success: ERROR_SUCCESS
1678 * Failure: Error code
1679 */
1680DWORD WINAPI RegFlushKey( HKEY hkey )
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001681{
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001682 FIXME( "(%x): stub\n", hkey );
1683 return ERROR_SUCCESS;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00001684}
1685
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001686/******************************************************************************
1687 * RegConnectRegistry32W [ADVAPI32.128]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001688 *
1689 * PARAMS
1690 * lpMachineName [I] Address of name of remote computer
1691 * hHey [I] Predefined registry handle
1692 * phkResult [I] Address of buffer for remote registry handle
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001693 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001694LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001695 LPHKEY phkResult )
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001696{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001697 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001698
1699 if (!lpMachineName || !*lpMachineName) {
1700 /* Use the local machine name */
1701 return RegOpenKey16( hKey, "", phkResult );
1702 }
1703
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001704 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001705 return ERROR_BAD_NETPATH;
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001706}
1707
1708
1709/******************************************************************************
1710 * RegConnectRegistry32A [ADVAPI32.127]
1711 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001712LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001713{
1714 DWORD ret;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001715 LPWSTR machineW = strdupA2W(machine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001716 ret = RegConnectRegistryW( machineW, hkey, reskey );
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001717 free(machineW);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001718 return ret;
Alexandre Julliard01d63461997-01-20 19:43:45 +00001719}
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001720
1721
1722/******************************************************************************
1723 * RegGetKeySecurity [ADVAPI32.144]
1724 * Retrieves a copy of security descriptor protecting the registry key
1725 *
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001726 * PARAMS
1727 * hkey [I] Open handle of key to set
1728 * SecurityInformation [I] Descriptor contents
1729 * pSecurityDescriptor [O] Address of descriptor for key
1730 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1731 *
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001732 * RETURNS
1733 * Success: ERROR_SUCCESS
1734 * Failure: Error code
1735 */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001736LONG WINAPI RegGetKeySecurity( HKEY hkey,
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001737 SECURITY_INFORMATION SecurityInformation,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001738 PSECURITY_DESCRIPTOR pSecurityDescriptor,
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001739 LPDWORD lpcbSecurityDescriptor )
1740{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001741 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001742 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001743
Alexandre Julliard642d3131998-07-12 19:29:36 +00001744 /* FIXME: Check for valid SecurityInformation values */
1745
Alexandre Julliardb24fc081999-02-25 16:36:07 +00001746 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001747 return ERROR_INSUFFICIENT_BUFFER;
1748
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001749 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001750 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1751
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001752 return ERROR_SUCCESS;
1753}
1754
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001755
1756/******************************************************************************
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001757 * RegNotifyChangeKeyValue [ADVAPI32.???]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001758 *
1759 * PARAMS
1760 * hkey [I] Handle of key to watch
1761 * fWatchSubTree [I] Flag for subkey notification
1762 * fdwNotifyFilter [I] Changes to be reported
1763 * hEvent [I] Handle of signaled event
1764 * fAsync [I] Flag for asynchronous reporting
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001765 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001766LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1767 DWORD fdwNotifyFilter, HANDLE hEvent,
1768 BOOL fAsync )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001769{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001770 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001771 hEvent,fAsync);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001772 return ERROR_SUCCESS;
1773}
1774
Alexandre Julliarda845b881998-06-01 10:44:35 +00001775
1776/******************************************************************************
1777 * RegUnLoadKey32W [ADVAPI32.173]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001778 *
1779 * PARAMS
1780 * hkey [I] Handle of open key
1781 * lpSubKey [I] Address of name of subkey to unload
Alexandre Julliarda845b881998-06-01 10:44:35 +00001782 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001783LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001784{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001785 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
Alexandre Julliarda845b881998-06-01 10:44:35 +00001786 return ERROR_SUCCESS;
1787}
1788
1789
1790/******************************************************************************
1791 * RegUnLoadKey32A [ADVAPI32.172]
1792 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001793LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001794{
1795 LONG ret;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001796 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001797 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001798 if(lpSubKeyW) free(lpSubKeyW);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001799 return ret;
1800}
1801
1802
1803/******************************************************************************
1804 * RegSetKeySecurity [ADVAPI32.167]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001805 *
1806 * PARAMS
1807 * hkey [I] Open handle of key to set
1808 * SecurityInfo [I] Descriptor contents
1809 * pSecurityDesc [I] Address of descriptor for key
Alexandre Julliarda845b881998-06-01 10:44:35 +00001810 */
1811LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001812 PSECURITY_DESCRIPTOR pSecurityDesc )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001813{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001814 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001815
1816 /* It seems to perform this check before the hkey check */
1817 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1818 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1819 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1820 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1821 /* Param OK */
1822 } else
1823 return ERROR_INVALID_PARAMETER;
1824
1825 if (!pSecurityDesc)
1826 return ERROR_INVALID_PARAMETER;
1827
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001828 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001829
Alexandre Julliarda845b881998-06-01 10:44:35 +00001830 return ERROR_SUCCESS;
1831}
1832
1833
1834/******************************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +00001835 * RegRestoreKey32W [ADVAPI32.164]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001836 *
1837 * PARAMS
1838 * hkey [I] Handle of key where restore begins
1839 * lpFile [I] Address of filename containing saved tree
1840 * dwFlags [I] Optional flags
Alexandre Julliarda845b881998-06-01 10:44:35 +00001841 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001842LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001843{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001844 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001845
1846 /* It seems to do this check before the hkey check */
1847 if (!lpFile || !*lpFile)
1848 return ERROR_INVALID_PARAMETER;
1849
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001850 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001851
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001852 /* Check for file existence */
1853
Alexandre Julliarda845b881998-06-01 10:44:35 +00001854 return ERROR_SUCCESS;
1855}
1856
1857
1858/******************************************************************************
1859 * RegRestoreKey32A [ADVAPI32.163]
1860 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001861LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
Alexandre Julliarda845b881998-06-01 10:44:35 +00001862{
1863 LONG ret;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001864 LPWSTR lpFileW = strdupA2W(lpFile);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001865 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001866 if(lpFileW) free(lpFileW);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001867 return ret;
1868}
1869
1870
1871/******************************************************************************
1872 * RegReplaceKey32W [ADVAPI32.162]
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001873 *
1874 * PARAMS
1875 * hkey [I] Handle of open key
1876 * lpSubKey [I] Address of name of subkey
1877 * lpNewFile [I] Address of filename for file with new data
1878 * lpOldFile [I] Address of filename for backup file
Alexandre Julliarda845b881998-06-01 10:44:35 +00001879 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001880LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
Alexandre Julliarda845b881998-06-01 10:44:35 +00001881 LPCWSTR lpOldFile )
1882{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001883 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
Alexandre Julliard642d3131998-07-12 19:29:36 +00001884 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
Alexandre Julliarda845b881998-06-01 10:44:35 +00001885 return ERROR_SUCCESS;
1886}
1887
1888
1889/******************************************************************************
1890 * RegReplaceKey32A [ADVAPI32.161]
1891 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001892LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
Alexandre Julliarda845b881998-06-01 10:44:35 +00001893 LPCSTR lpOldFile )
1894{
1895 LONG ret;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001896 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1897 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1898 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001899 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001900 free(lpOldFileW);
1901 free(lpNewFileW);
1902 free(lpSubKeyW);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001903 return ret;
1904}
1905
Alexandre Julliard2fab2ef1999-11-23 19:41:34 +00001906
1907
1908
1909
1910
1911/* 16-bit functions */
1912
1913/* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1914 * some programs. Do not remove those cases. -MM
1915 */
1916static inline void fix_win16_hkey( HKEY *hkey )
1917{
1918 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1919}
1920
1921/******************************************************************************
1922 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1923 */
1924DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1925{
1926 fix_win16_hkey( &hkey );
1927 return RegEnumKeyA( hkey, index, name, name_len );
1928}
1929
1930/******************************************************************************
1931 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1932 */
1933DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1934{
1935 fix_win16_hkey( &hkey );
1936 return RegOpenKeyA( hkey, name, retkey );
1937}
1938
1939/******************************************************************************
1940 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1941 */
1942DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1943{
1944 fix_win16_hkey( &hkey );
1945 return RegCreateKeyA( hkey, name, retkey );
1946}
1947
1948/******************************************************************************
1949 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1950 */
1951DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1952{
1953 fix_win16_hkey( &hkey );
1954 return RegDeleteKeyA( hkey, name );
1955}
1956
1957/******************************************************************************
1958 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1959 */
1960DWORD WINAPI RegCloseKey16( HKEY hkey )
1961{
1962 fix_win16_hkey( &hkey );
1963 return RegCloseKey( hkey );
1964}
1965
1966/******************************************************************************
1967 * RegSetValue16 [KERNEL.221] [SHELL.5]
1968 */
1969DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1970{
1971 fix_win16_hkey( &hkey );
1972 return RegSetValueA( hkey, name, type, data, count );
1973}
1974
1975/******************************************************************************
1976 * RegDeleteValue16 [KERNEL.222]
1977 */
1978DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1979{
1980 fix_win16_hkey( &hkey );
1981 return RegDeleteValueA( hkey, name );
1982}
1983
1984/******************************************************************************
1985 * RegEnumValue16 [KERNEL.223]
1986 */
1987DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1988 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1989{
1990 fix_win16_hkey( &hkey );
1991 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1992}
1993
1994/******************************************************************************
1995 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1996 *
1997 * NOTES
1998 * Is this HACK still applicable?
1999 *
2000 * HACK
2001 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2002 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2003 * Aldus FH4)
2004 */
2005DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2006{
2007 fix_win16_hkey( &hkey );
2008 if (count) *count &= 0xffff;
2009 return RegQueryValueA( hkey, name, data, count );
2010}
2011
2012/******************************************************************************
2013 * RegQueryValueEx16 [KERNEL.225]
2014 */
2015DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2016 LPBYTE data, LPDWORD count )
2017{
2018 fix_win16_hkey( &hkey );
2019 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2020}
2021
2022/******************************************************************************
2023 * RegSetValueEx16 [KERNEL.226]
2024 */
2025DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2026 CONST BYTE *data, DWORD count )
2027{
2028 fix_win16_hkey( &hkey );
2029 return RegSetValueExA( hkey, name, reserved, type, data, count );
2030}