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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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++ = '/';
|
||||
|
||||
/* 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 ***************************************/
|
||||
|
|
|
@ -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,8 +905,16 @@ 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) );
|
||||
{
|
||||
static const WCHAR name[] = { 'D','Y','N','D','A','T','A',0 }; /* FIXME */
|
||||
key = alloc_key( name, time(NULL) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
key = NULL;
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue