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:
parent
270c9fb109
commit
a01004d828
@ -51,59 +51,6 @@ static inline int is_string( DWORD type )
|
|||||||
return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
|
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 */
|
/* copy a key name into the request buffer */
|
||||||
static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
|
static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
|
||||||
{
|
{
|
||||||
@ -623,6 +570,7 @@ DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
|
|||||||
{
|
{
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
struct set_key_value_request *req = get_req_buffer();
|
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 );
|
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)])
|
if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
|
||||||
count += sizeof(WCHAR);
|
count += sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY; /* FIXME */
|
|
||||||
req->hkey = hkey;
|
req->hkey = hkey;
|
||||||
req->type = type;
|
req->type = type;
|
||||||
req->len = count;
|
req->total = count;
|
||||||
if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
|
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;
|
DWORD ret;
|
||||||
struct set_key_value_request *req = get_req_buffer();
|
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 );
|
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 user forgot to count terminating null, add it (yes NT does this) */
|
||||||
if (data[count-1] && !data[count]) count++;
|
if (data[count-1] && !data[count]) count++;
|
||||||
}
|
}
|
||||||
if (is_string( type ))
|
if (is_string( type )) /* need to convert to Unicode */
|
||||||
{
|
|
||||||
/* need to convert to Unicode */
|
|
||||||
count *= sizeof(WCHAR);
|
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->hkey = hkey;
|
||||||
req->type = type;
|
req->type = type;
|
||||||
req->len = count;
|
req->total = count;
|
||||||
if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
|
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;
|
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
req->hkey = hkey;
|
req->hkey = hkey;
|
||||||
|
req->offset = 0;
|
||||||
if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
|
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;
|
if (*count < req->len) ret = ERROR_MORE_DATA;
|
||||||
ret = copy_data( data, req->data, req->len, count, req->type );
|
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;
|
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,
|
DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
|
||||||
LPBYTE data, LPDWORD count )
|
LPBYTE data, LPDWORD count )
|
||||||
{
|
{
|
||||||
DWORD ret;
|
DWORD ret, total_len;
|
||||||
struct get_key_value_request *req = get_req_buffer();
|
struct get_key_value_request *req = get_req_buffer();
|
||||||
|
|
||||||
TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
|
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;
|
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
req->hkey = hkey;
|
req->hkey = hkey;
|
||||||
|
req->offset = 0;
|
||||||
if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
|
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;
|
if (*count < total_len) ret = ERROR_MORE_DATA;
|
||||||
ret = copy_data_WtoA( data, req->data, req->len, count, req->type );
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,6 +903,7 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co
|
|||||||
|
|
||||||
req->hkey = hkey;
|
req->hkey = hkey;
|
||||||
req->index = index;
|
req->index = index;
|
||||||
|
req->offset = 0;
|
||||||
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
|
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
|
||||||
|
|
||||||
len = lstrlenW( req->name ) + 1;
|
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) );
|
memcpy( value, req->name, len * sizeof(WCHAR) );
|
||||||
*val_count = len - 1;
|
*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;
|
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,
|
DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
|
||||||
LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD 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();
|
struct enum_key_value_request *req = get_req_buffer();
|
||||||
|
|
||||||
TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
|
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->hkey = hkey;
|
||||||
req->index = index;
|
req->index = index;
|
||||||
|
req->offset = 0;
|
||||||
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
|
if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
|
||||||
|
|
||||||
len = lstrlenW( req->name ) + 1;
|
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 );
|
memcpyWtoA( value, req->name, len );
|
||||||
*val_count = len - 1;
|
*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;
|
if (type) *type = req->type;
|
||||||
return copy_data_WtoA( data, req->data, req->len, count, req->type );
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -975,7 +975,9 @@ struct set_key_value_request
|
|||||||
{
|
{
|
||||||
IN int hkey; /* handle to registry key */
|
IN int hkey; /* handle to registry key */
|
||||||
IN int type; /* value type */
|
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 path_t name; /* value name */
|
||||||
IN unsigned char data[1]; /* value data */
|
IN unsigned char data[1]; /* value data */
|
||||||
};
|
};
|
||||||
@ -985,6 +987,7 @@ struct set_key_value_request
|
|||||||
struct get_key_value_request
|
struct get_key_value_request
|
||||||
{
|
{
|
||||||
IN int hkey; /* handle to registry key */
|
IN int hkey; /* handle to registry key */
|
||||||
|
IN unsigned int offset; /* offset for getting data */
|
||||||
OUT int type; /* value type */
|
OUT int type; /* value type */
|
||||||
OUT int len; /* value data len */
|
OUT int len; /* value data len */
|
||||||
IN WCHAR name[1]; /* value name */
|
IN WCHAR name[1]; /* value name */
|
||||||
@ -997,6 +1000,7 @@ struct enum_key_value_request
|
|||||||
{
|
{
|
||||||
IN int hkey; /* handle to registry key */
|
IN int hkey; /* handle to registry key */
|
||||||
IN int index; /* value index */
|
IN int index; /* value index */
|
||||||
|
IN unsigned int offset; /* offset for getting data */
|
||||||
OUT int type; /* value type */
|
OUT int type; /* value type */
|
||||||
OUT int len; /* value data len */
|
OUT int len; /* value data len */
|
||||||
OUT path_t name; /* value name */
|
OUT path_t name; /* value name */
|
||||||
@ -1042,7 +1046,6 @@ struct set_registry_levels_request
|
|||||||
{
|
{
|
||||||
IN int current; /* new current level */
|
IN int current; /* new current level */
|
||||||
IN int saving; /* new saving level */
|
IN int saving; /* new saving level */
|
||||||
IN int version; /* file format version for saving */
|
|
||||||
IN int period; /* duration between periodic saves (milliseconds) */
|
IN int period; /* duration between periodic saves (milliseconds) */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1255,7 +1258,7 @@ enum request
|
|||||||
REQ_NB_REQUESTS
|
REQ_NB_REQUESTS
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 11
|
#define SERVER_PROTOCOL_VERSION 12
|
||||||
|
|
||||||
/* ### make_requests end ### */
|
/* ### make_requests end ### */
|
||||||
/* Everything above this line is generated automatically by tools/make_requests */
|
/* Everything above this line is generated automatically by tools/make_requests */
|
||||||
|
@ -59,6 +59,7 @@ static void REGISTRY_Init(void);
|
|||||||
|
|
||||||
/* relative in ~user/.wine/ : */
|
/* relative in ~user/.wine/ : */
|
||||||
#define SAVE_CURRENT_USER "user.reg"
|
#define SAVE_CURRENT_USER "user.reg"
|
||||||
|
#define SAVE_DEFAULT_USER "userdef.reg"
|
||||||
#define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
|
#define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
|
||||||
#define SAVE_LOCAL_MACHINE "system.reg"
|
#define SAVE_LOCAL_MACHINE "system.reg"
|
||||||
|
|
||||||
@ -444,7 +445,7 @@ static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* _wine_loadreg [Internal]
|
* _wine_loadreg [Internal]
|
||||||
*/
|
*/
|
||||||
static void _wine_loadreg( HKEY hkey, char *fn )
|
static int _wine_loadreg( HKEY hkey, char *fn )
|
||||||
{
|
{
|
||||||
FILE *F;
|
FILE *F;
|
||||||
|
|
||||||
@ -453,10 +454,11 @@ static void _wine_loadreg( HKEY hkey, char *fn )
|
|||||||
F = fopen(fn,"rb");
|
F = fopen(fn,"rb");
|
||||||
if (F==NULL) {
|
if (F==NULL) {
|
||||||
WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
|
WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
_wine_loadsubreg(F,hkey,fn);
|
_wine_loadsubreg(F,hkey,fn);
|
||||||
fclose(F);
|
fclose(F);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NT REGISTRY LOADER */
|
/* NT REGISTRY LOADER */
|
||||||
@ -1346,18 +1348,16 @@ void _w31_loadreg(void) {
|
|||||||
|
|
||||||
|
|
||||||
/* configure save files and start the periodic saving timer */
|
/* 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();
|
struct set_registry_levels_request *req = get_req_buffer();
|
||||||
|
|
||||||
int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
|
int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
|
||||||
int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
|
|
||||||
int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
|
int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
|
||||||
|
|
||||||
/* set saving level (0 for saving everything, 1 for saving only modified keys) */
|
/* set saving level (0 for saving everything, 1 for saving only modified keys) */
|
||||||
req->current = 1;
|
req->current = 1;
|
||||||
req->saving = !all;
|
req->saving = !all;
|
||||||
req->version = version;
|
|
||||||
req->period = period * 1000;
|
req->period = period * 1000;
|
||||||
server_call( REQ_SET_REGISTRY_LEVELS );
|
server_call( REQ_SET_REGISTRY_LEVELS );
|
||||||
|
|
||||||
@ -1383,6 +1383,11 @@ static void SHELL_InitRegistrySaving(void)
|
|||||||
req->hkey = HKEY_LOCAL_MACHINE;
|
req->hkey = HKEY_LOCAL_MACHINE;
|
||||||
server_call( REQ_SAVE_REGISTRY_ATEXIT );
|
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( req->file, confdir );
|
||||||
strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
|
strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
|
||||||
req->hkey = HKEY_USERS;
|
req->hkey = HKEY_USERS;
|
||||||
@ -1403,7 +1408,6 @@ static void SetLoadLevel(int level)
|
|||||||
|
|
||||||
req->current = level;
|
req->current = level;
|
||||||
req->saving = 0;
|
req->saving = 0;
|
||||||
req->version = 1;
|
|
||||||
req->period = 0;
|
req->period = 0;
|
||||||
server_call( REQ_SET_REGISTRY_LEVELS );
|
server_call( REQ_SET_REGISTRY_LEVELS );
|
||||||
}
|
}
|
||||||
@ -1422,6 +1426,7 @@ void SHELL_LoadRegistry( void )
|
|||||||
char windir[MAX_PATHNAME_LEN];
|
char windir[MAX_PATHNAME_LEN];
|
||||||
char path[MAX_PATHNAME_LEN];
|
char path[MAX_PATHNAME_LEN];
|
||||||
int systemtype = REG_WIN31;
|
int systemtype = REG_WIN31;
|
||||||
|
HKEY hkey_users_default;
|
||||||
|
|
||||||
TRACE("(void)\n");
|
TRACE("(void)\n");
|
||||||
|
|
||||||
@ -1430,6 +1435,8 @@ void SHELL_LoadRegistry( void )
|
|||||||
REGISTRY_Init();
|
REGISTRY_Init();
|
||||||
SetLoadLevel(0);
|
SetLoadLevel(0);
|
||||||
|
|
||||||
|
if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default)) hkey_users_default = 0;
|
||||||
|
|
||||||
GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
|
GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
|
||||||
|
|
||||||
if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
|
if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
|
||||||
@ -1491,12 +1498,11 @@ void SHELL_LoadRegistry( void )
|
|||||||
MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
|
MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
|
||||||
}
|
}
|
||||||
/* default user.dat */
|
/* default user.dat */
|
||||||
if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
|
if (hkey_users_default)
|
||||||
{
|
{
|
||||||
strcpy(path, windir);
|
strcpy(path, windir);
|
||||||
strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
|
strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
|
||||||
NativeRegLoadKey(hkey, path, 1);
|
NativeRegLoadKey(hkey_users_default, path, 1);
|
||||||
RegCloseKey(hkey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1521,12 +1527,11 @@ void SHELL_LoadRegistry( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* default user.dat */
|
/* default user.dat */
|
||||||
if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
|
if (hkey_users_default)
|
||||||
{
|
{
|
||||||
strcpy(path, windir);
|
strcpy(path, windir);
|
||||||
strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
|
strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
|
||||||
NativeRegLoadKey(hkey, path, 1);
|
NativeRegLoadKey(hkey_users_default, path, 1);
|
||||||
RegCloseKey(hkey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1599,8 +1604,14 @@ void SHELL_LoadRegistry( void )
|
|||||||
str = fn + strlen(fn);
|
str = fn + strlen(fn);
|
||||||
*str++ = '/';
|
*str++ = '/';
|
||||||
|
|
||||||
strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
|
/* try to load HKU\.Default key only */
|
||||||
_wine_loadreg( HKEY_USERS, fn );
|
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 );
|
strcpy( str, SAVE_CURRENT_USER );
|
||||||
_wine_loadreg( HKEY_CURRENT_USER, fn );
|
_wine_loadreg( HKEY_CURRENT_USER, fn );
|
||||||
@ -1611,8 +1622,8 @@ void SHELL_LoadRegistry( void )
|
|||||||
if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
|
if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SHELL_InitRegistrySaving( hkey_users_default );
|
||||||
SHELL_InitRegistrySaving();
|
RegCloseKey( hkey_users_default );
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************* API FUNCTIONS ***************************************/
|
/********************* API FUNCTIONS ***************************************/
|
||||||
|
@ -73,17 +73,6 @@ struct key_value
|
|||||||
#define IS_ROOT_HKEY(h) (((h) >= HKEY_ROOT_FIRST) && ((h) <= HKEY_ROOT_LAST))
|
#define IS_ROOT_HKEY(h) (((h) >= HKEY_ROOT_FIRST) && ((h) <= HKEY_ROOT_LAST))
|
||||||
static struct key *root_keys[NB_ROOT_KEYS];
|
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 */
|
/* keys saving level */
|
||||||
/* current_level is the level that is put into all newly created or modified keys */
|
/* 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 current_level;
|
||||||
static int saving_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 struct timeval next_save_time; /* absolute time of next periodic save */
|
||||||
static int save_period; /* delay between periodic saves (ms) */
|
static int save_period; /* delay between periodic saves (ms) */
|
||||||
static struct timeout_user *save_timeout_user; /* saving timer */
|
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 );
|
dump_path( key->parent, base, f );
|
||||||
fprintf( f, "\\\\" );
|
fprintf( f, "\\\\" );
|
||||||
}
|
}
|
||||||
|
dump_strW( key->name, strlenW(key->name), 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 a value to a text file */
|
/* dump a value to a text file */
|
||||||
@ -274,7 +254,7 @@ static void key_destroy( struct object *obj )
|
|||||||
struct key *key = (struct key *)obj;
|
struct key *key = (struct key *)obj;
|
||||||
assert( obj->ops == &key_ops );
|
assert( obj->ops == &key_ops );
|
||||||
|
|
||||||
free( key->name );
|
if (key->name) free( key->name );
|
||||||
if (key->class) free( key->class );
|
if (key->class) free( key->class );
|
||||||
for (i = 0; i <= key->last_value; i++)
|
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;
|
struct key *key;
|
||||||
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
|
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
|
||||||
{
|
{
|
||||||
key->name = NULL;
|
|
||||||
key->class = NULL;
|
key->class = NULL;
|
||||||
key->flags = 0;
|
key->flags = 0;
|
||||||
key->last_subkey = -1;
|
key->last_subkey = -1;
|
||||||
@ -357,7 +336,7 @@ static struct key *alloc_key( const WCHAR *name, time_t modif )
|
|||||||
key->level = current_level;
|
key->level = current_level;
|
||||||
key->modif = modif;
|
key->modif = modif;
|
||||||
key->parent = NULL;
|
key->parent = NULL;
|
||||||
if (name && !(key->name = strdupW( name )))
|
if (!(key->name = strdupW( name )))
|
||||||
{
|
{
|
||||||
release_object( key );
|
release_object( key );
|
||||||
key = NULL;
|
key = NULL;
|
||||||
@ -719,16 +698,42 @@ static struct key_value *insert_value( struct key *key, const WCHAR *name )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* set a key value */
|
/* 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;
|
struct key_value *value;
|
||||||
void *ptr = NULL;
|
void *ptr = NULL;
|
||||||
|
|
||||||
/* first copy the data */
|
if (data_len + offset > total_len)
|
||||||
if (datalen)
|
|
||||||
{
|
{
|
||||||
if (!(ptr = mem_alloc( datalen ))) return;
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
memcpy( ptr, data, datalen );
|
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 )))
|
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 */
|
if (value->data) free( value->data ); /* already existing, free previous data */
|
||||||
value->type = type;
|
value->type = type;
|
||||||
value->len = datalen;
|
value->len = total_len;
|
||||||
value->data = ptr;
|
value->data = ptr;
|
||||||
touch_key( key );
|
touch_key( key );
|
||||||
if (debug_level > 1) dump_operation( key, value, "Set" );
|
if (debug_level > 1) dump_operation( key, value, "Set" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a key value */
|
/* 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;
|
struct key_value *value;
|
||||||
int index;
|
int index;
|
||||||
@ -754,7 +760,11 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *
|
|||||||
{
|
{
|
||||||
*type = value->type;
|
*type = value->type;
|
||||||
*len = value->len;
|
*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" );
|
if (debug_level > 1) dump_operation( key, value, "Get" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -765,7 +775,8 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* enumerate a key value */
|
/* 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;
|
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 );
|
strcpyW( name, value->name );
|
||||||
*type = value->type;
|
*type = value->type;
|
||||||
*len = value->len;
|
*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" );
|
if (debug_level > 1) dump_operation( key, value, "Enum" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -890,9 +905,17 @@ static struct key *create_root_key( int hkey )
|
|||||||
break;
|
break;
|
||||||
/* dynamically generated keys */
|
/* dynamically generated keys */
|
||||||
case HKEY_PERFORMANCE_DATA:
|
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:
|
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:
|
default:
|
||||||
key = NULL;
|
key = NULL;
|
||||||
assert(0);
|
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 */
|
/* 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;
|
WCHAR *p;
|
||||||
int res, len, modif;
|
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);
|
if (!sscanf( buffer + res, " %d", &modif )) modif = time(NULL);
|
||||||
|
|
||||||
for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') { p++; break; }
|
p = (WCHAR *)info->tmp;
|
||||||
return create_key( base, p, len - ((char *)p - info->tmp), NULL, 0, modif, &res );
|
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 */
|
/* 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 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 */
|
/* load all the keys from the input file */
|
||||||
static void load_keys( struct key *key, FILE *f )
|
static void load_keys( struct key *key, FILE *f )
|
||||||
{
|
{
|
||||||
struct key *subkey = NULL;
|
struct key *subkey = NULL;
|
||||||
struct file_load_info info;
|
struct file_load_info info;
|
||||||
char *p;
|
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.file = f;
|
||||||
info.len = 4;
|
info.len = 4;
|
||||||
@ -1230,7 +1295,9 @@ static void load_keys( struct key *key, FILE *f )
|
|||||||
{
|
{
|
||||||
case '[': /* new key */
|
case '[': /* new key */
|
||||||
if (subkey) release_object( subkey );
|
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;
|
break;
|
||||||
case '@': /* default value */
|
case '@': /* default value */
|
||||||
case '\"': /* value */
|
case '\"': /* value */
|
||||||
@ -1288,50 +1355,14 @@ static int update_level( struct key *key )
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dump a string to a registry save file in the old v1 format */
|
/* save a registry branch to a file */
|
||||||
static void save_string_v1( LPCWSTR str, FILE *f, int len )
|
static void save_all_subkeys( struct key *key, FILE *f )
|
||||||
{
|
{
|
||||||
if (!str) return;
|
fprintf( f, "WINE REGISTRY Version 2\n" );
|
||||||
while ((len == -1) ? *str : (*str && len--))
|
fprintf( f, ";; All keys relative to " );
|
||||||
{
|
dump_path( key, NULL, f );
|
||||||
if ((*str > 0x7f) || (*str == '\n') || (*str == '='))
|
fprintf( f, "\n" );
|
||||||
fprintf( f, "\\u%04x", *str );
|
save_subkeys( key, key, f );
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save a registry branch to a file handle */
|
/* 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" );
|
FILE *f = fdopen( fd, "w" );
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
fprintf( f, "WINE REGISTRY Version %d\n", saving_version );
|
save_all_subkeys( key, f );
|
||||||
if (saving_version == 2) save_subkeys( key, key, f );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
update_level( key );
|
|
||||||
save_subkeys_v1( key, 0, f );
|
|
||||||
}
|
|
||||||
if (fclose( f )) file_set_error();
|
if (fclose( f )) file_set_error();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1446,13 +1471,7 @@ static int save_branch( struct key *key, const char *path )
|
|||||||
dump_operation( key, NULL, "saving" );
|
dump_operation( key, NULL, "saving" );
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf( f, "WINE REGISTRY Version %d\n", saving_version );
|
save_all_subkeys( key, f );
|
||||||
if (saving_version == 2) save_subkeys( key, key, f );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
update_level( key );
|
|
||||||
save_subkeys_v1( key, 0, f );
|
|
||||||
}
|
|
||||||
ret = !fclose(f);
|
ret = !fclose(f);
|
||||||
|
|
||||||
if (tmp)
|
if (tmp)
|
||||||
@ -1594,16 +1613,14 @@ DECL_HANDLER(query_key_info)
|
|||||||
DECL_HANDLER(set_key_value)
|
DECL_HANDLER(set_key_value)
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
int max = get_req_size( req, req->data, sizeof(req->data[0]) );
|
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
|
||||||
int datalen = req->len;
|
unsigned int datalen = req->len;
|
||||||
if (datalen > max)
|
|
||||||
{
|
if (datalen > max) datalen = max;
|
||||||
set_error( STATUS_NO_MEMORY ); /* FIXME */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
|
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 );
|
release_object( key );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1612,11 +1629,13 @@ DECL_HANDLER(set_key_value)
|
|||||||
DECL_HANDLER(get_key_value)
|
DECL_HANDLER(get_key_value)
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
|
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
|
||||||
|
|
||||||
req->len = 0;
|
req->len = 0;
|
||||||
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
|
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 );
|
release_object( key );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1625,12 +1644,14 @@ DECL_HANDLER(get_key_value)
|
|||||||
DECL_HANDLER(enum_key_value)
|
DECL_HANDLER(enum_key_value)
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
|
unsigned int max = get_req_size( req, req->data, sizeof(req->data[0]) );
|
||||||
|
|
||||||
req->len = 0;
|
req->len = 0;
|
||||||
req->name[0] = 0;
|
req->name[0] = 0;
|
||||||
if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
|
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 );
|
release_object( key );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1682,7 +1703,6 @@ DECL_HANDLER(set_registry_levels)
|
|||||||
{
|
{
|
||||||
current_level = req->current;
|
current_level = req->current;
|
||||||
saving_level = req->saving;
|
saving_level = req->saving;
|
||||||
saving_version = req->version;
|
|
||||||
|
|
||||||
/* set periodic save timer */
|
/* set periodic save timer */
|
||||||
|
|
||||||
|
@ -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 )
|
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 );
|
dump_bytes( req->data, count );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_varargs_enum_key_value_reply( const struct enum_key_value_request *req )
|
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 );
|
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, " hkey=%d,", req->hkey );
|
||||||
fprintf( stderr, " type=%d,", req->type );
|
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=" );
|
fprintf( stderr, " name=" );
|
||||||
dump_path_t( req, &req->name );
|
dump_path_t( req, &req->name );
|
||||||
fprintf( stderr, "," );
|
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 )
|
static void dump_get_key_value_request( const struct get_key_value_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " hkey=%d,", req->hkey );
|
fprintf( stderr, " hkey=%d,", req->hkey );
|
||||||
|
fprintf( stderr, " offset=%08x,", req->offset );
|
||||||
fprintf( stderr, " name=" );
|
fprintf( stderr, " name=" );
|
||||||
dump_unicode_string( req, req->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 )
|
static void dump_enum_key_value_request( const struct enum_key_value_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " hkey=%d,", req->hkey );
|
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 )
|
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, " current=%d,", req->current );
|
||||||
fprintf( stderr, " saving=%d,", req->saving );
|
fprintf( stderr, " saving=%d,", req->saving );
|
||||||
fprintf( stderr, " version=%d,", req->version );
|
|
||||||
fprintf( stderr, " period=%d", req->period );
|
fprintf( stderr, " period=%d", req->period );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user