[NTOS]: Reorder the destruction code in CmpDestroyHive() to make it similar to the...
[reactos.git] / reactos / 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 RtlAppendUnicodeStringToString(&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 /* Close handles and free buffers */
380 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
381 ObDereferenceObject(Event);
382 ZwClose(EventHandle);
383 DPRINT1("ZwCreateFile failed : %lx.\n", Status);
384 *Primary = NULL;
385 return Status;
386 }
387
388 if (MarkAsSystemHive)
389 {
390 /* We opened it, mark it as a system hive */
391 Status = ZwFsControlFile(*Primary,
392 EventHandle,
393 NULL,
394 NULL,
395 &IoStatusBlock,
396 FSCTL_MARK_AS_SYSTEM_HIVE,
397 NULL,
398 0,
399 NULL,
400 0);
401 if (Status == STATUS_PENDING)
402 {
403 /* Wait for completion */
404 KeWaitForSingleObject(Event,
405 Executive,
406 KernelMode,
407 FALSE,
408 NULL);
409 Status = IoStatusBlock.Status;
410 }
411
412 /* If we don't support it, ignore the failure */
413 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
414
415 if (!NT_SUCCESS(Status))
416 {
417 /* Close handles and free buffers */
418 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
419 ObDereferenceObject(Event);
420 ZwClose(EventHandle);
421 ZwClose(*Primary);
422 *Primary = NULL;
423 return Status;
424 }
425 }
426
427 /* Disable compression */
428 CompressionState = 0;
429 Status = ZwFsControlFile(*Primary,
430 EventHandle,
431 NULL,
432 NULL,
433 &IoStatusBlock,
434 FSCTL_SET_COMPRESSION,
435 &CompressionState,
436 sizeof(CompressionState),
437 NULL,
438 0);
439 if (Status == STATUS_PENDING)
440 {
441 /* Wait for completion */
442 KeWaitForSingleObject(Event,
443 Executive,
444 KernelMode,
445 FALSE,
446 NULL);
447 }
448
449 /* Get the disposition */
450 *PrimaryDisposition = (ULONG)IoStatusBlock.Information;
451 if (IoStatusBlock.Information != FILE_CREATED)
452 {
453 /* Check how large the file is */
454 Status = ZwQueryInformationFile(*Primary,
455 &IoStatusBlock,
456 &FileInformation,
457 sizeof(FileInformation),
458 FileStandardInformation);
459 if (NT_SUCCESS(Status))
460 {
461 /* Check if it's 0 bytes */
462 if (!FileInformation.EndOfFile.QuadPart)
463 {
464 /* Assume it's a new file */
465 *PrimaryDisposition = FILE_CREATED;
466 }
467 }
468 }
469
470 /* Check if the caller wants cluster size returned */
471 if (ClusterSize)
472 {
473 /* Query it */
474 Status = ZwQueryVolumeInformationFile(*Primary,
475 &IoStatusBlock,
476 &FsSizeInformation,
477 sizeof(FsSizeInformation),
478 FileFsSizeInformation);
479 if (!NT_SUCCESS(Status))
480 {
481 /* Close handles and free buffers */
482 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
483 ObDereferenceObject(Event);
484 ZwClose(EventHandle);
485 return Status;
486 }
487
488 /* Check if the sector size is invalid */
489 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE)
490 {
491 /* Close handles and free buffers */
492 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
493 ObDereferenceObject(Event);
494 ZwClose(EventHandle);
495 return STATUS_CANNOT_LOAD_REGISTRY_FILE;
496 }
497
498 /* Return cluster size */
499 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE);
500 }
501
502 /* Check if we don't need to create a log file */
503 if (!Extension)
504 {
505 /* We're done, close handles */
506 ObDereferenceObject(Event);
507 ZwClose(EventHandle);
508 return STATUS_SUCCESS;
509 }
510
511 /* Check if we can create the hive */
512 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
513 if (*PrimaryDisposition == FILE_CREATED)
514 {
515 /* Over-write the existing log file, since this is a new hive */
516 CreateDisposition = FILE_SUPERSEDE;
517 }
518
519 /* Setup the name */
520 RtlInitUnicodeString(&ExtensionName, Extension);
521 RtlAppendUnicodeStringToString(&FullName, &ExtensionName);
522
523 /* Initialize the attributes */
524 InitializeObjectAttributes(&ObjectAttributes,
525 &FullName,
526 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
527 NULL,
528 NULL);
529
530 /* Setup the flags */
531 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
532
533 /* Check if this is a log file */
534 if (!_wcsnicmp(Extension, L".log", 4))
535 {
536 /* Hide log files */
537 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN;
538 }
539
540 /* Now create the file */
541 Status = ZwCreateFile(Log,
542 DesiredAccess,
543 &ObjectAttributes,
544 &IoStatusBlock,
545 NULL,
546 AttributeFlags,
547 ShareMode,
548 CreateDisposition,
549 IoFlags,
550 NULL,
551 0);
552 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
553 {
554 /* We opened it, mark it as a system hive */
555 Status = ZwFsControlFile(*Log,
556 EventHandle,
557 NULL,
558 NULL,
559 &IoStatusBlock,
560 FSCTL_MARK_AS_SYSTEM_HIVE,
561 NULL,
562 0,
563 NULL,
564 0);
565 if (Status == STATUS_PENDING)
566 {
567 /* Wait for completion */
568 KeWaitForSingleObject(Event,
569 Executive,
570 KernelMode,
571 FALSE,
572 NULL);
573 Status = IoStatusBlock.Status;
574 }
575
576 /* If we don't support it, ignore the failure */
577 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
578
579 /* If we failed, close the handle */
580 if (!NT_SUCCESS(Status)) ZwClose(*Log);
581 }
582
583 /* Check if anything failed until now */
584 if (!NT_SUCCESS(Status))
585 {
586 /* Clear the handle */
587 *Log = NULL;
588 }
589 else
590 {
591 /* Disable compression */
592 Status = ZwFsControlFile(*Log,
593 EventHandle,
594 NULL,
595 NULL,
596 &IoStatusBlock,
597 FSCTL_SET_COMPRESSION,
598 &CompressionState,
599 sizeof(CompressionState),
600 NULL,
601 0);
602 if (Status == STATUS_PENDING)
603 {
604 /* Wait for completion */
605 KeWaitForSingleObject(Event,
606 Executive,
607 KernelMode,
608 FALSE,
609 NULL);
610 }
611
612 /* Return the disposition */
613 *LogDisposition = (ULONG)IoStatusBlock.Information;
614 }
615
616 /* We're done, close handles and free buffers */
617 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
618 ObDereferenceObject(Event);
619 ZwClose(EventHandle);
620 return STATUS_SUCCESS;
621 }
622
623 VOID
624 NTAPI
625 CmpCloseHiveFiles(IN PCMHIVE Hive)
626 {
627 ULONG i;
628
629 for (i = 0; i < HFILE_TYPE_MAX; i++)
630 {
631 if (Hive->FileHandles[i] != NULL)
632 {
633 ZwClose(Hive->FileHandles[i]);
634 Hive->FileHandles[i] = NULL;
635 }
636 }
637 }