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