[NTFS]
[reactos.git] / rostests / kmtests / rtl / RtlRegistry.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for RtlQueryRegistryValues
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #define KMT_EMULATE_KERNEL
9 #include <kmt_test.h>
10
11 #ifdef KMT_KERNEL_MODE
12 #define KMT_KERNEL_HANDLE OBJ_KERNEL_HANDLE
13 #else
14 #define KMT_KERNEL_HANDLE 0
15 #endif
16
17 #ifndef RTL_NUMBER_OF
18 #define RTL_NUMBER_OF(x) (sizeof(x) / sizeof(x[0]))
19 #endif
20
21 typedef struct
22 {
23 PCWSTR ValueName;
24 ULONG ValueType;
25 PVOID ValueData;
26 ULONG ValueLength;
27 } EXPECTED_VALUE, *PEXPECTED_VALUE;
28
29 typedef struct
30 {
31 ULONG Count;
32 ULONG CurrentIndex;
33 EXPECTED_VALUE Values[20];
34 } EXPECTED_VALUES, *PEXPECTED_VALUES;
35
36 //static RTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
37 static
38 NTSTATUS
39 NTAPI
40 QueryRoutine(
41 _In_ PWSTR ValueName,
42 _In_ ULONG ValueType,
43 _In_ PVOID ValueData,
44 _In_ ULONG ValueLength,
45 _In_ PVOID Context,
46 _In_ PVOID EntryContext)
47 {
48 PEXPECTED_VALUES ExpectedValues = Context;
49 PEXPECTED_VALUE Expected;
50 SIZE_T EqualBytes;
51
52 ok(ExpectedValues->CurrentIndex < ExpectedValues->Count,
53 "Call number %lu, expected only %lu\n",
54 ExpectedValues->CurrentIndex, ExpectedValues->Count);
55 if (!skip(ExpectedValues->CurrentIndex < ExpectedValues->Count, "Out of bounds\n"))
56 {
57 Expected = &ExpectedValues->Values[ExpectedValues->CurrentIndex];
58 if (EntryContext)
59 ok_eq_pointer(EntryContext, Expected);
60 ok_eq_wstr(ValueName, Expected->ValueName);
61 ok_eq_ulong(ValueType, Expected->ValueType);
62 ok_eq_ulong(ValueLength, Expected->ValueLength);
63 EqualBytes = RtlCompareMemory(ValueData,
64 Expected->ValueData,
65 min(ValueLength, Expected->ValueLength));
66 ok_eq_size(EqualBytes, Expected->ValueLength);
67 }
68
69 ExpectedValues->CurrentIndex++;
70 return STATUS_SUCCESS;
71 }
72
73 static
74 VOID
75 TestRtlQueryRegistryValues(
76 _In_ HANDLE KeyHandle)
77 {
78 NTSTATUS Status;
79 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"TestValue");
80 RTL_QUERY_REGISTRY_TABLE QueryTable[] =
81 {
82 { QueryRoutine, 0, L"TestValue", NULL, REG_NONE, NULL, 0 },
83 { NULL }
84 };
85 EXPECTED_VALUES Expected;
86 typedef struct
87 {
88 PWSTR Str;
89 ULONG Len;
90 } STR_AND_LEN;
91 #define CONST_STR_AND_LEN(d) { (d), sizeof(d) }
92 #define CSAL CONST_STR_AND_LEN
93
94 #define NO_AUTO_LEN 1
95 #define NO_DEFAULT 2
96 #define AUTO_DIFFERS 4
97 #define DEFAULT_DIFFERS 8
98 struct
99 {
100 STR_AND_LEN Value;
101 ULONG ExpectedCount;
102 STR_AND_LEN Expected[20];
103 ULONG Flags;
104 ULONG DefaultExpectedCount;
105 STR_AND_LEN DefaultExpected[20];
106
107 } Tests[] =
108 {
109 { { NULL, 0 }, 0, { { NULL, 0 } }, NO_AUTO_LEN | NO_DEFAULT },
110 { CSAL(L""), 0, { { NULL, 0 } }, NO_AUTO_LEN },
111 { CSAL(L"\0"), 1, { CSAL(L"") },
112 AUTO_DIFFERS | DEFAULT_DIFFERS, 0, { { NULL, 0 } } },
113 { CSAL(L"String"), 1, { CSAL(L"String") }, NO_AUTO_LEN },
114 { CSAL(L"String\0"), 1, { CSAL(L"String") } },
115 { CSAL(L"String1\0String2"), 2, { CSAL(L"String1"), CSAL(L"String2") }, NO_AUTO_LEN },
116 { CSAL(L"String1\0String2\0"), 2, { CSAL(L"String1"), CSAL(L"String2") } },
117 { CSAL(L"String1\0\0String3"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") }, NO_AUTO_LEN },
118 { CSAL(L"String1\0\0String3\0"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") },
119 AUTO_DIFFERS, 1, { CSAL(L"String1") } },
120 };
121
122 #define DO_QUERY(ExpectedArray, ExpectedCount) do \
123 { \
124 ULONG _i; \
125 ULONG _ExpectedCount = (ExpectedCount); \
126 for (_i = 0; _i < _ExpectedCount; _i++) \
127 { \
128 Expected.Values[_i].ValueName = ValueName.Buffer; \
129 Expected.Values[_i].ValueType = REG_SZ; \
130 Expected.Values[_i].ValueData = (ExpectedArray)[_i].Str; \
131 Expected.Values[_i].ValueLength = (ExpectedArray)[_i].Len; \
132 } \
133 Expected.CurrentIndex = 0; \
134 Expected.Count = _ExpectedCount; \
135 if (_ExpectedCount == 1) \
136 QueryTable[0].EntryContext = &Expected.Values[0]; \
137 else \
138 QueryTable[0].EntryContext = NULL; \
139 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, \
140 (PCWSTR)KeyHandle, \
141 QueryTable, \
142 &Expected, \
143 NULL); \
144 ok_eq_hex(Status, STATUS_SUCCESS); \
145 ok_eq_ulong(Expected.CurrentIndex, Expected.Count); \
146 } while(0)
147
148 ULONG TestCount = RTL_NUMBER_OF(Tests);
149 ULONG i;
150
151 for (i = 0; i < TestCount; i++)
152 {
153 trace("Set: %lu\n", i);
154 Status = ZwSetValueKey(KeyHandle,
155 &ValueName,
156 0,
157 REG_MULTI_SZ,
158 Tests[i].Value.Str,
159 Tests[i].Value.Len);
160 ok_eq_hex(Status, STATUS_SUCCESS);
161
162 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
163 }
164
165 /* Delete value to test default values */
166 Status = ZwDeleteValueKey(KeyHandle, &ValueName);
167 ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND,
168 "ZwDeleteValueKey returned %lx\n", Status);
169
170 /* Default: REG_NONE */
171 DO_QUERY((STR_AND_LEN *)NULL, 0);
172
173 for (i = 0; i < TestCount; i++)
174 {
175 if (Tests[i].Flags & NO_DEFAULT)
176 continue;
177 trace("Default: %lu\n", i);
178 QueryTable[0].DefaultType = REG_MULTI_SZ;
179 QueryTable[0].DefaultData = Tests[i].Value.Str;
180 QueryTable[0].DefaultLength = Tests[i].Value.Len;
181
182 if (Tests[i].Flags & DEFAULT_DIFFERS)
183 DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount);
184 else
185 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
186 }
187
188 for (i = 0; i < TestCount; i++)
189 {
190 if (Tests[i].Flags & NO_AUTO_LEN)
191 continue;
192 trace("Auto: %lu\n", i);
193 QueryTable[0].DefaultType = REG_MULTI_SZ;
194 QueryTable[0].DefaultData = Tests[i].Value.Str;
195 QueryTable[0].DefaultLength = 0;
196
197 if (Tests[i].Flags & AUTO_DIFFERS)
198 DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount);
199 else
200 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
201 }
202 }
203
204 START_TEST(RtlRegistry)
205 {
206 NTSTATUS Status;
207 UNICODE_STRING KeyName;
208 OBJECT_ATTRIBUTES ObjectAttributes;
209 HANDLE SoftwareHandle;
210 HANDLE KeyHandle;
211
212 RtlInitUnicodeString(&KeyName, L"\\Registry\\MACHINE\\Software");
213 InitializeObjectAttributes(&ObjectAttributes,
214 &KeyName,
215 OBJ_CASE_INSENSITIVE | KMT_KERNEL_HANDLE,
216 NULL,
217 NULL);
218 Status = ZwOpenKey(&SoftwareHandle,
219 KEY_CREATE_SUB_KEY,
220 &ObjectAttributes);
221 ok_eq_hex(Status, STATUS_SUCCESS);
222 if (skip(NT_SUCCESS(Status) && SoftwareHandle != NULL, "No software key\n"))
223 return;
224
225 RtlInitUnicodeString(&KeyName, L"RtlRegistryKmtestKey");
226 InitializeObjectAttributes(&ObjectAttributes,
227 &KeyName,
228 OBJ_CASE_INSENSITIVE | KMT_KERNEL_HANDLE,
229 SoftwareHandle,
230 NULL);
231 Status = ZwCreateKey(&KeyHandle,
232 KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE,
233 &ObjectAttributes,
234 0,
235 NULL,
236 REG_OPTION_VOLATILE,
237 NULL);
238 ok_eq_hex(Status, STATUS_SUCCESS);
239
240 if (!skip(NT_SUCCESS(Status) && KeyHandle != NULL, "No test key\n"))
241 {
242 TestRtlQueryRegistryValues(KeyHandle);
243
244 Status = ZwDeleteKey(KeyHandle);
245 ok_eq_hex(Status, STATUS_SUCCESS);
246 Status = ZwClose(KeyHandle);
247 ok_eq_hex(Status, STATUS_SUCCESS);
248 }
249 }