Added support for registry values larger than the server buffer.

When loading a registry file, automatically determine overlap between
key name and file contents based on the first key name.
Removed v1 saving code.
Save USER\.Default separately into ~/.wine/userdef.reg.
This commit is contained in:
Alexandre Julliard 2000-05-14 22:57:57 +00:00
parent 270c9fb109
commit a01004d828
5 changed files with 325 additions and 213 deletions

View File

@ -51,59 +51,6 @@ static inline int is_string( DWORD type )
return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
}
/* copy key value data into a user-specified buffer
*
* 'len' is the total length of the data
* 'count' is the size of the user-specified buffer
* and is updated to reflect the length copied
*
* if the type is REG_SZ and data is not 0-terminated and there is enough space in the
* buffer nt appends a \0
*/
static DWORD copy_data( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
{
DWORD ret = ERROR_SUCCESS;
if (data)
{
if (*count < len) ret = ERROR_MORE_DATA;
else memcpy( data, src, len );
}
if (count)
{
if (len && data && is_string( type ) && (len < *count) && ((WCHAR *)data)[len-1])
((WCHAR *)data)[len] = 0;
*count = len;
}
return ret;
}
/* same as copy_data but with optional Unicode->Ascii conversion depending on the type */
static DWORD copy_data_WtoA( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
{
DWORD ret = ERROR_SUCCESS;
if (is_string( type ))
{
/* need to convert from Unicode */
len /= sizeof(WCHAR);
if (data)
{
if (*count < len) ret = ERROR_MORE_DATA;
else if (len)
{
memcpyWtoA( data, src, len );
if ((len < *count) && ((char*)data)[len-1]) ((char *)data)[len] = 0;
}
}
}
else if (data)
{
if (*count < len) ret = ERROR_MORE_DATA;
else memcpy( data, src, len );
}
if (count) *count = len;
return ret;
}
/* copy a key name into the request buffer */
static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
{
@ -623,6 +570,7 @@ DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
{
DWORD ret;
struct set_key_value_request *req = get_req_buffer();
unsigned int max, pos;
TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(name), reserved, type, data, count );
@ -635,13 +583,25 @@ DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
count += sizeof(WCHAR);
}
if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY; /* FIXME */
req->hkey = hkey;
req->type = type;
req->len = count;
req->total = count;
if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
memcpy( req->data, data, count );
return reg_server_call( REQ_SET_KEY_VALUE );
max = server_remaining( req->data );
pos = 0;
while (pos < count)
{
unsigned int len = count - pos;
if (len > max) len = max;
req->offset = pos;
req->len = len;
memcpy( req->data, data + pos, len );
if ((ret = reg_server_call( REQ_SET_KEY_VALUE )) != ERROR_SUCCESS) break;
pos += len;
}
return ret;
}
@ -653,6 +613,7 @@ DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
{
DWORD ret;
struct set_key_value_request *req = get_req_buffer();
unsigned int max, pos;
TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_a(name), reserved, type, data, count );
@ -663,23 +624,31 @@ DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
/* if user forgot to count terminating null, add it (yes NT does this) */
if (data[count-1] && !data[count]) count++;
}
if (is_string( type ))
{
/* need to convert to Unicode */
if (is_string( type )) /* need to convert to Unicode */
count *= sizeof(WCHAR);
if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY; /* FIXME */
memcpyAtoW( (LPWSTR)req->data, data, count / sizeof(WCHAR) );
}
else
{
if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY; /* FIXME */
memcpy( req->data, data, count );
}
req->hkey = hkey;
req->type = type;
req->len = count;
req->total = count;
if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
return reg_server_call( REQ_SET_KEY_VALUE );
max = server_remaining( req->data );
pos = 0;
while (pos < count)
{
unsigned int len = count - pos;
if (len > max) len = max;
req->offset = pos;
req->len = len;
if (is_string( type ))
memcpyAtoW( (LPWSTR)req->data, data + pos/sizeof(WCHAR), len/sizeof(WCHAR) );
else
memcpy( req->data, data + pos, len );
if ((ret = reg_server_call( REQ_SET_KEY_VALUE )) != ERROR_SUCCESS) break;
pos += len;
}
return ret;
}
@ -762,12 +731,35 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
req->hkey = hkey;
req->offset = 0;
if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
if (data)
{
if (type) *type = req->type;
ret = copy_data( data, req->data, req->len, count, req->type );
if (*count < req->len) ret = ERROR_MORE_DATA;
else
{
/* copy the data */
unsigned int max = server_remaining( req->data );
unsigned int pos = 0;
while (pos < req->len)
{
unsigned int len = min( req->len - pos, max );
memcpy( data + pos, req->data, len );
if ((pos += len) >= req->len) break;
req->offset = pos;
if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
}
}
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
if (req->len && is_string(req->type) &&
(req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
}
if (type) *type = req->type;
if (count) *count = req->len;
return ret;
}
@ -781,7 +773,7 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR
DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
LPBYTE data, LPDWORD count )
{
DWORD ret;
DWORD ret, total_len;
struct get_key_value_request *req = get_req_buffer();
TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
@ -790,12 +782,41 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
req->hkey = hkey;
req->offset = 0;
if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
if (data)
{
if (type) *type = req->type;
ret = copy_data_WtoA( data, req->data, req->len, count, req->type );
if (*count < total_len) ret = ERROR_MORE_DATA;
else
{
/* copy the data */
unsigned int max = server_remaining( req->data );
unsigned int pos = 0;
while (pos < req->len)
{
unsigned int len = min( req->len - pos, max );
if (is_string( req->type ))
memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
else
memcpy( data + pos, req->data, len );
if ((pos += len) >= req->len) break;
req->offset = pos;
if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
}
}
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
data[total_len] = 0;
}
if (count) *count = total_len;
if (type) *type = req->type;
return ret;
}
@ -882,6 +903,7 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co
req->hkey = hkey;
req->index = index;
req->offset = 0;
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
len = lstrlenW( req->name ) + 1;
@ -889,8 +911,31 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co
memcpy( value, req->name, len * sizeof(WCHAR) );
*val_count = len - 1;
if (data)
{
if (*count < req->len) ret = ERROR_MORE_DATA;
else
{
/* copy the data */
unsigned int max = server_remaining( req->data );
unsigned int pos = 0;
while (pos < req->len)
{
unsigned int len = min( req->len - pos, max );
memcpy( data + pos, req->data, len );
if ((pos += len) >= req->len) break;
req->offset = pos;
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
}
}
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
if (req->len && is_string(req->type) &&
(req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
}
if (type) *type = req->type;
return copy_data( data, req->data, req->len, count, req->type );
if (count) *count = req->len;
return ret;
}
@ -900,7 +945,7 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co
DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
{
DWORD ret, len;
DWORD ret, len, total_len;
struct enum_key_value_request *req = get_req_buffer();
TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
@ -911,6 +956,7 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou
req->hkey = hkey;
req->index = index;
req->offset = 0;
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
len = lstrlenW( req->name ) + 1;
@ -918,8 +964,37 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou
memcpyWtoA( value, req->name, len );
*val_count = len - 1;
total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
if (data)
{
if (*count < total_len) ret = ERROR_MORE_DATA;
else
{
/* copy the data */
unsigned int max = server_remaining( req->data );
unsigned int pos = 0;
while (pos < req->len)
{
unsigned int len = min( req->len - pos, max );
if (is_string( req->type ))
memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
else
memcpy( data + pos, req->data, len );
if ((pos += len) >= req->len) break;
req->offset = pos;
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
}
}
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
data[total_len] = 0;
}
if (count) *count = total_len;
if (type) *type = req->type;
return copy_data_WtoA( data, req->data, req->len, count, req->type );
return ret;
}

View File

@ -975,7 +975,9 @@ struct set_key_value_request
{
IN int hkey; /* handle to registry key */
IN int type; /* value type */
IN int len; /* value data len */
IN unsigned int total; /* total value len */
IN unsigned int offset; /* offset for setting data */
IN unsigned int len; /* value data len */
IN path_t name; /* value name */
IN unsigned char data[1]; /* value data */
};
@ -985,6 +987,7 @@ struct set_key_value_request
struct get_key_value_request
{
IN int hkey; /* handle to registry key */
IN unsigned int offset; /* offset for getting data */
OUT int type; /* value type */
OUT int len; /* value data len */
IN WCHAR name[1]; /* value name */
@ -997,6 +1000,7 @@ struct enum_key_value_request
{
IN int hkey; /* handle to registry key */
IN int index; /* value index */
IN unsigned int offset; /* offset for getting data */
OUT int type; /* value type */
OUT int len; /* value data len */
OUT path_t name; /* value name */
@ -1042,7 +1046,6 @@ struct set_registry_levels_request
{
IN int current; /* new current level */
IN int saving; /* new saving level */
IN int version; /* file format version for saving */
IN int period; /* duration between periodic saves (milliseconds) */
};
@ -1255,7 +1258,7 @@ enum request
REQ_NB_REQUESTS
};
#define SERVER_PROTOCOL_VERSION 11
#define SERVER_PROTOCOL_VERSION 12
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */

View File

@ -59,6 +59,7 @@ static void REGISTRY_Init(void);
/* relative in ~user/.wine/ : */
#define SAVE_CURRENT_USER "user.reg"
#define SAVE_DEFAULT_USER "userdef.reg"
#define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
#define SAVE_LOCAL_MACHINE "system.reg"
@ -444,7 +445,7 @@ static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
/******************************************************************************
* _wine_loadreg [Internal]
*/
static void _wine_loadreg( HKEY hkey, char *fn )
static int _wine_loadreg( HKEY hkey, char *fn )
{
FILE *F;
@ -453,10 +454,11 @@ static void _wine_loadreg( HKEY hkey, char *fn )
F = fopen(fn,"rb");
if (F==NULL) {
WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
return;
return -1;
}
_wine_loadsubreg(F,hkey,fn);
fclose(F);
return 0;
}
/* NT REGISTRY LOADER */
@ -1346,18 +1348,16 @@ void _w31_loadreg(void) {
/* configure save files and start the periodic saving timer */
static void SHELL_InitRegistrySaving(void)
static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
{
struct set_registry_levels_request *req = get_req_buffer();
int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
/* set saving level (0 for saving everything, 1 for saving only modified keys) */
req->current = 1;
req->saving = !all;
req->version = version;
req->period = period * 1000;
server_call( REQ_SET_REGISTRY_LEVELS );
@ -1383,6 +1383,11 @@ static void SHELL_InitRegistrySaving(void)
req->hkey = HKEY_LOCAL_MACHINE;
server_call( REQ_SAVE_REGISTRY_ATEXIT );
strcpy( req->file, confdir );
strcpy( str, "/" SAVE_DEFAULT_USER );
req->hkey = hkey_users_default;
server_call( REQ_SAVE_REGISTRY_ATEXIT );
strcpy( req->file, confdir );
strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
req->hkey = HKEY_USERS;
@ -1403,7 +1408,6 @@ static void SetLoadLevel(int level)
req->current = level;
req->saving = 0;
req->version = 1;
req->period = 0;
server_call( REQ_SET_REGISTRY_LEVELS );
}
@ -1422,6 +1426,7 @@ void SHELL_LoadRegistry( void )
char windir[MAX_PATHNAME_LEN];
char path[MAX_PATHNAME_LEN];
int systemtype = REG_WIN31;
HKEY hkey_users_default;
TRACE("(void)\n");
@ -1430,6 +1435,8 @@ void SHELL_LoadRegistry( void )
REGISTRY_Init();
SetLoadLevel(0);
if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default)) hkey_users_default = 0;
GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
@ -1491,12 +1498,11 @@ void SHELL_LoadRegistry( void )
MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
}
/* default user.dat */
if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
if (hkey_users_default)
{
strcpy(path, windir);
strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
NativeRegLoadKey(hkey, path, 1);
RegCloseKey(hkey);
NativeRegLoadKey(hkey_users_default, path, 1);
}
}
else
@ -1521,12 +1527,11 @@ void SHELL_LoadRegistry( void )
}
/* default user.dat */
if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
if (hkey_users_default)
{
strcpy(path, windir);
strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
NativeRegLoadKey(hkey, path, 1);
RegCloseKey(hkey);
NativeRegLoadKey(hkey_users_default, path, 1);
}
/*
@ -1599,8 +1604,14 @@ void SHELL_LoadRegistry( void )
str = fn + strlen(fn);
*str++ = '/';
strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
_wine_loadreg( HKEY_USERS, fn );
/* try to load HKU\.Default key only */
strcpy( str, SAVE_DEFAULT_USER );
if (_wine_loadreg( hkey_users_default, fn ))
{
/* if not found load old file containing both HKU\.Default and HKU\user */
strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
_wine_loadreg( HKEY_USERS, fn );
}
strcpy( str, SAVE_CURRENT_USER );
_wine_loadreg( HKEY_CURRENT_USER, fn );
@ -1611,8 +1622,8 @@ void SHELL_LoadRegistry( void )
if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
}
}
SHELL_InitRegistrySaving();
SHELL_InitRegistrySaving( hkey_users_default );
RegCloseKey( hkey_users_default );
}
/********************* API FUNCTIONS ***************************************/

