mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
ntdll: Don't special-case default values in RtlQueryRegistryValues.
Additional tests reveal that RTL_QUERY_REGISTRY_DIRECT does work with non-string default values, it just requires a pointer to the value and it doesn't infer the size automatically. That means that the same code can be used to handle both default and non-default values.
This commit is contained in:
parent
5eafe53e54
commit
7053e0f641
2 changed files with 123 additions and 78 deletions
112
dlls/ntdll/reg.c
112
dlls/ntdll/reg.c
|
@ -243,58 +243,59 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
|
|||
PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
|
||||
{
|
||||
PUNICODE_STRING str = pQuery->EntryContext;
|
||||
ULONG type, len, offset, count, res;
|
||||
UNICODE_STRING src, dst;
|
||||
WCHAR *data, *wstr;
|
||||
LONG *bin;
|
||||
ULONG offset;
|
||||
PWSTR wstr;
|
||||
DWORD res;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
ULONG len;
|
||||
|
||||
if (pInfo == NULL)
|
||||
if (pInfo)
|
||||
{
|
||||
ULONG default_size = pQuery->DefaultLength;
|
||||
if (!default_size && pQuery->DefaultType == REG_SZ && pQuery->DefaultData)
|
||||
default_size = (wcslen(pQuery->DefaultData) + 1) * sizeof(WCHAR);
|
||||
|
||||
if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
|
||||
{
|
||||
if (pQuery->QueryRoutine)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (pQuery->DefaultType == REG_SZ || pQuery->DefaultType == REG_EXPAND_SZ ||
|
||||
pQuery->DefaultType == REG_MULTI_SZ || pQuery->DefaultType == REG_LINK)
|
||||
{
|
||||
if (!pQuery->DefaultData)
|
||||
return STATUS_DATA_OVERRUN;
|
||||
if (str->MaximumLength < default_size)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
memcpy(str->Buffer, pQuery->DefaultData, default_size);
|
||||
str->Length = default_size - sizeof(WCHAR);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (pQuery->QueryRoutine)
|
||||
{
|
||||
status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
|
||||
default_size, pContext, pQuery->EntryContext);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
type = pInfo->Type;
|
||||
data = (WCHAR*)((char*)pInfo + pInfo->DataOffset);
|
||||
len = pInfo->DataLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = pQuery->DefaultType;
|
||||
data = pQuery->DefaultData;
|
||||
len = pQuery->DefaultLength;
|
||||
|
||||
if (!data)
|
||||
return STATUS_DATA_OVERRUN;
|
||||
|
||||
if (!len)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_LINK:
|
||||
len = (wcslen(data) + 1) * sizeof(WCHAR);
|
||||
break;
|
||||
|
||||
case REG_MULTI_SZ:
|
||||
for (wstr = data; *wstr; wstr += count)
|
||||
{
|
||||
count = wcslen(wstr) + 1;
|
||||
len += count * sizeof(WCHAR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
|
||||
{
|
||||
if (pQuery->QueryRoutine)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
switch(pInfo->Type)
|
||||
switch (type)
|
||||
{
|
||||
case REG_EXPAND_SZ:
|
||||
if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
|
||||
{
|
||||
RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
|
||||
RtlInitUnicodeString(&src, data);
|
||||
res = 0;
|
||||
dst.MaximumLength = 0;
|
||||
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
|
||||
|
@ -307,12 +308,12 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
|
|||
case REG_SZ:
|
||||
case REG_LINK:
|
||||
if (str->Buffer == NULL)
|
||||
RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
|
||||
RtlCreateUnicodeString(str, data);
|
||||
else
|
||||
{
|
||||
if (str->MaximumLength < len)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
memcpy(str->Buffer, (char*)pInfo + pInfo->DataOffset, len);
|
||||
memcpy(str->Buffer, data, len);
|
||||
str->Length = len - sizeof(WCHAR);
|
||||
}
|
||||
break;
|
||||
|
@ -330,28 +331,27 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
|
|||
else if (str->MaximumLength < len)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
len -= sizeof(WCHAR);
|
||||
memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
|
||||
memcpy(str->Buffer, data, len);
|
||||
str->Buffer[len / sizeof(WCHAR)] = 0;
|
||||
str->Length = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
bin = pQuery->EntryContext;
|
||||
if (pInfo->DataLength <= sizeof(ULONG))
|
||||
memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
|
||||
pInfo->DataLength);
|
||||
if (len <= sizeof(ULONG))
|
||||
memcpy(bin, data, len);
|
||||
else
|
||||
{
|
||||
if (bin[0] < 0)
|
||||
{
|
||||
if (pInfo->DataLength <= -bin[0])
|
||||
memcpy(bin, (char*)pInfo + pInfo->DataOffset, pInfo->DataLength);
|
||||
if (len <= -bin[0])
|
||||
memcpy(bin, data, len);
|
||||
}
|
||||
else if (pInfo->DataLength <= bin[0])
|
||||
else if (len <= bin[0])
|
||||
{
|
||||
bin[0] = len;
|
||||
bin[1] = pInfo->Type;
|
||||
memcpy(bin + 2, (char*)pInfo + pInfo->DataOffset, len);
|
||||
bin[1] = type;
|
||||
memcpy(bin + 2, data, len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -360,15 +360,13 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
|
|||
else if (pQuery->QueryRoutine)
|
||||
{
|
||||
if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
|
||||
(pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
|
||||
(type != REG_EXPAND_SZ && type != REG_MULTI_SZ))
|
||||
{
|
||||
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
|
||||
((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
|
||||
pContext, pQuery->EntryContext);
|
||||
status = pQuery->QueryRoutine(pQuery->Name, type, data, len, pContext, pQuery->EntryContext);
|
||||
}
|
||||
else if (pInfo->Type == REG_EXPAND_SZ)
|
||||
else if (type == REG_EXPAND_SZ)
|
||||
{
|
||||
RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
|
||||
RtlInitUnicodeString(&src, data);
|
||||
res = 0;
|
||||
dst.MaximumLength = 0;
|
||||
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
|
||||
|
@ -381,11 +379,11 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
|
|||
}
|
||||
else /* REG_MULTI_SZ */
|
||||
{
|
||||
for (offset = 0; offset < pInfo->DataLength; offset += len)
|
||||
for (offset = 0; offset < len; offset += count)
|
||||
{
|
||||
wstr = (WCHAR*)((char*)pInfo + pInfo->DataOffset + offset);
|
||||
len = (wcslen(wstr) + 1) * sizeof(WCHAR);
|
||||
status = pQuery->QueryRoutine(pQuery->Name, REG_SZ, wstr, len, pContext, pQuery->EntryContext);
|
||||
wstr = (WCHAR*)((char*)data + offset);
|
||||
count = (wcslen(wstr) + 1) * sizeof(WCHAR);
|
||||
status = pQuery->QueryRoutine(pQuery->Name, REG_SZ, wstr, count, pContext, pQuery->EntryContext);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -2632,7 +2632,7 @@ static ULONG query_reg_values_direct_int;
|
|||
static union
|
||||
{
|
||||
ULONG size;
|
||||
char data[16];
|
||||
char data[32];
|
||||
}
|
||||
query_reg_values_direct_sized;
|
||||
|
||||
|
@ -2640,7 +2640,7 @@ static struct
|
|||
{
|
||||
ULONG size;
|
||||
ULONG type;
|
||||
char data[16];
|
||||
char data[32];
|
||||
}
|
||||
query_reg_values_direct_typed;
|
||||
|
||||
|
@ -2708,7 +2708,7 @@ static struct query_reg_values_test query_reg_values_tests[] =
|
|||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife32", &query_reg_values_direct_int }},
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, (WCHAR*)42
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, L"\x2a"
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife64", &query_reg_values_direct_sized }},
|
||||
|
@ -2783,11 +2783,11 @@ static struct query_reg_values_test query_reg_values_tests[] =
|
|||
},
|
||||
{
|
||||
{{ query_routine, 0, (WCHAR*)L"I don't exist", NULL, REG_EXPAND_SZ, (WCHAR*)L"%SYSTEMDRIVE%" }},
|
||||
STATUS_SUCCESS, 1, WINE_TODO_TYPE | WINE_TODO_SIZE, REG_SZ, L"C:"
|
||||
STATUS_SUCCESS, 1, 0, REG_SZ, L"C:"
|
||||
},
|
||||
{
|
||||
{{ query_routine, 0, (WCHAR*)L"I don't exist", NULL, REG_MULTI_SZ, (WCHAR*)L"Brussels\0Paris\0%PATH%\0" }},
|
||||
STATUS_SUCCESS, 3, EXPECT_DEFAULT_DATA | SPLIT_MULTI | WINE_TODO_CALLS | WINE_TODO_TYPE | WINE_TODO_SIZE
|
||||
STATUS_SUCCESS, 3, EXPECT_DEFAULT_DATA | SPLIT_MULTI
|
||||
},
|
||||
{
|
||||
{{ query_routine, 0, (WCHAR*)L"I don't exist", NULL, REG_DWORD, (WCHAR*)0xdeadbeef }},
|
||||
|
@ -2811,23 +2811,68 @@ static struct query_reg_values_test query_reg_values_tests[] =
|
|||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_str, REG_EXPAND_SZ, (WCHAR*)L"%SYSTEMDRIVE%" }},
|
||||
STATUS_SUCCESS, 0, WINE_TODO_SIZE | WINE_TODO_DATA, REG_NONE, L"C:"
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, L"C:"
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_str, REG_EXPAND_SZ, (WCHAR*)L"%SYSTEMDRIVE%" }},
|
||||
STATUS_SUCCESS, 0, WINE_TODO_SIZE, REG_NONE, L"\x2323", 0, 2 * sizeof(WCHAR)
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, L"\x2323", 0, 2 * sizeof(WCHAR)
|
||||
},
|
||||
/* DIRECT with a multi-string default value crashes on Windows */
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_int, REG_DWORD, (WCHAR*)0xdeadbeef }},
|
||||
STATUS_SUCCESS, 0
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_int, REG_DWORD, (WCHAR*)L"\x2a", sizeof(DWORD) }},
|
||||
STATUS_SUCCESS, 0, EXPECT_DEFAULT_DATA
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_sized, REG_DWORD, (WCHAR*)L"Some default", sizeof(L"Some default") }},
|
||||
STATUS_SUCCESS, 0, EXPECT_DEFAULT_DATA
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_sized, REG_DWORD, (WCHAR*)L"Some default", sizeof(L"Some default") }},
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, L"\xff", 1, 1
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_typed, REG_NONE, (WCHAR*)L"Some default", sizeof(L"Some default") }},
|
||||
STATUS_SUCCESS, 0, WINE_TODO_TYPE | WINE_TODO_SIZE, 0x23, NULL, -1
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_typed, REG_QWORD, (WCHAR*)L"Some default", sizeof(L"Some default") }},
|
||||
STATUS_SUCCESS, 0, WINE_TODO_TYPE | WINE_TODO_SIZE, 0x23, NULL, -1
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_typed, REG_QWORD, (WCHAR*)L"\x2a\0\0", sizeof(UINT64) }},
|
||||
STATUS_SUCCESS, 0, EXPECT_DEFAULT_DATA
|
||||
},
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_typed, REG_QWORD, (WCHAR*)L"\x2a\0\0", sizeof(UINT64) }},
|
||||
STATUS_SUCCESS, 0, 0, 0x23, L"\x23", 1, 1
|
||||
},
|
||||
/* DIRECT with a multi-string default value crashes on Windows without NOEXPAND */
|
||||
/* {
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_str, REG_NONE, (WCHAR*)L"A\0B\0C\0", sizeof(L"A\0B\0C\0") }},
|
||||
STATUS_SUCCESS, EXPECT_DEFAULT_DATA
|
||||
&query_reg_values_direct_str, REG_MULTI_SZ, (WCHAR*)L"A\0B\0C\0", sizeof(L"A\0B\0C\0") }},
|
||||
STATUS_SUCCESS, 0, EXPECT_DEFAULT_DATA
|
||||
}, */
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_str, REG_MULTI_SZ, (WCHAR*)L"A\0B\0C\0", sizeof(L"A\0B\0C\0") }},
|
||||
STATUS_SUCCESS, 0, EXPECT_DEFAULT_DATA | WINE_TODO_SIZE
|
||||
},
|
||||
/* The default value is not used if it is not valid */
|
||||
{
|
||||
{{ query_routine, 0, (WCHAR*)L"I don't exist", NULL, REG_SZ }},
|
||||
STATUS_DATA_OVERRUN, 0, EXPECT_DEFAULT_DATA | WINE_TODO_RET | WINE_TODO_CALLS
|
||||
STATUS_DATA_OVERRUN, 0, EXPECT_DEFAULT_DATA
|
||||
},
|
||||
{
|
||||
{{ query_routine, 0, (WCHAR*)L"I don't exist", NULL, REG_NONE, (WCHAR*)L"Some default" }},
|
||||
|
@ -2843,12 +2888,6 @@ static struct query_reg_values_test query_reg_values_tests[] =
|
|||
&query_reg_values_direct_str, REG_NONE, (WCHAR*)L"Some default" }},
|
||||
STATUS_SUCCESS, 0, 0, REG_NONE, NULL, -1
|
||||
},
|
||||
/* DIRECT additionally requires the default value to be a string */
|
||||
{
|
||||
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
|
||||
&query_reg_values_direct_int, REG_DWORD, (WCHAR*)0xdeadbeef }},
|
||||
STATUS_SUCCESS, 0
|
||||
},
|
||||
/* REQUIRED fails if the value doesn't exist and there is no default */
|
||||
{
|
||||
{{ query_routine, RTL_QUERY_REGISTRY_REQUIRED, (WCHAR*)L"I don't exist",
|
||||
|
@ -2985,12 +3024,12 @@ static void test_RtlQueryRegistryValues(void)
|
|||
{
|
||||
if (expected_data)
|
||||
{
|
||||
ok(!memcmp(&query_reg_values_direct_int, &expected_data, expected_size),
|
||||
ok(!memcmp(&query_reg_values_direct_int, expected_data, expected_size),
|
||||
"Data does not match\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
- ok(query_reg_values_direct_int == 1,
|
||||
ok(query_reg_values_direct_int == 1,
|
||||
"Expected data to not change, got %lu\n", query_reg_values_direct_int);
|
||||
}
|
||||
}
|
||||
|
@ -3001,17 +3040,25 @@ static void test_RtlQueryRegistryValues(void)
|
|||
}
|
||||
else if (query->EntryContext == &query_reg_values_direct_typed)
|
||||
{
|
||||
if (expected_size == -1)
|
||||
expected_size = sizeof(query_reg_values_direct_typed.data);
|
||||
|
||||
todo_wine_if(test->flags & WINE_TODO_SIZE)
|
||||
ok(query_reg_values_direct_typed.size == expected_size,
|
||||
"Expected size %lu, got %lu\n", expected_size, query_reg_values_direct_typed.size);
|
||||
|
||||
todo_wine_if(test->flags & WINE_TODO_TYPE)
|
||||
ok(query_reg_values_direct_typed.type == expected_type,
|
||||
"Expected type %lu, got %lu\n", expected_type, query_reg_values_direct_typed.type);
|
||||
|
||||
if (expected_data)
|
||||
{
|
||||
ok(!memcmp(query_reg_values_direct_typed.data, expected_data, expected_size),
|
||||
"Data does not match\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
winetest_pop_context();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue