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 is not a primary hive too.
43 * - A volatile hive that is linked to permanent storage,
44 * unless this hive is a shared system hive.
45 * - An in-memory initialization without hive data.
46 * - A log hive that is not linked to a correct file type.
48 if (((External
) && ((Primary
) || (Log
))) ||
49 ((Log
) && !(Primary
)) ||
50 (!(CmpShareSystemHives
) && (HiveFlags
& HIVE_VOLATILE
) &&
51 ((Primary
) || (External
) || (Log
))) ||
52 ((OperationType
== HINIT_MEMORY
) && (!HiveData
)) ||
53 ((Log
) && (FileType
!= HFILE_TYPE_LOG
)))
55 /* Fail the request */
56 return STATUS_INVALID_PARAMETER
;
59 /* Check if this is a primary hive */
62 /* Get the cluster size */
63 Status
= ZwQueryVolumeInformationFile(Primary
,
66 sizeof(FILE_FS_SIZE_INFORMATION
),
67 FileFsSizeInformation
);
68 if (!NT_SUCCESS(Status
)) return Status
;
70 /* Make sure it's not larger then the block size */
71 if (FileSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
74 return STATUS_REGISTRY_IO_FAILED
;
77 /* Otherwise, calculate the cluster */
78 Cluster
= FileSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
;
79 Cluster
= max(1, Cluster
);
83 /* Otherwise use cluster 1 */
87 /* Allocate the hive */
88 Hive
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CMHIVE
), TAG_CMHIVE
);
89 if (!Hive
) return STATUS_INSUFFICIENT_RESOURCES
;
91 /* Setup null fields */
92 Hive
->UnloadEvent
= NULL
;
95 Hive
->UnloadWorkItem
= NULL
;
96 Hive
->GrowOnlyMode
= FALSE
;
98 Hive
->CellRemapArray
= NULL
;
99 Hive
->UseCountLog
.Next
= 0;
100 Hive
->LockHiveLog
.Next
= 0;
101 Hive
->FileObject
= NULL
;
102 Hive
->NotifyList
.Flink
= NULL
;
103 Hive
->NotifyList
.Blink
= NULL
;
105 /* Set loading flag */
106 Hive
->HiveIsLoading
= TRUE
;
108 /* Set the current thread as creator */
109 Hive
->CreatorOwner
= KeGetCurrentThread();
111 /* Initialize lists */
112 InitializeListHead(&Hive
->KcbConvertListHead
);
113 InitializeListHead(&Hive
->KnodeConvertListHead
);
114 InitializeListHead(&Hive
->TrustClassEntry
);
116 /* Allocate the view log */
117 Hive
->ViewLock
= ExAllocatePoolWithTag(NonPagedPool
,
118 sizeof(KGUARDED_MUTEX
),
122 /* Cleanup allocation and fail */
123 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
124 return STATUS_INSUFFICIENT_RESOURCES
;
127 /* Allocate the flush lock */
128 Hive
->FlusherLock
= ExAllocatePoolWithTag(NonPagedPool
,
131 if (!Hive
->FlusherLock
)
133 /* Cleanup allocations and fail */
134 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CMHIVE
);
135 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
136 return STATUS_INSUFFICIENT_RESOURCES
;
139 /* Setup the handles */
140 Hive
->FileHandles
[HFILE_TYPE_PRIMARY
] = Primary
;
141 Hive
->FileHandles
[HFILE_TYPE_LOG
] = Log
;
142 Hive
->FileHandles
[HFILE_TYPE_EXTERNAL
] = External
;
144 /* Initailize the guarded mutex */
145 KeInitializeGuardedMutex(Hive
->ViewLock
);
146 Hive
->ViewLockOwner
= NULL
;
148 /* Initialize the flush lock */
149 ExInitializeResourceLite(Hive
->FlusherLock
);
151 /* Setup hive locks */
152 ExInitializePushLock(&Hive
->HiveLock
);
153 Hive
->HiveLockOwner
= NULL
;
154 ExInitializePushLock(&Hive
->WriterLock
);
155 Hive
->WriterLockOwner
= NULL
;
156 ExInitializePushLock(&Hive
->SecurityLock
);
157 Hive
->HiveSecurityLockOwner
= NULL
;
159 /* Clear file names */
160 RtlInitEmptyUnicodeString(&Hive
->FileUserName
, NULL
, 0);
161 RtlInitEmptyUnicodeString(&Hive
->FileFullPath
, NULL
, 0);
163 /* Initialize the view list */
164 CmpInitHiveViewList(Hive
);
166 /* Initailize the security cache */
167 CmpInitSecurityCache(Hive
);
171 Hive
->FlushCount
= 0;
174 Status
= HvInitialize(&Hive
->Hive
,
187 if (!NT_SUCCESS(Status
))
189 /* Cleanup allocations and fail */
190 ExDeleteResourceLite(Hive
->FlusherLock
);
191 ExFreePoolWithTag(Hive
->FlusherLock
, TAG_CMHIVE
);
192 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CMHIVE
);
193 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
197 /* Check if we should verify the registry */
198 if ((OperationType
== HINIT_FILE
) ||
199 (OperationType
== HINIT_MEMORY
) ||
200 (OperationType
== HINIT_MEMORY_INPLACE
) ||
201 (OperationType
== HINIT_MAPFILE
))
203 /* Verify integrity */
204 ULONG CheckStatus
= CmCheckRegistry(Hive
, CheckFlags
);
205 if (CheckStatus
!= 0)
207 /* Cleanup allocations and fail */
208 ExDeleteResourceLite(Hive
->FlusherLock
);
209 ExFreePoolWithTag(Hive
->FlusherLock
, TAG_CMHIVE
);
210 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CMHIVE
);
211 ExFreePoolWithTag(Hive
, TAG_CMHIVE
);
212 return STATUS_REGISTRY_CORRUPT
;
216 /* Lock the hive list */
217 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
219 /* Insert this hive */
220 InsertHeadList(&CmpHiveListHead
, &Hive
->HiveList
);
222 /* Release the lock */
223 ExReleasePushLock(&CmpHiveListHeadLock
);
225 /* Return the hive and success */
227 return STATUS_SUCCESS
;
232 CmpDestroyHive(IN PCMHIVE CmHive
)
234 /* Remove the hive from the list */
235 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
236 RemoveEntryList(&CmHive
->HiveList
);
237 ExReleasePushLock(&CmpHiveListHeadLock
);
239 /* Destroy the security descriptor cache */
240 CmpDestroySecurityCache(CmHive
);
242 /* Destroy the view list */
243 CmpDestroyHiveViewList(CmHive
);
245 /* Delete the flusher lock */
246 ExDeleteResourceLite(CmHive
->FlusherLock
);
247 ExFreePoolWithTag(CmHive
->FlusherLock
, TAG_CMHIVE
);
249 /* Delete the view lock */
250 ExFreePoolWithTag(CmHive
->ViewLock
, TAG_CMHIVE
);
252 /* Free the hive storage */
253 HvFree(&CmHive
->Hive
);
256 CmpFree(CmHive
, TAG_CM
);
258 return STATUS_SUCCESS
;
263 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName
,
264 IN PCWSTR Extension OPTIONAL
,
267 OUT PULONG PrimaryDisposition
,
268 OUT PULONG LogDisposition
,
269 IN BOOLEAN CreateAllowed
,
270 IN BOOLEAN MarkAsSystemHive
,
271 IN BOOLEAN NoBuffering
,
272 OUT PULONG ClusterSize OPTIONAL
)
277 UNICODE_STRING FullName
, ExtensionName
;
280 OBJECT_ATTRIBUTES ObjectAttributes
;
281 IO_STATUS_BLOCK IoStatusBlock
;
282 ULONG AttributeFlags
, ShareMode
, DesiredAccess
, CreateDisposition
, IoFlags
;
283 USHORT CompressionState
;
284 FILE_STANDARD_INFORMATION FileInformation
;
285 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
288 Status
= CmpCreateEvent(NotificationEvent
, &EventHandle
, &Event
);
289 if (!NT_SUCCESS(Status
)) return Status
;
291 /* Initialize the full name */
292 RtlInitEmptyUnicodeString(&FullName
, NULL
, 0);
293 Length
= BaseName
->Length
;
295 /* Check if we have an extension */
298 /* Update the name length */
299 Length
+= (USHORT
)wcslen(Extension
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
301 /* Allocate the buffer for the full name */
302 NameBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
306 ObDereferenceObject(Event
);
307 ZwClose(EventHandle
);
308 return STATUS_NO_MEMORY
;
311 /* Build the full name */
312 FullName
.Buffer
= NameBuffer
;
313 FullName
.MaximumLength
= Length
;
314 RtlCopyUnicodeString(&FullName
, BaseName
);
318 /* The base name is the full name */
319 FullName
= *BaseName
;
323 /* Initialize the attributes */
324 InitializeObjectAttributes(&ObjectAttributes
,
326 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
330 /* Check if we can create the hive */
331 if ((CreateAllowed
) && !(CmpShareSystemHives
))
333 /* Open only or create */
334 CreateDisposition
= FILE_OPEN_IF
;
339 CreateDisposition
= FILE_OPEN
;
342 /* Setup the flags */
343 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot
344 IoFlags
= //FILE_OPEN_FOR_BACKUP_INTENT |
345 FILE_NO_COMPRESSION
|
347 (NoBuffering
? FILE_NO_INTERMEDIATE_BUFFERING
: 0);
349 /* Set share and access modes */
350 if ((CmpMiniNTBoot
) && (CmpShareSystemHives
))
352 /* We're on Live CD or otherwise sharing */
353 DesiredAccess
= FILE_READ_DATA
;
354 ShareMode
= FILE_SHARE_READ
;
358 /* We want to write exclusively */
360 DesiredAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
363 /* Default attributes */
364 AttributeFlags
= FILE_ATTRIBUTE_NORMAL
;
366 /* Now create the file */
367 Status
= ZwCreateFile(Primary
,
368 DesiredAccess
| SYNCHRONIZE
,
375 FILE_SYNCHRONOUS_IO_NONALERT
| IoFlags
,
378 /* Check if anything failed until now */
379 if (!NT_SUCCESS(Status
))
381 DPRINT1("ZwCreateFile(%wZ) failed, Status 0x%08lx.\n", ObjectAttributes
.ObjectName
, Status
);
383 /* Close handles and free buffers */
384 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
385 ObDereferenceObject(Event
);
386 ZwClose(EventHandle
);
391 if (MarkAsSystemHive
)
393 /* We opened it, mark it as a system hive */
394 Status
= ZwFsControlFile(*Primary
,
399 FSCTL_MARK_AS_SYSTEM_HIVE
,
404 if (Status
== STATUS_PENDING
)
406 /* Wait for completion */
407 KeWaitForSingleObject(Event
,
412 Status
= IoStatusBlock
.Status
;
415 /* If we don't support it, ignore the failure */
416 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
418 if (!NT_SUCCESS(Status
))
420 /* Close handles and free buffers */
421 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
422 ObDereferenceObject(Event
);
423 ZwClose(EventHandle
);
430 /* Disable compression */
431 CompressionState
= 0;
432 Status
= ZwFsControlFile(*Primary
,
437 FSCTL_SET_COMPRESSION
,
439 sizeof(CompressionState
),
442 if (Status
== STATUS_PENDING
)
444 /* Wait for completion */
445 KeWaitForSingleObject(Event
,
452 /* Get the disposition */
453 *PrimaryDisposition
= (ULONG
)IoStatusBlock
.Information
;
454 if (IoStatusBlock
.Information
!= FILE_CREATED
)
456 /* Check how large the file is */
457 Status
= ZwQueryInformationFile(*Primary
,
460 sizeof(FileInformation
),
461 FileStandardInformation
);
462 if (NT_SUCCESS(Status
))
464 /* Check if it's 0 bytes */
465 if (!FileInformation
.EndOfFile
.QuadPart
)
467 /* Assume it's a new file */
468 *PrimaryDisposition
= FILE_CREATED
;
473 /* Check if the caller wants cluster size returned */
477 Status
= ZwQueryVolumeInformationFile(*Primary
,
480 sizeof(FsSizeInformation
),
481 FileFsSizeInformation
);
482 if (!NT_SUCCESS(Status
))
484 /* Close handles and free buffers */
485 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
486 ObDereferenceObject(Event
);
487 ZwClose(EventHandle
);
491 /* Check if the sector size is invalid */
492 if (FsSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
494 /* Close handles and free buffers */
495 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
496 ObDereferenceObject(Event
);
497 ZwClose(EventHandle
);
498 return STATUS_CANNOT_LOAD_REGISTRY_FILE
;
501 /* Return cluster size */
502 *ClusterSize
= max(1, FsSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
);
505 /* Check if we don't need to create a log file */
508 /* We're done, close handles */
509 ObDereferenceObject(Event
);
510 ZwClose(EventHandle
);
511 return STATUS_SUCCESS
;
514 /* Check if we can create the hive */
515 CreateDisposition
= CmpShareSystemHives
? FILE_OPEN
: FILE_OPEN_IF
;
516 if (*PrimaryDisposition
== FILE_CREATED
)
518 /* Over-write the existing log file, since this is a new hive */
519 CreateDisposition
= FILE_SUPERSEDE
;
523 RtlInitUnicodeString(&ExtensionName
, Extension
);
524 RtlAppendUnicodeStringToString(&FullName
, &ExtensionName
);
526 /* Initialize the attributes */
527 InitializeObjectAttributes(&ObjectAttributes
,
529 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
533 /* Setup the flags */
534 IoFlags
= FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
;
536 /* Check if this is a log file */
537 if (!_wcsnicmp(Extension
, L
".log", 4))
540 AttributeFlags
|= FILE_ATTRIBUTE_HIDDEN
;
543 /* Now create the file */
544 Status
= ZwCreateFile(Log
,
555 if ((NT_SUCCESS(Status
)) && (MarkAsSystemHive
))
557 /* We opened it, mark it as a system hive */
558 Status
= ZwFsControlFile(*Log
,
563 FSCTL_MARK_AS_SYSTEM_HIVE
,
568 if (Status
== STATUS_PENDING
)
570 /* Wait for completion */
571 KeWaitForSingleObject(Event
,
576 Status
= IoStatusBlock
.Status
;
579 /* If we don't support it, ignore the failure */
580 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
582 /* If we failed, close the handle */
583 if (!NT_SUCCESS(Status
)) ZwClose(*Log
);
586 /* Check if anything failed until now */
587 if (!NT_SUCCESS(Status
))
589 /* Clear the handle */
594 /* Disable compression */
595 Status
= ZwFsControlFile(*Log
,
600 FSCTL_SET_COMPRESSION
,
602 sizeof(CompressionState
),
605 if (Status
== STATUS_PENDING
)
607 /* Wait for completion */
608 KeWaitForSingleObject(Event
,
615 /* Return the disposition */
616 *LogDisposition
= (ULONG
)IoStatusBlock
.Information
;
619 /* We're done, close handles and free buffers */
620 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
621 ObDereferenceObject(Event
);
622 ZwClose(EventHandle
);
623 return STATUS_SUCCESS
;
628 CmpCloseHiveFiles(IN PCMHIVE Hive
)
632 for (i
= 0; i
< HFILE_TYPE_MAX
; i
++)
634 if (Hive
->FileHandles
[i
] != NULL
)
636 ZwClose(Hive
->FileHandles
[i
]);
637 Hive
->FileHandles
[i
] = NULL
;