View File

@ -73,17 +73,6 @@ struct key_value
#define IS_ROOT_HKEY(h) (((h) >= HKEY_ROOT_FIRST) && ((h) <= HKEY_ROOT_LAST))
static struct key *root_keys[NB_ROOT_KEYS];
static const char * const root_key_names[NB_ROOT_KEYS] =
{
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
"HKEY_PERFORMANCE_DATA",
"HKEY_CURRENT_CONFIG",
"HKEY_DYN_DATA"
};
/* keys saving level */
/* current_level is the level that is put into all newly created or modified keys */
@ -91,8 +80,6 @@ static const char * const root_key_names[NB_ROOT_KEYS] =
static int current_level;
static int saving_level;
static int saving_version = 1; /* file format version */
static struct timeval next_save_time; /* absolute time of next periodic save */
static int save_period; /* delay between periodic saves (ms) */
static struct timeout_user *save_timeout_user; /* saving timer */
@ -165,14 +152,7 @@ static void dump_path( struct key *key, struct key *base, FILE *f )
dump_path( key->parent, base, f );
fprintf( f, "\\\\" );
}
if (key->name) dump_strW( key->name, strlenW(key->name), f, "[]" );
else /* root key */
{
int i;
for (i = 0; i < NB_ROOT_KEYS; i++)
if (root_keys[i] == key) fprintf( f, "%s", root_key_names[i] );
}
dump_strW( key->name, strlenW(key->name), f, "[]" );
}
/* dump a value to a text file */
@ -274,7 +254,7 @@ static void key_destroy( struct object *obj )
struct key *key = (struct key *)obj;
assert( obj->ops == &key_ops );
free( key->name );
if (key->name) free( key->name );
if (key->class) free( key->class );
for (i = 0; i <= key->last_value; i++)
{
@ -345,7 +325,6 @@ static struct key *alloc_key( const WCHAR *name, time_t modif )
struct key *key;
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
{
key->name = NULL;
key->class = NULL;
key->flags = 0;
key->last_subkey = -1;
@ -357,7 +336,7 @@ static struct key *alloc_key( const WCHAR *name, time_t modif )
key->level = current_level;
key->modif = modif;
key->parent = NULL;
if (name && !(key->name = strdupW( name )))
if (!(key->name = strdupW( name )))
{
release_object( key );
key = NULL;
@ -719,16 +698,42 @@ static struct key_value *insert_value( struct key *key, const WCHAR *name )
}
/* set a key value */
static void set_value( struct key *key, WCHAR *name, int type, int datalen, void *data )
static void set_value( struct key *key, WCHAR *name, int type, unsigned int total_len,
unsigned int offset, unsigned int data_len, void *data )
{
struct key_value *value;
void *ptr = NULL;
/* first copy the data */
if (datalen)
if (data_len + offset > total_len)
{
if (!(ptr = mem_alloc( datalen ))) return;
memcpy( ptr, data, datalen );
set_error( STATUS_INVALID_PARAMETER );
return;
}
if (offset) /* adding data to an existing value */
{
int index;
if (!(value = find_value( key, name, &index )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return;
}
if (value->len != total_len)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
memcpy( (char *)value->data + offset, data, data_len );
if (debug_level > 1) dump_operation( key, value, "Set" );
return;
}
/* first copy the data */
if (total_len)
{
if (!(ptr = mem_alloc( total_len ))) return;
memcpy( ptr, data, data_len );
if (data_len < total_len) memset( (char *)ptr + data_len, 0, total_len - data_len );
}
if (!(value = insert_value( key, name )))
@ -738,14 +743,15 @@ static void set_value( struct key *key, WCHAR *name, int type, int datalen, void
}
if (value->data) free( value->data ); /* already existing, free previous data */
value->type = type;
value->len = datalen;
value->len = total_len;
value->data = ptr;
touch_key( key );
if (debug_level > 1) dump_operation( key, value, "Set" );
}
/* get a key value */
static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *data )
static void get_value( struct key *key, WCHAR *name, unsigned int offset,
unsigned int maxlen, int *type, int *len, void *data )
{
struct key_value *value;
int index;
@ -754,7 +760,11 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *
{
*type = value->type;
*len = value->len;
if (value->data) memcpy( data, value->data, value->len );
if (value->data && offset < value->len)
{
if (maxlen > value->len - offset) maxlen = value->len - offset;
memcpy( data, (char *)value->data + offset, maxlen );
}
if (debug_level > 1) dump_operation( key, value, "Get" );
}
else
@ -765,7 +775,8 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *
}
/* enumerate a key value */
static void enum_value( struct key *key, int i, WCHAR *name, int *type, int *len, void *data )
static void enum_value( struct key *key, int i, WCHAR *name, unsigned int offset,
unsigned int maxlen, int *type, int *len, void *data )
{
struct key_value *value;
@ -776,7 +787,11 @@ static void enum_value( struct key *key, int i, WCHAR *name, int *type, int *len
strcpyW( name, value->name );
*type = value->type;
*len = value->len;
if (value->data) memcpy( data, value->data, value->len );
if (value->data && offset < value->len)
{
if (maxlen > value->len - offset) maxlen = value->len - offset;
memcpy( data, (char *)value->data + offset, maxlen );
}
if (debug_level > 1) dump_operation( key, value, "Enum" );
}
}
@ -890,9 +905,17 @@ static struct key *create_root_key( int hkey )
break;
/* dynamically generated keys */
case HKEY_PERFORMANCE_DATA:
{
static const WCHAR name[] = { 'P','E','R','F','D','A','T','A',0 }; /* FIXME */
key = alloc_key( name, time(NULL) );
}
break;
case HKEY_DYN_DATA:
key = alloc_key( NULL, time(NULL) );
break;
{
static const WCHAR name[] = { 'D','Y','N','D','A','T','A',0 }; /* FIXME */
key = alloc_key( name, time(NULL) );
}
break;
default:
key = NULL;
assert(0);
@ -1067,7 +1090,8 @@ static int get_data_type( const char *buffer, int *type, int *parse_type )
}
/* load and create a key from the input file */
static struct key *load_key( struct key *base, const char *buffer, struct file_load_info *info )
static struct key *load_key( struct key *base, const char *buffer, unsigned int options,
int prefix_len, struct file_load_info *info )
{
WCHAR *p;
int res, len, modif;
@ -1082,8 +1106,20 @@ static struct key *load_key( struct key *base, const char *buffer, struct file_l
}
if (!sscanf( buffer + res, " %d", &modif )) modif = time(NULL);
for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') { p++; break; }
return create_key( base, p, len - ((char *)p - info->tmp), NULL, 0, modif, &res );
p = (WCHAR *)info->tmp;
while (prefix_len && *p) { if (*p++ == '\\') prefix_len--; }
if (!*p)
{
if (prefix_len > 1)
{
file_read_error( "Malformed key", info );
return NULL;
}
/* empty key name, return base key */
return (struct key *)grab_object( base );
}
return create_key( base, p, len - ((char *)p - info->tmp), NULL, options, modif, &res );
}
/* parse a comma-separated list of hex digits */
@ -1198,12 +1234,41 @@ static int load_value( struct key *key, const char *buffer, struct file_load_inf
return 0;
}
/* return the length (in path elements) of name that is part of the key name */
/* for instance if key is USER\foo\bar and name is foo\bar\baz, return 2 */
static int get_prefix_len( struct key *key, const char *name, struct file_load_info *info )
{
WCHAR *p;
int res;
int len = strlen(name) * sizeof(WCHAR);
if (!get_file_tmp_space( info, len )) return NULL;
if ((res = parse_strW( (WCHAR *)info->tmp, &len, name, ']' )) == -1)
{
file_read_error( "Malformed key", info );
return NULL;
}
for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') break;
*p = 0;
for (res = 1; key; res++)
{
if (!strcmpiW( (WCHAR *)info->tmp, key->name )) break;
key = key->parent;
}
if (!key) res = 0; /* no matching name */
return res;
}
/* load all the keys from the input file */
static void load_keys( struct key *key, FILE *f )
{
struct key *subkey = NULL;
struct file_load_info info;
char *p;
unsigned int options = 0;
int prefix_len = -1; /* number of key name prefixes to skip */
if (key->flags & KEY_VOLATILE) options |= REG_OPTION_VOLATILE;
info.file = f;
info.len = 4;
@ -1230,7 +1295,9 @@ static void load_keys( struct key *key, FILE *f )
{
case '[': /* new key */
if (subkey) release_object( subkey );
subkey = load_key( key, p + 1, &info );
if (prefix_len == -1) prefix_len = get_prefix_len( key, p + 1, &info );
if (!(subkey = load_key( key, p + 1, options, prefix_len, &info )))
file_read_error( "Error creating key", &info );
break;
case '@': /* default value */
case '\"': /* value */
@ -1288,50 +1355,14 @@ static int update_level( struct key *key )
return max;
}
/* dump a string to a registry save file in the old v1 format */
static void save_string_v1( LPCWSTR str, FILE *f, int len )
/* save a registry branch to a file */
static void save_all_subkeys( struct key *key, FILE *f )
{
if (!str) return;
while ((len == -1) ? *str : (*str && len--))
{
if ((*str > 0x7f) || (*str == '\n') || (*str == '='))
fprintf( f, "\\u%04x", *str );
else
{
if (*str == '\\') fputc( '\\', f );
fputc( (char)*str, f );
}
str++;
}
}
/* save a registry and all its subkeys to a text file in the old v1 format */
static void save_subkeys_v1( struct key *key, int nesting, FILE *f )
{
int i, j;
if (key->flags & KEY_VOLATILE) return;
if (key->level < saving_level) return;
for (i = 0; i <= key->last_value; i++)
{
struct key_value *value = &key->values[i];
for (j = nesting; j > 0; j --) fputc( '\t', f );
save_string_v1( value->name, f, -1 );
fprintf( f, "=%d,%d,", value->type, 0 );
if (value->type == REG_SZ || value->type == REG_EXPAND_SZ)
save_string_v1( (LPWSTR)value->data, f, value->len / 2 );
else
for (j = 0; j < value->len; j++)
fprintf( f, "%02x", *((unsigned char *)value->data + j) );
fputc( '\n', f );
}
for (i = 0; i <= key->last_subkey; i++)
{
for (j = nesting; j > 0; j --) fputc( '\t', f );
save_string_v1( key->subkeys[i]->name, f, -1 );
fputc( '\n', f );
save_subkeys_v1( key->subkeys[i], nesting + 1, f );
}
fprintf( f, "WINE REGISTRY Version 2\n" );
fprintf( f, ";; All keys relative to " );
dump_path( key, NULL, f );
fprintf( f, "\n" );
save_subkeys( key, key, f );
}
/* save a registry branch to a file handle */
@ -1353,13 +1384,7 @@ static void save_registry( struct key *key, int handle )
FILE *f = fdopen( fd, "w" );
if (f)
{
fprintf( f, "WINE REGISTRY Version %d\n", saving_version );
if (saving_version == 2) save_subkeys( key, key, f );
else
{
update_level( key );
save_subkeys_v1( key, 0, f );
}
save_all_subkeys( key, f );
if (fclose( f )) file_set_error();
}
else
@ -1446,13 +1471,7 @@ static int save_branch( struct key *key, const char *path )
dump_operation( key, NULL, "saving" );
}
fprintf( f, "WINE REGISTRY Version %d\n", saving_version );
if (saving_version == 2) save_subkeys( key, key, f );
else
{
update_level( key );
save_subkeys_v1( key, 0, f );
}
save_all_subkeys( key, f );
ret = !fclose(f);
if (tmp)
@ -1594,16 +1613,14 @@ DECL_HANDLER(query_key_info)
DECL_HANDLER(set_key_value)
{
struct key *key;
int max = get_req_size( req, req->data, sizeof(req->data[0]) );
int datalen = req->len;
if (datalen > max)
{
set_error( STATUS_NO_MEMORY ); /* FIXME */
return;
}
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
unsigned int datalen = req->len;
if (datalen > max) datalen = max;
if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
{
set_value( key, copy_path( req->name ), req->type, datalen, req->data );
set_value( key, copy_path( req->name ), req->type, req->total,
req->offset, datalen, req->data );
release_object( key );
}
}
@ -1612,11 +1629,13 @@ DECL_HANDLER(set_key_value)
DECL_HANDLER(get_key_value)
{
struct key *key;
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
req->len = 0;
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
{
get_value( key, copy_path( req->name ), &req->type, &req->len, req->data );
get_value( key, copy_path( req->name ), req->offset, max,
&req->type, &req->len, req->data );
release_object( key );
}
}
@ -1625,12 +1644,14 @@ DECL_HANDLER(get_key_value)
DECL_HANDLER(enum_key_value)
{
struct key *key;
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
req->len = 0;
req->name[0] = 0;
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
{
enum_value( key, req->index, req->name, &req->type, &req->len, req->data );
enum_value( key, req->index, req->name, req->offset, max,
&req->type, &req->len, req->data );
release_object( key );
}
}
@ -1682,7 +1703,6 @@ DECL_HANDLER(set_registry_levels)
{
current_level = req->current;
saving_level = req->saving;
saving_version = req->version;
/* set periodic save timer */

View File

@ -198,13 +198,13 @@ static void dump_varargs_set_key_value_request( const struct set_key_value_reque
static void dump_varargs_get_key_value_reply( const struct get_key_value_request *req )
{
int count = min( req->len, get_req_size( req, req->data, 1 ));
int count = min( req->len - req->offset, get_req_size( req, req->data, 1 ));
dump_bytes( req->data, count );
}
static void dump_varargs_enum_key_value_reply( const struct enum_key_value_request *req )
{
int count = min( req->len, get_req_size( req, req->data, 1 ));
int count = min( req->len - req->offset, get_req_size( req, req->data, 1 ));
dump_bytes( req->data, count );
}
@ -1141,7 +1141,9 @@ static void dump_set_key_value_request( const struct set_key_value_request *req
{
fprintf( stderr, " hkey=%d,", req->hkey );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " len=%d,", req->len );
fprintf( stderr, " total=%08x,", req->total );
fprintf( stderr, " offset=%08x,", req->offset );
fprintf( stderr, " len=%08x,", req->len );
fprintf( stderr, " name=" );
dump_path_t( req, &req->name );
fprintf( stderr, "," );
@ -1152,6 +1154,7 @@ static void dump_set_key_value_request( const struct set_key_value_request *req
static void dump_get_key_value_request( const struct get_key_value_request *req )
{
fprintf( stderr, " hkey=%d,", req->hkey );
fprintf( stderr, " offset=%08x,", req->offset );
fprintf( stderr, " name=" );
dump_unicode_string( req, req->name );
}
@ -1167,7 +1170,8 @@ static void dump_get_key_value_reply( const struct get_key_value_request *req )
static void dump_enum_key_value_request( const struct enum_key_value_request *req )
{
fprintf( stderr, " hkey=%d,", req->hkey );
fprintf( stderr, " index=%d", req->index );
fprintf( stderr, " index=%d,", req->index );
fprintf( stderr, " offset=%08x", req->offset );
}
static void dump_enum_key_value_reply( const struct enum_key_value_request *req )
@ -1213,7 +1217,6 @@ static void dump_set_registry_levels_request( const struct set_registry_levels_r
{
fprintf( stderr, " current=%d,", req->current );
fprintf( stderr, " saving=%d,", req->saving );
fprintf( stderr, " version=%d,", req->version );
fprintf( stderr, " period=%d", req->period );
}