[WLAN-BRINGUP]
[reactos.git] / ntoskrnl / config / cminit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cminit.c
5 * PURPOSE: Configuration Manager - Hive Initialization
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* FUNCTIONS *****************************************************************/
16
17 NTSTATUS
18 NTAPI
19 CmpInitializeHive(OUT PCMHIVE *RegistryHive,
20 IN ULONG OperationType,
21 IN ULONG HiveFlags,
22 IN ULONG FileType,
23 IN PVOID HiveData OPTIONAL,
24 IN HANDLE Primary,
25 IN HANDLE Log,
26 IN HANDLE External,
27 IN PCUNICODE_STRING FileName OPTIONAL,
28 IN ULONG CheckFlags)
29 {
30 PCMHIVE Hive;
31 FILE_STANDARD_INFORMATION FileInformation;
32 IO_STATUS_BLOCK IoStatusBlock;
33 FILE_FS_SIZE_INFORMATION FileSizeInformation;
34 NTSTATUS Status;
35 ULONG Cluster;
36
37 /* Assume failure */
38 *RegistryHive = NULL;
39
40 /*
41 * The following are invalid:
42 * An external hive that is also internal.
43 * A log hive that's not a primary hive too.
44 * A volatile hive that's linked to permanent storage.
45 * An in-memory initialization without hive data.
46 * A log hive that's not linked to a correct file type.
47 */
48 if (((External) && ((Primary) || (Log))) ||
49 ((Log) && !(Primary)) ||
50 ((HiveFlags & HIVE_VOLATILE) && ((Primary) || (External) || (Log))) ||
51 ((OperationType == HINIT_MEMORY) && (!HiveData)) ||
52 ((Log) && (FileType != HFILE_TYPE_LOG)))
53 {
54 /* Fail the request */
55 return STATUS_INVALID_PARAMETER;
56 }
57
58 /* Check if this is a primary hive */
59 if (Primary)
60 {
61 /* Get the cluster size */
62 Status = ZwQueryVolumeInformationFile(Primary,
63 &IoStatusBlock,
64 &FileSizeInformation,
65 sizeof(FILE_FS_SIZE_INFORMATION),
66 FileFsSizeInformation);
67 if (!NT_SUCCESS(Status)) return Status;
68
69 /* Make sure it's not larger then the block size */
70 if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE)
71 {
72 /* Fail */
73 return STATUS_REGISTRY_IO_FAILED;
74 }
75
76 /* Otherwise, calculate the cluster */
77 Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE;
78 Cluster = max(1, Cluster);
79 }
80 else
81 {
82 /* Otherwise use cluster 1 */
83 Cluster = 1;
84 }
85
86 /* Allocate the hive */
87 Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CM);
88 if (!Hive) return STATUS_INSUFFICIENT_RESOURCES;
89
90 /* Setup null fields */
91 Hive->UnloadEvent = NULL;
92 Hive->RootKcb = NULL;
93 Hive->Frozen = FALSE;
94 Hive->UnloadWorkItem = NULL;
95 Hive->GrowOnlyMode = FALSE;
96 Hive->GrowOffset = 0;
97 Hive->CellRemapArray = NULL;
98 Hive->UseCountLog.Next = 0;
99 Hive->LockHiveLog.Next = 0;
100 Hive->FileObject = NULL;
101 Hive->NotifyList.Flink = NULL;
102 Hive->NotifyList.Blink = NULL;
103
104 /* Set loading flag */
105 Hive->HiveIsLoading = TRUE;
106
107 /* Set the current thread as creator */
108 Hive->CreatorOwner = KeGetCurrentThread();
109
110 /* Initialize lists */
111 InitializeListHead(&Hive->KcbConvertListHead);
112 InitializeListHead(&Hive->KnodeConvertListHead);
113 InitializeListHead(&Hive->TrustClassEntry);
114
115 /* Allocate the view log */
116 Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool,
117 sizeof(KGUARDED_MUTEX),
118 TAG_CM);
119 if (!Hive->ViewLock) return STATUS_INSUFFICIENT_RESOURCES;
120
121 /* Allocate the flush lock */
122 Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool,
123 sizeof(ERESOURCE),
124 TAG_CM);
125 if (!Hive->FlusherLock) return STATUS_INSUFFICIENT_RESOURCES;
126
127 /* Setup the handles */
128 Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary;
129 Hive->FileHandles[HFILE_TYPE_LOG] = Log;
130 Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External;
131
132 /* Initailize the guarded mutex */
133 KeInitializeGuardedMutex(Hive->ViewLock);
134 Hive->ViewLockOwner = NULL;
135
136 /* Initialize the flush lock */
137 ExInitializeResourceLite(Hive->FlusherLock);
138
139 /* Setup hive locks */
140 ExInitializePushLock(&Hive->HiveLock);
141 Hive->HiveLockOwner = NULL;
142 ExInitializePushLock(&Hive->WriterLock);
143 Hive->WriterLockOwner = NULL;
144 ExInitializePushLock(&Hive->SecurityLock);
145 Hive->HiveSecurityLockOwner = NULL;
146
147 /* Clear file names */
148 RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0);
149 RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0);
150
151 /* Initialize the view list */
152 CmpInitHiveViewList(Hive);
153
154 /* Initailize the security cache */
155 CmpInitSecurityCache(Hive);
156
157 /* Setup flags */
158 Hive->Flags = 0;
159 Hive->FlushCount = 0;
160
161 /* Set flags */
162 Hive->Flags = HiveFlags;
163
164 /* Check if this is a primary */
165 if (Primary)
166 {
167 /* Check how large the file is */
168 ZwQueryInformationFile(Primary,
169 &IoStatusBlock,
170 &FileInformation,
171 sizeof(FileInformation),
172 FileStandardInformation);
173 Cluster = FileInformation.EndOfFile.LowPart;
174 }
175
176 /* Initialize it */
177 Status = HvInitialize(&Hive->Hive,
178 OperationType,
179 FileType,
180 HiveFlags,
181 HiveData,
182 CmpAllocate,
183 CmpFree,
184 CmpFileSetSize,
185 CmpFileWrite,
186 CmpFileRead,
187 CmpFileFlush,
188 Cluster,
189 (PUNICODE_STRING)FileName);
190 if (!NT_SUCCESS(Status))
191 {
192 /* Clear allocations and fail */
193 ExFreePool(Hive->ViewLock);
194 ExFreePool(Hive->FlusherLock);
195 ExFreePool(Hive);
196 return Status;
197 }
198
199 /* Check if we should verify the registry */
200 if ((OperationType == HINIT_FILE) ||
201 (OperationType == HINIT_MEMORY) ||
202 (OperationType == HINIT_MEMORY_INPLACE) ||
203 (OperationType == HINIT_MAPFILE))
204 {
205 /* Verify integrity */
206 if (CmCheckRegistry((PCMHIVE)Hive, TRUE))
207 {
208 /* Free all alocations */
209 ExFreePool(Hive->ViewLock);
210 ExFreePool(Hive->FlusherLock);
211 ExFreePool(Hive);
212 return STATUS_REGISTRY_CORRUPT;
213 }
214 }
215
216 /* Lock the hive list */
217 ExAcquirePushLockExclusive(&CmpHiveListHeadLock);
218
219 /* Insert this hive */
220 InsertHeadList(&CmpHiveListHead, &Hive->HiveList);
221
222 /* Release the lock */
223 ExReleasePushLock(&CmpHiveListHeadLock);
224
225 /* Return the hive and success */
226 *RegistryHive = (PCMHIVE)Hive;
227 return STATUS_SUCCESS;
228 }
229
230 NTSTATUS
231 NTAPI
232 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,
233 IN PCWSTR Extension OPTIONAL,
234 IN PHANDLE Primary,
235 IN PHANDLE Log,
236 IN PULONG PrimaryDisposition,
237 IN PULONG LogDisposition,
238 IN BOOLEAN CreateAllowed,
239 IN BOOLEAN MarkAsSystemHive,
240 IN BOOLEAN NoBuffering,
241 OUT PULONG ClusterSize OPTIONAL)
242 {
243 HANDLE EventHandle;
244 PKEVENT Event;
245 NTSTATUS Status;
246 UNICODE_STRING FullName, ExtensionName;
247 PWCHAR NameBuffer;
248 USHORT Length;
249 OBJECT_ATTRIBUTES ObjectAttributes;
250 IO_STATUS_BLOCK IoStatusBlock;
251 ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags;
252 USHORT CompressionState;
253 FILE_STANDARD_INFORMATION FileInformation;
254 FILE_FS_SIZE_INFORMATION FsSizeInformation;
255
256 /* Create event */
257 Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event);
258 if (!NT_SUCCESS(Status)) return Status;
259
260 /* Initialize the full name */
261 RtlInitEmptyUnicodeString(&FullName, NULL, 0);
262 Length = BaseName->Length;
263
264 /* Check if we have an extension */
265 if (Extension)
266 {
267 /* Update the name length */
268 Length += (USHORT)wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
269
270 /* Allocate the buffer for the full name */
271 NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
272 if (!NameBuffer)
273 {
274 /* Fail */
275 ObDereferenceObject(Event);
276 ZwClose(EventHandle);
277 return STATUS_NO_MEMORY;
278 }
279
280 /* Build the full name */
281 FullName.Buffer = NameBuffer;
282 FullName.MaximumLength = Length;
283 RtlAppendUnicodeStringToString(&FullName, BaseName);
284 }
285 else
286 {
287 /* The base name is the full name */
288 FullName = *BaseName;
289 NameBuffer = NULL;
290 }
291
292 /* Initialize the attributes */
293 InitializeObjectAttributes(&ObjectAttributes,
294 &FullName,
295 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
296 NULL,
297 NULL);
298
299 /* Check if we can create the hive */
300 if ((CreateAllowed) && !(CmpShareSystemHives))
301 {
302 /* Open only or create */
303 CreateDisposition = FILE_OPEN_IF;
304 }
305 else
306 {
307 /* Open only */
308 CreateDisposition = FILE_OPEN;
309 }
310
311 /* Setup the flags */
312 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot
313 IoFlags = //FILE_OPEN_FOR_BACKUP_INTENT |
314 FILE_NO_COMPRESSION |
315 FILE_RANDOM_ACCESS |
316 (NoBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0);
317
318 /* Set share and access modes */
319 if ((CmpMiniNTBoot) && (CmpShareSystemHives))
320 {
321 /* We're on Live CD or otherwise sharing */
322 DesiredAccess = FILE_READ_DATA;
323 ShareMode = FILE_SHARE_READ;
324 }
325 else
326 {
327 /* We want to write exclusively */
328 ShareMode = 0;
329 DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA;
330 }
331
332 /* Default attributes */
333 AttributeFlags = FILE_ATTRIBUTE_NORMAL;
334
335 /* Now create the file */
336 Status = ZwCreateFile(Primary,
337 DesiredAccess,
338 &ObjectAttributes,
339 &IoStatusBlock,
340 NULL,
341 AttributeFlags,
342 ShareMode,
343 CreateDisposition,
344 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags,
345 NULL,
346 0);
347 /* Check if anything failed until now */
348 if (!NT_SUCCESS(Status))
349 {
350 /* Close handles and free buffers */
351 if (NameBuffer) ExFreePool(NameBuffer);
352 ObDereferenceObject(Event);
353 ZwClose(EventHandle);
354 DPRINT1("ZwCreateFile failed : %lx.\n", Status);
355 *Primary = NULL;
356 return Status;
357 }
358
359 if (MarkAsSystemHive)
360 {
361 /* We opened it, mark it as a system hive */
362 Status = ZwFsControlFile(*Primary,
363 EventHandle,
364 NULL,
365 NULL,
366 &IoStatusBlock,
367 FSCTL_MARK_AS_SYSTEM_HIVE,
368 NULL,
369 0,
370 NULL,
371 0);
372 if (Status == STATUS_PENDING)
373 {
374 /* Wait for completion */
375 KeWaitForSingleObject(Event,
376 Executive,
377 KernelMode,
378 FALSE,
379 NULL);
380 Status = IoStatusBlock.Status;
381 }
382
383 /* If we don't support it, ignore the failure */
384 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
385
386 if (!NT_SUCCESS(Status))
387 {
388 /* Close handles and free buffers */
389 if (NameBuffer) ExFreePool(NameBuffer);
390 ObDereferenceObject(Event);
391 ZwClose(EventHandle);
392 ZwClose(*Primary);
393 *Primary = NULL;
394 return Status;
395 }
396 }
397
398 /* Disable compression */
399 CompressionState = 0;
400 Status = ZwFsControlFile(*Primary,
401 EventHandle,
402 NULL,
403 NULL,
404 &IoStatusBlock,
405 FSCTL_SET_COMPRESSION,
406 &CompressionState,
407 sizeof(CompressionState),
408 NULL,
409 0);
410 if (Status == STATUS_PENDING)
411 {
412 /* Wait for completion */
413 KeWaitForSingleObject(Event,
414 Executive,
415 KernelMode,
416 FALSE,
417 NULL);
418 }
419
420 /* Get the disposition */
421 *PrimaryDisposition = (ULONG)IoStatusBlock.Information;
422 if (IoStatusBlock.Information != FILE_CREATED)
423 {
424 /* Check how large the file is */
425 Status = ZwQueryInformationFile(*Primary,
426 &IoStatusBlock,
427 &FileInformation,
428 sizeof(FileInformation),
429 FileStandardInformation);
430 if (NT_SUCCESS(Status))
431 {
432 /* Check if it's 0 bytes */
433 if (!FileInformation.EndOfFile.QuadPart)
434 {
435 /* Assume it's a new file */
436 *PrimaryDisposition = FILE_CREATED;
437 }
438 }
439 }
440
441 /* Check if the caller wants cluster size returned */
442 if (ClusterSize)
443 {
444 /* Query it */
445 Status = ZwQueryVolumeInformationFile(*Primary,
446 &IoStatusBlock,
447 &FsSizeInformation,
448 sizeof(FsSizeInformation),
449 FileFsSizeInformation);
450 if (!NT_SUCCESS(Status))
451 {
452 /* Close handles and free buffers */
453 if (NameBuffer) ExFreePool(NameBuffer);
454 ObDereferenceObject(Event);
455 ZwClose(EventHandle);
456 return Status;
457 }
458
459 /* Check if the sector size is invalid */
460 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE)
461 {
462 /* Close handles and free buffers */
463 if (NameBuffer) ExFreePool(NameBuffer);
464 ObDereferenceObject(Event);
465 ZwClose(EventHandle);
466 return STATUS_CANNOT_LOAD_REGISTRY_FILE;
467 }
468
469 /* Return cluster size */
470 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE);
471 }
472
473 /* Check if we don't need to create a log file */
474 if (!Extension)
475 {
476 /* We're done, close handles */
477 ObDereferenceObject(Event);
478 ZwClose(EventHandle);
479 return STATUS_SUCCESS;
480 }
481
482 /* Check if we can create the hive */
483 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
484 if (*PrimaryDisposition == FILE_CREATED)
485 {
486 /* Over-write the existing log file, since this is a new hive */
487 CreateDisposition = FILE_SUPERSEDE;
488 }
489
490 /* Setup the name */
491 RtlInitUnicodeString(&ExtensionName, Extension);
492 RtlAppendUnicodeStringToString(&FullName, &ExtensionName);
493
494 /* Initialize the attributes */
495 InitializeObjectAttributes(&ObjectAttributes,
496 &FullName,
497 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
498 NULL,
499 NULL);
500
501 /* Setup the flags */
502 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
503
504 /* Check if this is a log file */
505 if (!_wcsnicmp(Extension, L".log", 4))
506 {
507 /* Hide log files */
508 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN;
509 }
510
511 /* Now create the file */
512 Status = ZwCreateFile(Log,
513 DesiredAccess,
514 &ObjectAttributes,
515 &IoStatusBlock,
516 NULL,
517 AttributeFlags,
518 ShareMode,
519 CreateDisposition,
520 IoFlags,
521 NULL,
522 0);
523 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
524 {
525 /* We opened it, mark it as a system hive */
526 Status = ZwFsControlFile(*Log,
527 EventHandle,
528 NULL,
529 NULL,
530 &IoStatusBlock,
531 FSCTL_MARK_AS_SYSTEM_HIVE,
532 NULL,
533 0,
534 NULL,
535 0);
536 if (Status == STATUS_PENDING)
537 {
538 /* Wait for completion */
539 KeWaitForSingleObject(Event,
540 Executive,
541 KernelMode,
542 FALSE,
543 NULL);
544 Status = IoStatusBlock.Status;
545 }
546
547 /* If we don't support it, ignore the failure */
548 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
549
550 /* If we failed, close the handle */
551 if (!NT_SUCCESS(Status)) ZwClose(*Log);
552 }
553
554 /* Check if anything failed until now */
555 if (!NT_SUCCESS(Status))
556 {
557 /* Clear the handle */
558 *Log = NULL;
559 }
560 else
561 {
562 /* Disable compression */
563 Status = ZwFsControlFile(*Log,
564 EventHandle,
565 NULL,
566 NULL,
567 &IoStatusBlock,
568 FSCTL_SET_COMPRESSION,
569 &CompressionState,
570 sizeof(CompressionState),
571 NULL,
572 0);
573 if (Status == STATUS_PENDING)
574 {
575 /* Wait for completion */
576 KeWaitForSingleObject(Event,
577 Executive,
578 KernelMode,
579 FALSE,
580 NULL);
581 }
582
583 /* Return the disposition */
584 *LogDisposition = (ULONG)IoStatusBlock.Information;
585 }
586
587 /* We're done, close handles and free buffers */
588 if (NameBuffer) ExFreePool(NameBuffer);
589 ObDereferenceObject(Event);
590 ZwClose(EventHandle);
591 return STATUS_SUCCESS;
592 }