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); 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;
} }

View File

@ -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 */

View File

@ -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 ***************************************/

View File

@ -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 */

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 ) 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 );
} }