Implemented many console & registry functions to get registry explorer running.
[reactos.git] / reactos / ntoskrnl / cm / rtlfunc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/rtlfunc.c
5 * PURPOSE: Rtlxxx function for registry access
6 * UPDATE HISTORY:
7 */
8
9 #include <ddk/ntddk.h>
10 #include <roscfg.h>
11 #include <internal/ob.h>
12 #include <limits.h>
13 #include <string.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 #include "cm.h"
21
22 NTSTATUS STDCALL
23 RtlCheckRegistryKey(IN ULONG RelativeTo,
24 IN PWSTR Path)
25 {
26 HANDLE KeyHandle;
27 NTSTATUS Status;
28
29 Status = RtlpGetRegistryHandle(RelativeTo,
30 Path,
31 FALSE,
32 &KeyHandle);
33 if (!NT_SUCCESS(Status))
34 return Status;
35
36 NtClose(KeyHandle);
37
38 return STATUS_SUCCESS;
39 }
40
41
42 NTSTATUS STDCALL
43 RtlCreateRegistryKey(IN ULONG RelativeTo,
44 IN PWSTR Path)
45 {
46 HANDLE KeyHandle;
47 NTSTATUS Status;
48
49 Status = RtlpGetRegistryHandle(RelativeTo,
50 Path,
51 TRUE,
52 &KeyHandle);
53 if (!NT_SUCCESS(Status))
54 return Status;
55
56 NtClose(KeyHandle);
57
58 return STATUS_SUCCESS;
59 }
60
61
62 NTSTATUS STDCALL
63 RtlDeleteRegistryValue(IN ULONG RelativeTo,
64 IN PWSTR Path,
65 IN PWSTR ValueName)
66 {
67 HANDLE KeyHandle;
68 NTSTATUS Status;
69 UNICODE_STRING Name;
70
71 Status = RtlpGetRegistryHandle(RelativeTo,
72 Path,
73 TRUE,
74 &KeyHandle);
75 if (!NT_SUCCESS(Status))
76 return Status;
77
78 RtlInitUnicodeString(&Name,
79 ValueName);
80
81 NtDeleteValueKey(KeyHandle,
82 &Name);
83
84 NtClose(KeyHandle);
85
86 return STATUS_SUCCESS;
87 }
88
89
90 NTSTATUS STDCALL
91 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
92 OUT PHANDLE KeyHandle)
93 {
94 OBJECT_ATTRIBUTES ObjectAttributes;
95 UNICODE_STRING KeyPath;
96 NTSTATUS Status;
97
98 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
99 if (NT_SUCCESS(Status))
100 {
101 InitializeObjectAttributes(&ObjectAttributes,
102 &KeyPath,
103 OBJ_CASE_INSENSITIVE,
104 NULL,
105 NULL);
106 Status = NtOpenKey(KeyHandle,
107 DesiredAccess,
108 &ObjectAttributes);
109 RtlFreeUnicodeString(&KeyPath);
110 if (NT_SUCCESS(Status))
111 return STATUS_SUCCESS;
112 }
113
114 RtlInitUnicodeString(&KeyPath,
115 L"\\Registry\\User\\.Default");
116
117 InitializeObjectAttributes(&ObjectAttributes,
118 &KeyPath,
119 OBJ_CASE_INSENSITIVE,
120 NULL,
121 NULL);
122 Status = NtOpenKey(KeyHandle,
123 DesiredAccess,
124 &ObjectAttributes);
125 return(Status);
126 }
127
128
129 NTSTATUS STDCALL
130 RtlQueryRegistryValues(IN ULONG RelativeTo,
131 IN PWSTR Path,
132 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
133 IN PVOID Context,
134 IN PVOID Environment)
135 {
136 NTSTATUS Status;
137 HANDLE BaseKeyHandle;
138 HANDLE CurrentKeyHandle;
139 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
140 OBJECT_ATTRIBUTES ObjectAttributes;
141 UNICODE_STRING KeyName;
142 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
143 ULONG BufferSize;
144 ULONG ResultSize;
145
146 DPRINT("RtlQueryRegistryValues() called\n");
147
148 Status = RtlpGetRegistryHandle(RelativeTo,
149 Path,
150 FALSE,
151 &BaseKeyHandle);
152 if (!NT_SUCCESS(Status))
153 {
154 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status);
155 return Status;
156 }
157
158 CurrentKeyHandle = BaseKeyHandle;
159 QueryEntry = QueryTable;
160 while ((QueryEntry->QueryRoutine != NULL) ||
161 (QueryEntry->Name != NULL))
162 {
163 //CSH: Was:
164 //if ((QueryEntry->QueryRoutine == NULL) &&
165 // ((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_DIRECT)) != 0))
166 // Which is more correct?
167 if ((QueryEntry->QueryRoutine == NULL) &&
168 ((QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY) != 0))
169 {
170 DPRINT("Bad parameters\n");
171 Status = STATUS_INVALID_PARAMETER;
172 break;
173 }
174
175 DPRINT("Name: %S\n", QueryEntry->Name);
176
177 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
178 (BaseKeyHandle != CurrentKeyHandle))
179 {
180 NtClose(CurrentKeyHandle);
181 CurrentKeyHandle = BaseKeyHandle;
182 }
183
184 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
185 {
186 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
187
188 RtlInitUnicodeString(&KeyName,
189 QueryEntry->Name);
190 InitializeObjectAttributes(&ObjectAttributes,
191 &KeyName,
192 OBJ_CASE_INSENSITIVE,
193 BaseKeyHandle,
194 NULL);
195 Status = NtOpenKey(&CurrentKeyHandle,
196 KEY_ALL_ACCESS,
197 &ObjectAttributes);
198 if (!NT_SUCCESS(Status))
199 break;
200 }
201 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
202 {
203 DPRINT("Query value directly: %S\n", QueryEntry->Name);
204
205 RtlInitUnicodeString(&KeyName,
206 QueryEntry->Name);
207
208 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
209 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
210 if (ValueInfo == NULL)
211 {
212 Status = STATUS_NO_MEMORY;
213 break;
214 }
215
216 Status = ZwQueryValueKey(CurrentKeyHandle,
217 &KeyName,
218 KeyValuePartialInformation,
219 ValueInfo,
220 BufferSize,
221 &ResultSize);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT("ZwQueryValueKey() failed with status %x\n", Status);
225 ExFreePool(ValueInfo);
226 break;
227 }
228 else
229 {
230 if (ValueInfo->Type == REG_SZ)
231 {
232 PUNICODE_STRING ValueString;
233 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
234 if (ValueString->Buffer == 0)
235 {
236 RtlInitUnicodeString(ValueString, NULL);
237 ValueString->MaximumLength = 256 * sizeof(WCHAR);
238 ValueString->Buffer = ExAllocatePool(PagedPool, ValueString->MaximumLength);
239 if (!ValueString->Buffer)
240 break;
241 ValueString->Buffer[0] = 0;
242 }
243 ValueString->Length = RtlMin(ValueInfo->DataLength,
244 ValueString->MaximumLength - sizeof(WCHAR));
245 memcpy(ValueString->Buffer,
246 ValueInfo->Data,
247 ValueInfo->DataLength);
248 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
249 }
250 else
251 {
252 memcpy(QueryEntry->EntryContext,
253 ValueInfo->Data,
254 ValueInfo->DataLength);
255 }
256 }
257
258 ExFreePool (ValueInfo);
259 }
260 else
261 {
262 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
263
264 }
265
266 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
267 {
268 DPRINT("Delete value: %S\n", QueryEntry->Name);
269
270 }
271
272 QueryEntry++;
273 }
274
275 if (CurrentKeyHandle != BaseKeyHandle)
276 NtClose(CurrentKeyHandle);
277
278 NtClose(BaseKeyHandle);
279
280 return Status;
281 }
282
283
284 NTSTATUS STDCALL
285 RtlWriteRegistryValue(IN ULONG RelativeTo,
286 IN PWSTR Path,
287 IN PWSTR ValueName,
288 IN ULONG ValueType,
289 IN PVOID ValueData,
290 IN ULONG ValueLength)
291 {
292 HANDLE KeyHandle;
293 NTSTATUS Status;
294 UNICODE_STRING Name;
295
296 Status = RtlpGetRegistryHandle(RelativeTo,
297 Path,
298 TRUE,
299 &KeyHandle);
300 if (!NT_SUCCESS(Status))
301 return Status;
302
303 RtlInitUnicodeString(&Name,
304 ValueName);
305
306 NtSetValueKey(KeyHandle,
307 &Name,
308 0,
309 ValueType,
310 ValueData,
311 ValueLength);
312
313 NtClose(KeyHandle);
314
315 return STATUS_SUCCESS;
316 }
317
318 NTSTATUS STDCALL
319 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath)
320 {
321 /* FIXME: !!! */
322 RtlCreateUnicodeString(KeyPath,
323 L"\\Registry\\User\\.Default");
324
325 return STATUS_SUCCESS;
326 }
327
328 /* ------------------------------------------ Private Implementation */
329
330
331 NTSTATUS
332 RtlpGetRegistryHandle(ULONG RelativeTo,
333 PWSTR Path,
334 BOOLEAN Create,
335 PHANDLE KeyHandle)
336 {
337 UNICODE_STRING KeyName;
338 WCHAR KeyBuffer[MAX_PATH];
339 OBJECT_ATTRIBUTES ObjectAttributes;
340 NTSTATUS Status;
341
342 if (RelativeTo & RTL_REGISTRY_HANDLE)
343 {
344 Status = NtDuplicateObject(
345 PsGetCurrentProcessId(),
346 (PHANDLE)&Path,
347 PsGetCurrentProcessId(),
348 KeyHandle,
349 0,
350 FALSE,
351 DUPLICATE_SAME_ACCESS);
352 return Status;
353 }
354
355 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
356 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
357
358 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
359 return STATUS_INVALID_PARAMETER;
360
361 KeyName.Length = 0;
362 KeyName.MaximumLength = MAX_PATH;
363 KeyName.Buffer = KeyBuffer;
364 KeyBuffer[0] = 0;
365
366 switch (RelativeTo)
367 {
368 case RTL_REGISTRY_SERVICES:
369 RtlAppendUnicodeToString(&KeyName,
370 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
371 break;
372
373 case RTL_REGISTRY_CONTROL:
374 RtlAppendUnicodeToString(&KeyName,
375 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
376 break;
377
378 case RTL_REGISTRY_WINDOWS_NT:
379 RtlAppendUnicodeToString(&KeyName,
380 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
381 break;
382
383 case RTL_REGISTRY_DEVICEMAP:
384 RtlAppendUnicodeToString(&KeyName,
385 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
386 break;
387
388 case RTL_REGISTRY_USER:
389 Status = RtlFormatCurrentUserKeyPath(&KeyName);
390 if (!NT_SUCCESS(Status))
391 return Status;
392 break;
393
394 /* ReactOS specific */
395 case RTL_REGISTRY_ENUM:
396 RtlAppendUnicodeToString(&KeyName,
397 L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
398 break;
399 }
400
401 if (Path[0] != L'\\')
402 {
403 RtlAppendUnicodeToString(&KeyName,
404 Path);
405 }
406 else
407 {
408 Path++;
409 RtlAppendUnicodeToString(&KeyName,
410 Path);
411 }
412
413 InitializeObjectAttributes(&ObjectAttributes,
414 &KeyName,
415 OBJ_CASE_INSENSITIVE,
416 NULL,
417 NULL);
418
419 if (Create == TRUE)
420 {
421 Status = NtCreateKey(KeyHandle,
422 KEY_ALL_ACCESS,
423 &ObjectAttributes,
424 0,
425 NULL,
426 0,
427 NULL);
428 }
429 else
430 {
431 Status = NtOpenKey(KeyHandle,
432 KEY_ALL_ACCESS,
433 &ObjectAttributes);
434 }
435
436 return Status;
437 }
438
439
440 NTSTATUS
441 RtlpCreateRegistryKeyPath(PWSTR Path)
442 {
443 OBJECT_ATTRIBUTES ObjectAttributes;
444 WCHAR KeyBuffer[MAX_PATH];
445 UNICODE_STRING KeyName;
446 HANDLE KeyHandle;
447 NTSTATUS Status;
448 PWCHAR Current;
449 PWCHAR Next;
450
451 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
452 {
453 return STATUS_INVALID_PARAMETER;
454 }
455
456 wcsncpy(KeyBuffer, Path, MAX_PATH-1);
457 RtlInitUnicodeString(&KeyName, KeyBuffer);
458
459 /* Skip \\Registry\\ */
460 Current = KeyName.Buffer;
461 Current = wcschr(Current, '\\') + 1;
462 Current = wcschr(Current, '\\') + 1;
463
464 do {
465 Next = wcschr(Current, '\\');
466 if (Next == NULL)
467 {
468 /* The end */
469 }
470 else
471 {
472 *Next = 0;
473 }
474
475 InitializeObjectAttributes(
476 &ObjectAttributes,
477 &KeyName,
478 OBJ_CASE_INSENSITIVE,
479 NULL,
480 NULL);
481
482 DPRINT("Create '%S'\n", KeyName.Buffer);
483
484 Status = NtCreateKey(
485 &KeyHandle,
486 KEY_ALL_ACCESS,
487 &ObjectAttributes,
488 0,
489 NULL,
490 0,
491 NULL);
492 if (!NT_SUCCESS(Status))
493 {
494 DPRINT("NtCreateKey() failed with status %x\n", Status);
495 return Status;
496 }
497
498 NtClose(KeyHandle);
499
500 if (Next != NULL)
501 {
502 *Next = L'\\';
503 }
504
505 Current = Next + 1;
506 } while (Next != NULL);
507
508 return STATUS_SUCCESS;
509 }
510
511 /* EOF */