From a01004d828d722a41a15595d5d3d780b8435b92d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 14 May 2000 22:57:57 +0000 Subject: [PATCH] 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. --- dlls/advapi32/registry.c | 235 ++++++++++++++++++++++++++++++---------------- include/server.h | 9 +- misc/registry.c | 43 +++++---- server/registry.c | 236 +++++++++++++++++++++++++---------------------- server/trace.c | 13 ++- 5 files changed, 324 insertions(+), 212 deletions(-) diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index c287fd990fc..30a5f2118e6 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -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; } diff --git a/include/server.h b/include/server.h index 234d8db6110..774b8ebb90b 100644 --- a/include/server.h +++ b/include/server.h @@ -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 */ diff --git a/misc/registry.c b/misc/registry.c index 48320bb426b..01b9645f5e4 100644 --- a/misc/registry.c +++ b/misc/registry.c @@ -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 ); @@ -1384,6 +1384,11 @@ static void SHELL_InitRegistrySaving(void) 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; server_call( REQ_SAVE_REGISTRY_ATEXIT ); @@ -1403,7 +1408,6 @@ static void SetLoadLevel(int level) req->current = level; req->saving = 0; - req->version = 1; req->period = 0; server_call( REQ_SET_REGISTRY_LEVELS ); } @@ -1422,6 +1426,7 @@ void SHELL_LoadRegistry( void ) char windir[MAX_PATHNAME_LEN]; char path[MAX_PATHNAME_LEN]; int systemtype = REG_WIN31; + HKEY hkey_users_default; TRACE("(void)\n"); @@ -1430,6 +1435,8 @@ void SHELL_LoadRegistry( void ) REGISTRY_Init(); SetLoadLevel(0); + if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default)) hkey_users_default = 0; + GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN ); if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1)) @@ -1491,12 +1498,11 @@ void SHELL_LoadRegistry( void ) MESSAGE("check wine.conf, section [Wine], value 'Profile'\n"); } /* default user.dat */ - if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey)) + if (hkey_users_default) { strcpy(path, windir); strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1); - NativeRegLoadKey(hkey, path, 1); - RegCloseKey(hkey); + NativeRegLoadKey(hkey_users_default, path, 1); } } else @@ -1521,12 +1527,11 @@ void SHELL_LoadRegistry( void ) } /* default user.dat */ - if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey)) + if (hkey_users_default) { strcpy(path, windir); strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1); - NativeRegLoadKey(hkey, path, 1); - RegCloseKey(hkey); + NativeRegLoadKey(hkey_users_default, path, 1); } /* @@ -1599,8 +1604,14 @@ void SHELL_LoadRegistry( void ) str = fn + strlen(fn); *str++ = '/'; - strcpy( str, SAVE_LOCAL_USERS_DEFAULT ); - _wine_loadreg( HKEY_USERS, fn ); + /* try to load HKU\.Default key only */ + strcpy( str, SAVE_DEFAULT_USER ); + if (_wine_loadreg( hkey_users_default, fn )) + { + /* if not found load old file containing both HKU\.Default and HKU\user */ + strcpy( str, SAVE_LOCAL_USERS_DEFAULT ); + _wine_loadreg( HKEY_USERS, fn ); + } strcpy( str, SAVE_CURRENT_USER ); _wine_loadreg( HKEY_CURRENT_USER, fn ); @@ -1611,8 +1622,8 @@ void SHELL_LoadRegistry( void ) if (fn != path) HeapFree( GetProcessHeap(), 0, fn ); } } - - SHELL_InitRegistrySaving(); + SHELL_InitRegistrySaving( hkey_users_default ); + RegCloseKey( hkey_users_default ); } /********************* API FUNCTIONS ***************************************/ diff --git a/server/registry.c b/server/registry.c index 6d6b034943d..e4bcf217a94 100644 --- a/server/registry.c +++ b/server/registry.c @@ -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; - + + if (data_len + offset > total_len) + { + 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 (datalen) + if (total_len) { - if (!(ptr = mem_alloc( datalen ))) return; - memcpy( ptr, data, datalen ); + if (!(ptr = mem_alloc( total_len ))) return; + memcpy( ptr, data, data_len ); + if (data_len < total_len) memset( (char *)ptr + data_len, 0, total_len - data_len ); } if (!(value = insert_value( key, name ))) @@ -738,14 +743,15 @@ static void set_value( struct key *key, WCHAR *name, int type, int datalen, void } if (value->data) free( value->data ); /* already existing, free previous data */ value->type = type; - value->len = datalen; + value->len = total_len; value->data = ptr; touch_key( key ); if (debug_level > 1) dump_operation( key, value, "Set" ); } /* get a key value */ -static void get_value( struct key *key, WCHAR *name, int *type, int *len, void *data ) +static void get_value( struct key *key, WCHAR *name, unsigned int offset, + unsigned int maxlen, int *type, int *len, void *data ) { struct key_value *value; int index; @@ -754,7 +760,11 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void * { *type = value->type; *len = value->len; - if (value->data) memcpy( data, value->data, value->len ); + if (value->data && offset < value->len) + { + if (maxlen > value->len - offset) maxlen = value->len - offset; + memcpy( data, (char *)value->data + offset, maxlen ); + } if (debug_level > 1) dump_operation( key, value, "Get" ); } else @@ -765,7 +775,8 @@ static void get_value( struct key *key, WCHAR *name, int *type, int *len, void * } /* enumerate a key value */ -static void enum_value( struct key *key, int i, WCHAR *name, int *type, int *len, void *data ) +static void enum_value( struct key *key, int i, WCHAR *name, unsigned int offset, + unsigned int maxlen, int *type, int *len, void *data ) { struct key_value *value; @@ -776,7 +787,11 @@ static void enum_value( struct key *key, int i, WCHAR *name, int *type, int *len strcpyW( name, value->name ); *type = value->type; *len = value->len; - if (value->data) memcpy( data, value->data, value->len ); + if (value->data && offset < value->len) + { + if (maxlen > value->len - offset) maxlen = value->len - offset; + memcpy( data, (char *)value->data + offset, maxlen ); + } if (debug_level > 1) dump_operation( key, value, "Enum" ); } } @@ -890,9 +905,17 @@ static struct key *create_root_key( int hkey ) break; /* dynamically generated keys */ case HKEY_PERFORMANCE_DATA: + { + static const WCHAR name[] = { 'P','E','R','F','D','A','T','A',0 }; /* FIXME */ + key = alloc_key( name, time(NULL) ); + } + break; case HKEY_DYN_DATA: - key = alloc_key( NULL, time(NULL) ); - break; + { + static const WCHAR name[] = { 'D','Y','N','D','A','T','A',0 }; /* FIXME */ + key = alloc_key( name, time(NULL) ); + } + break; default: key = NULL; assert(0); @@ -1067,7 +1090,8 @@ static int get_data_type( const char *buffer, int *type, int *parse_type ) } /* load and create a key from the input file */ -static struct key *load_key( struct key *base, const char *buffer, struct file_load_info *info ) +static struct key *load_key( struct key *base, const char *buffer, unsigned int options, + int prefix_len, struct file_load_info *info ) { WCHAR *p; int res, len, modif; @@ -1082,8 +1106,20 @@ static struct key *load_key( struct key *base, const char *buffer, struct file_l } if (!sscanf( buffer + res, " %d", &modif )) modif = time(NULL); - for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') { p++; break; } - return create_key( base, p, len - ((char *)p - info->tmp), NULL, 0, modif, &res ); + p = (WCHAR *)info->tmp; + while (prefix_len && *p) { if (*p++ == '\\') prefix_len--; } + + if (!*p) + { + if (prefix_len > 1) + { + file_read_error( "Malformed key", info ); + return NULL; + } + /* empty key name, return base key */ + return (struct key *)grab_object( base ); + } + return create_key( base, p, len - ((char *)p - info->tmp), NULL, options, modif, &res ); } /* parse a comma-separated list of hex digits */ @@ -1198,12 +1234,41 @@ static int load_value( struct key *key, const char *buffer, struct file_load_inf return 0; } +/* return the length (in path elements) of name that is part of the key name */ +/* for instance if key is USER\foo\bar and name is foo\bar\baz, return 2 */ +static int get_prefix_len( struct key *key, const char *name, struct file_load_info *info ) +{ + WCHAR *p; + int res; + int len = strlen(name) * sizeof(WCHAR); + if (!get_file_tmp_space( info, len )) return NULL; + + if ((res = parse_strW( (WCHAR *)info->tmp, &len, name, ']' )) == -1) + { + file_read_error( "Malformed key", info ); + return NULL; + } + for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') break; + *p = 0; + for (res = 1; key; res++) + { + if (!strcmpiW( (WCHAR *)info->tmp, key->name )) break; + key = key->parent; + } + if (!key) res = 0; /* no matching name */ + return res; +} + /* load all the keys from the input file */ static void load_keys( struct key *key, FILE *f ) { struct key *subkey = NULL; struct file_load_info info; char *p; + unsigned int options = 0; + int prefix_len = -1; /* number of key name prefixes to skip */ + + if (key->flags & KEY_VOLATILE) options |= REG_OPTION_VOLATILE; info.file = f; info.len = 4; @@ -1230,7 +1295,9 @@ static void load_keys( struct key *key, FILE *f ) { case '[': /* new key */ if (subkey) release_object( subkey ); - subkey = load_key( key, p + 1, &info ); + if (prefix_len == -1) prefix_len = get_prefix_len( key, p + 1, &info ); + if (!(subkey = load_key( key, p + 1, options, prefix_len, &info ))) + file_read_error( "Error creating key", &info ); break; case '@': /* default value */ case '\"': /* value */ @@ -1288,50 +1355,14 @@ static int update_level( struct key *key ) return max; } -/* dump a string to a registry save file in the old v1 format */ -static void save_string_v1( LPCWSTR str, FILE *f, int len ) -{ - 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 ) +/* save a registry branch to a file */ +static void save_all_subkeys( struct key *key, 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 */ diff --git a/server/trace.c b/server/trace.c index 176c02eabea..4ea9319988a 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ); } -- 2.11.4.GIT