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)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
19 CmpInitializeHive(OUT PCMHIVE
*CmHive
,
20 IN ULONG OperationType
,
23 IN PVOID HiveData OPTIONAL
,
27 IN PCUNICODE_STRING FileName OPTIONAL
,
31 IO_STATUS_BLOCK IoStatusBlock
;
32 FILE_FS_SIZE_INFORMATION FileSizeInformation
;
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.
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
)))
53 /* Fail the request */
54 return STATUS_INVALID_PARAMETER
;
57 /* Check if this is a primary hive */
60 /* Get the cluster size */
61 Status
= ZwQueryVolumeInformationFile(Primary
,
64 sizeof(FILE_FS_SIZE_INFORMATION
),
65 FileFsSizeInformation
);
66 if (!NT_SUCCESS(Status
)) return Status
;
68 /* Make sure it's not larger then the block size */
69 if (FileSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
72 return STATUS_REGISTRY_IO_FAILED
;
75 /* Otherwise, calculate the cluster */
76 Cluster
= FileSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
;
77 Cluster
= max(1, Cluster
);
81 /* Otherwise use cluster 1 */
85 /* Allocate the hive */
86 Hive
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CMHIVE
), TAG_CMHIVE
);
87 if (!Hive
) return STATUS_INSUFFICIENT_RESOURCES
;
89 /* Setup null fields */
90 Hive
->UnloadEvent
= NULL
;
93 Hive
->UnloadWorkItem
= NULL
;
94 Hive
->GrowOnlyMode
= FALSE
;
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
;
103 /* Set loading flag */
104 Hive
->HiveIsLoading
= TRUE
;
106 /* Set the current thread as creator */
107 Hive
->CreatorOwner
= KeGetCurrentThread();
109 /* Initialize lists */
110 InitializeListHead(&Hive
->KcbConvertListHead
);
111 InitializeListHead(&Hive
->KnodeConvertListHead
);
112 InitializeListHead(&Hive
->TrustClassEntry
);
114 /* Allocate the view log */
115 Hive
->ViewLock
= ExAllocatePoolWithTag(NonPagedPool
,
116 sizeof(KGUARDED_MUTEX
),
120 /* Cleanup allocation and fail */
121 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
122 return STATUS_INSUFFICIENT_RESOURCES
;
125 /* Allocate the flush lock */
126 Hive
->FlusherLock
= ExAllocatePoolWithTag(NonPagedPool
,
129 if (!Hive
->FlusherLock
)
131 /* Cleanup allocations and fail */
132 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CMHIVE
);
133 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
134 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
142 /* Initailize the guarded mutex */
143 KeInitializeGuardedMutex(Hive
->ViewLock
);
144 Hive
->ViewLockOwner
= NULL
;
146 /* Initialize the flush lock */
147 ExInitializeResourceLite(Hive
->FlusherLock
);
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
;
157 /* Clear file names */
158 RtlInitEmptyUnicodeString(&Hive
->FileUserName
, NULL
, 0);
159 RtlInitEmptyUnicodeString(&Hive
->FileFullPath
, NULL
, 0);
161 /* Initialize the view list */
162 CmpInitHiveViewList(Hive
);
164 /* Initailize the security cache */
165 CmpInitSecurityCache(Hive
);
169 Hive
->FlushCount
= 0;
172 Status
= HvInitialize(&Hive
->Hive
,
185 if (!NT_SUCCESS(Status
))
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
);
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
))
201 /* Verify integrity */
202 ULONG CheckStatus
= CmCheckRegistry(Hive
, CheckFlags
);
203 if (CheckStatus
!= 0)
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
;
214 /* Lock the hive list */
215 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
217 /* Insert this hive */
218 InsertHeadList(&CmpHiveListHead
, &Hive
->HiveList
);
220 /* Release the lock */
221 ExReleasePushLock(&CmpHiveListHeadLock
);
223 /* Return the hive and success */
225 return STATUS_SUCCESS
;
230 CmpDestroyHive(IN PCMHIVE CmHive
)
232 /* Remove the hive from the list */
233 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
234 RemoveEntryList(&CmHive
->HiveList
);
235 ExReleasePushLock(&CmpHiveListHeadLock
);
237 /* Destroy the security descriptor cache */
238 CmpDestroySecurityCache(CmHive
);
240 /* Destroy the view list */
241 CmpDestroyHiveViewList(CmHive
);
243 /* Delete the flusher lock */
244 ExDeleteResourceLite(CmHive
->FlusherLock
);
245 ExFreePoolWithTag(CmHive
->FlusherLock
, TAG_CMHIVE
);
247 /* Delete the view lock */
248 ExFreePoolWithTag(CmHive
->ViewLock
, TAG_CMHIVE
);
250 /* Free the hive storage */
251 HvFree(&CmHive
->Hive
);
254 CmpFree(CmHive
, TAG_CM
);
256 return STATUS_SUCCESS
;
261 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName
,
262 IN PCWSTR Extension OPTIONAL
,
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
)
275 UNICODE_STRING FullName
, ExtensionName
;
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
;
286 Status
= CmpCreateEvent(NotificationEvent
, &EventHandle
, &Event
);
287 if (!NT_SUCCESS(Status
)) return Status
;
289 /* Initialize the full name */
290 RtlInitEmptyUnicodeString(&FullName
, NULL
, 0);
291 Length
= BaseName
->Length
;
293 /* Check if we have an extension */
296 /* Update the name length */
297 Length
+= (USHORT
)wcslen(Extension
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
299 /* Allocate the buffer for the full name */
300 NameBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
304 ObDereferenceObject(Event
);
305 ZwClose(EventHandle
);
306 return STATUS_NO_MEMORY
;
309 /* Build the full name */
310 FullName
.Buffer
= NameBuffer
;
311 FullName
.MaximumLength
= Length
;
312 RtlCopyUnicodeString(&FullName
, BaseName
);
316 /* The base name is the full name */
317 FullName
= *BaseName
;
321 /* Initialize the attributes */
322 InitializeObjectAttributes(&ObjectAttributes
,
324 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
328 /* Check if we can create the hive */
329 if ((CreateAllowed
) && !(CmpShareSystemHives
))
331 /* Open only or create */
332 CreateDisposition
= FILE_OPEN_IF
;
337 CreateDisposition
= FILE_OPEN
;
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
|
345 (NoBuffering
? FILE_NO_INTERMEDIATE_BUFFERING
: 0);
347 /* Set share and access modes */
348 if ((CmpMiniNTBoot
) && (CmpShareSystemHives
))
350 /* We're on Live CD or otherwise sharing */
351 DesiredAccess
= FILE_READ_DATA
;
352 ShareMode
= FILE_SHARE_READ
;
356 /* We want to write exclusively */
358 DesiredAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
361 /* Default attributes */
362 AttributeFlags
= FILE_ATTRIBUTE_NORMAL
;
364 /* Now create the file */
365 Status
= ZwCreateFile(Primary
,
366 DesiredAccess
| SYNCHRONIZE
,
373 FILE_SYNCHRONOUS_IO_NONALERT
| IoFlags
,
376 /* Check if anything failed until now */
377 if (!NT_SUCCESS(Status
))
379 DPRINT1("ZwCreateFile(%wZ) failed, Status 0x%08lx.\n", ObjectAttributes
.ObjectName
, Status
);
381 /* Close handles and free buffers */
382 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
383 ObDereferenceObject(Event
);
384 ZwClose(EventHandle
);
389 if (MarkAsSystemHive
)
391 /* We opened it, mark it as a system hive */
392 Status
= ZwFsControlFile(*Primary
,
397 FSCTL_MARK_AS_SYSTEM_HIVE
,
402 if (Status
== STATUS_PENDING
)
404 /* Wait for completion */
405 KeWaitForSingleObject(Event
,
410 Status
= IoStatusBlock
.Status
;
413 /* If we don't support it, ignore the failure */
414 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
416 if (!NT_SUCCESS(Status
))
418 /* Close handles and free buffers */
419 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
420 ObDereferenceObject(Event
);
421 ZwClose(EventHandle
);
428 /* Disable compression */
429 CompressionState
= 0;
430 Status
= ZwFsControlFile(*Primary
,
435 FSCTL_SET_COMPRESSION
,
437 sizeof(CompressionState
),
440 if (Status
== STATUS_PENDING
)
442 /* Wait for completion */
443 KeWaitForSingleObject(Event
,
450 /* Get the disposition */
451 *PrimaryDisposition
= (ULONG
)IoStatusBlock
.Information
;
452 if (IoStatusBlock
.Information
!= FILE_CREATED
)
454 /* Check how large the file is */
455 Status
= ZwQueryInformationFile(*Primary
,
458 sizeof(FileInformation
),
459 FileStandardInformation
);
460 if (NT_SUCCESS(Status
))
462 /* Check if it's 0 bytes */
463 if (!FileInformation
.EndOfFile
.QuadPart
)
465 /* Assume it's a new file */
466 *PrimaryDisposition
= FILE_CREATED
;
471 /* Check if the caller wants cluster size returned */
475 Status
= ZwQueryVolumeInformationFile(*Primary
,
478 sizeof(FsSizeInformation
),
479 FileFsSizeInformation
);
480 if (!NT_SUCCESS(Status
))
482 /* Close handles and free buffers */
483 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
484 ObDereferenceObject(Event
);
485 ZwClose(EventHandle
);
489 /* Check if the sector size is invalid */
490 if (FsSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
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
;
499 /* Return cluster size */
500 *ClusterSize
= max(1, FsSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
);
503 /* Check if we don't need to create a log file */
506 /* We're done, close handles */
507 ObDereferenceObject(Event
);
508 ZwClose(EventHandle
);
509 return STATUS_SUCCESS
;
512 /* Check if we can create the hive */
513 CreateDisposition
= CmpShareSystemHives
? FILE_OPEN
: FILE_OPEN_IF
;
514 if (*PrimaryDisposition
== FILE_CREATED
)
516 /* Over-write the existing log file, since this is a new hive */
517 CreateDisposition
= FILE_SUPERSEDE
;
521 RtlInitUnicodeString(&ExtensionName
, Extension
);
522 RtlAppendUnicodeStringToString(&FullName
, &ExtensionName
);
524 /* Initialize the attributes */
525 InitializeObjectAttributes(&ObjectAttributes
,
527 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
531 /* Setup the flags */
532 IoFlags
= FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
;
534 /* Check if this is a log file */
535 if (!_wcsnicmp(Extension
, L
".log", 4))
538 AttributeFlags
|= FILE_ATTRIBUTE_HIDDEN
;
541 /* Now create the file */
542 Status
= ZwCreateFile(Log
,
553 if ((NT_SUCCESS(Status
)) && (MarkAsSystemHive
))
555 /* We opened it, mark it as a system hive */
556 Status
= ZwFsControlFile(*Log
,
561 FSCTL_MARK_AS_SYSTEM_HIVE
,
566 if (Status
== STATUS_PENDING
)
568 /* Wait for completion */
569 KeWaitForSingleObject(Event
,
574 Status
= IoStatusBlock
.Status
;
577 /* If we don't support it, ignore the failure */
578 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
580 /* If we failed, close the handle */
581 if (!NT_SUCCESS(Status
)) ZwClose(*Log
);
584 /* Check if anything failed until now */
585 if (!NT_SUCCESS(Status
))
587 /* Clear the handle */
592 /* Disable compression */
593 Status
= ZwFsControlFile(*Log
,
598 FSCTL_SET_COMPRESSION
,
600 sizeof(CompressionState
),
603 if (Status
== STATUS_PENDING
)
605 /* Wait for completion */
606 KeWaitForSingleObject(Event
,
613 /* Return the disposition */
614 *LogDisposition
= (ULONG
)IoStatusBlock
.Information
;
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
;
626 CmpCloseHiveFiles(IN PCMHIVE Hive
)
630 for (i
= 0; i
< HFILE_TYPE_MAX
; i
++)
632 if (Hive
->FileHandles
[i
] != NULL
)
634 ZwClose(Hive
->FileHandles
[i
]);
635 Hive
->FileHandles
[i
] = NULL
;