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
*RegistryHive
,
20 IN ULONG OperationType
,
23 IN PVOID HiveData OPTIONAL
,
27 IN PCUNICODE_STRING FileName OPTIONAL
,
31 FILE_STANDARD_INFORMATION FileInformation
;
32 IO_STATUS_BLOCK IoStatusBlock
;
33 FILE_FS_SIZE_INFORMATION FileSizeInformation
;
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.
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
)))
54 /* Fail the request */
55 return STATUS_INVALID_PARAMETER
;
58 /* Check if this is a primary hive */
61 /* Get the cluster size */
62 Status
= ZwQueryVolumeInformationFile(Primary
,
65 sizeof(FILE_FS_SIZE_INFORMATION
),
66 FileFsSizeInformation
);
67 if (!NT_SUCCESS(Status
)) return Status
;
69 /* Make sure it's not larger then the block size */
70 if (FileSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
73 return STATUS_REGISTRY_IO_FAILED
;
76 /* Otherwise, calculate the cluster */
77 Cluster
= FileSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
;
78 Cluster
= max(1, Cluster
);
82 /* Otherwise use cluster 1 */
86 /* Allocate the hive */
87 Hive
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CMHIVE
), TAG_CM
);
88 if (!Hive
) return STATUS_INSUFFICIENT_RESOURCES
;
90 /* Setup null fields */
91 Hive
->UnloadEvent
= NULL
;
94 Hive
->UnloadWorkItem
= NULL
;
95 Hive
->GrowOnlyMode
= FALSE
;
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
;
104 /* Set loading flag */
105 Hive
->HiveIsLoading
= TRUE
;
107 /* Set the current thread as creator */
108 Hive
->CreatorOwner
= KeGetCurrentThread();
110 /* Initialize lists */
111 InitializeListHead(&Hive
->KcbConvertListHead
);
112 InitializeListHead(&Hive
->KnodeConvertListHead
);
113 InitializeListHead(&Hive
->TrustClassEntry
);
115 /* Allocate the view log */
116 Hive
->ViewLock
= ExAllocatePoolWithTag(NonPagedPool
,
117 sizeof(KGUARDED_MUTEX
),
119 if (!Hive
->ViewLock
) return STATUS_INSUFFICIENT_RESOURCES
;
121 /* Allocate the flush lock */
122 Hive
->FlusherLock
= ExAllocatePoolWithTag(NonPagedPool
,
125 if (!Hive
->FlusherLock
) return STATUS_INSUFFICIENT_RESOURCES
;
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
;
132 /* Initailize the guarded mutex */
133 KeInitializeGuardedMutex(Hive
->ViewLock
);
134 Hive
->ViewLockOwner
= NULL
;
136 /* Initialize the flush lock */
137 ExInitializeResourceLite(Hive
->FlusherLock
);
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
;
147 /* Clear file names */
148 RtlInitEmptyUnicodeString(&Hive
->FileUserName
, NULL
, 0);
149 RtlInitEmptyUnicodeString(&Hive
->FileFullPath
, NULL
, 0);
151 /* Initialize the view list */
152 CmpInitHiveViewList(Hive
);
154 /* Initailize the security cache */
155 CmpInitSecurityCache(Hive
);
159 Hive
->FlushCount
= 0;
162 Hive
->Flags
= HiveFlags
;
164 /* Check if this is a primary */
167 /* Check how large the file is */
168 ZwQueryInformationFile(Primary
,
171 sizeof(FileInformation
),
172 FileStandardInformation
);
173 Cluster
= FileInformation
.EndOfFile
.LowPart
;
177 Status
= HvInitialize(&Hive
->Hive
,
189 (PUNICODE_STRING
)FileName
);
190 if (!NT_SUCCESS(Status
))
192 /* Clear allocations and fail */
193 ExFreePool(Hive
->ViewLock
);
194 ExFreePool(Hive
->FlusherLock
);
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
))
205 /* Verify integrity */
206 if (CmCheckRegistry((PCMHIVE
)Hive
, TRUE
))
208 /* Free all alocations */
209 ExFreePool(Hive
->ViewLock
);
210 ExFreePool(Hive
->FlusherLock
);
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 */
226 *RegistryHive
= (PCMHIVE
)Hive
;
227 return STATUS_SUCCESS
;
232 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName
,
233 IN PCWSTR Extension OPTIONAL
,
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
)
246 UNICODE_STRING FullName
, ExtensionName
;
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
;
257 Status
= CmpCreateEvent(NotificationEvent
, &EventHandle
, &Event
);
258 if (!NT_SUCCESS(Status
)) return Status
;
260 /* Initialize the full name */
261 RtlInitEmptyUnicodeString(&FullName
, NULL
, 0);
262 Length
= BaseName
->Length
;
264 /* Check if we have an extension */
267 /* Update the name length */
268 Length
+= wcslen(Extension
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
270 /* Allocate the buffer for the full name */
271 NameBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
275 ObDereferenceObject(Event
);
276 ZwClose(EventHandle
);
277 return STATUS_NO_MEMORY
;
280 /* Build the full name */
281 FullName
.Buffer
= NameBuffer
;
282 FullName
.MaximumLength
= Length
;
283 RtlAppendUnicodeStringToString(&FullName
, BaseName
);
287 /* The base name is the full name */
288 FullName
= *BaseName
;
292 /* Initialize the attributes */
293 InitializeObjectAttributes(&ObjectAttributes
,
295 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
299 /* Check if we can create the hive */
300 if ((CreateAllowed
) && !(CmpShareSystemHives
))
302 /* Open only or create */
303 CreateDisposition
= FILE_OPEN_IF
;
308 CreateDisposition
= FILE_OPEN
;
311 /* Setup the flags */
312 IoFlags
= FILE_OPEN_FOR_BACKUP_INTENT
|
313 FILE_NO_COMPRESSION
|
315 (NoBuffering
) ? FILE_NO_INTERMEDIATE_BUFFERING
: 0;
317 /* Set share and access modes */
318 if ((CmpMiniNTBoot
) && (CmpShareSystemHives
))
320 /* We're on Live CD or otherwise sharing */
321 DesiredAccess
= FILE_READ_DATA
;
322 ShareMode
= FILE_SHARE_READ
;
326 /* We want to write exclusively */
328 DesiredAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
331 /* Default attributes */
332 AttributeFlags
= FILE_ATTRIBUTE_NORMAL
;
334 /* Now create the file */
335 Status
= ZwCreateFile(Primary
,
343 FILE_SYNCHRONOUS_IO_NONALERT
| IoFlags
,
346 if ((NT_SUCCESS(Status
)) && (MarkAsSystemHive
))
348 /* We opened it, mark it as a system hive */
349 Status
= ZwFsControlFile(*Primary
,
354 FSCTL_MARK_AS_SYSTEM_HIVE
,
359 if (Status
== STATUS_PENDING
)
361 /* Wait for completion */
362 KeWaitForSingleObject(Event
,
367 Status
= IoStatusBlock
.Status
;
370 /* If we don't support it, ignore the failure */
371 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
373 /* If we failed, close the handle */
374 if (!NT_SUCCESS(Status
)) ZwClose(*Primary
);
377 /* Check if anything failed until now */
378 if (!NT_SUCCESS(Status
))
380 /* Close handles and free buffers */
381 if (NameBuffer
) ExFreePool(NameBuffer
);
382 ObDereferenceObject(Event
);
383 ZwClose(EventHandle
);
387 /* Disable compression */
388 CompressionState
= 0;
389 Status
= ZwFsControlFile(*Primary
,
394 FSCTL_SET_COMPRESSION
,
396 sizeof(CompressionState
),
399 if (Status
== STATUS_PENDING
)
401 /* Wait for completion */
402 KeWaitForSingleObject(Event
,
409 /* Get the disposition */
410 *PrimaryDisposition
= IoStatusBlock
.Information
;
411 if (IoStatusBlock
.Information
!= FILE_CREATED
)
413 /* Check how large the file is */
414 Status
= ZwQueryInformationFile(*Primary
,
417 sizeof(FileInformation
),
418 FileStandardInformation
);
419 if (NT_SUCCESS(Status
))
421 /* Check if it's 0 bytes */
422 if (!FileInformation
.EndOfFile
.QuadPart
)
424 /* Assume it's a new file */
425 *PrimaryDisposition
= FILE_CREATED
;
430 /* Check if the caller wants cluster size returned */
434 Status
= ZwQueryVolumeInformationFile(*Primary
,
437 sizeof(FsSizeInformation
),
438 FileFsSizeInformation
);
439 if (!NT_SUCCESS(Status
))
441 /* Close handles and free buffers */
442 if (NameBuffer
) ExFreePool(NameBuffer
);
443 ObDereferenceObject(Event
);
444 ZwClose(EventHandle
);
448 /* Check if the sector size is invalid */
449 if (FsSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
451 /* Close handles and free buffers */
452 if (NameBuffer
) ExFreePool(NameBuffer
);
453 ObDereferenceObject(Event
);
454 ZwClose(EventHandle
);
455 return STATUS_CANNOT_LOAD_REGISTRY_FILE
;
458 /* Return cluster size */
459 *ClusterSize
= max(1, FsSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
);
462 /* Check if we don't need to create a log file */
465 /* We're done, close handles */
466 ObDereferenceObject(Event
);
467 ZwClose(EventHandle
);
468 return STATUS_SUCCESS
;
471 /* Check if we can create the hive */
472 CreateDisposition
= CmpShareSystemHives
? FILE_OPEN
: FILE_OPEN_IF
;
473 if (*PrimaryDisposition
== FILE_CREATED
)
475 /* Over-write the existing log file, since this is a new hive */
476 CreateDisposition
= FILE_SUPERSEDE
;
480 RtlInitUnicodeString(&ExtensionName
, Extension
);
481 RtlAppendUnicodeStringToString(&FullName
, &ExtensionName
);
483 /* Initialize the attributes */
484 InitializeObjectAttributes(&ObjectAttributes
,
486 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
490 /* Setup the flags */
491 IoFlags
= FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
;
493 /* Check if this is a log file */
494 if (!_wcsnicmp(Extension
, L
".log", 4))
497 AttributeFlags
|= FILE_ATTRIBUTE_HIDDEN
;
500 /* Now create the file */
501 Status
= ZwCreateFile(Log
,
512 if ((NT_SUCCESS(Status
)) && (MarkAsSystemHive
))
514 /* We opened it, mark it as a system hive */
515 Status
= ZwFsControlFile(*Log
,
520 FSCTL_MARK_AS_SYSTEM_HIVE
,
525 if (Status
== STATUS_PENDING
)
527 /* Wait for completion */
528 KeWaitForSingleObject(Event
,
533 Status
= IoStatusBlock
.Status
;
536 /* If we don't support it, ignore the failure */
537 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
539 /* If we failed, close the handle */
540 if (!NT_SUCCESS(Status
)) ZwClose(*Log
);
543 /* Check if anything failed until now */
544 if (!NT_SUCCESS(Status
))
546 /* Clear the handle */
551 /* Disable compression */
552 Status
= ZwFsControlFile(*Log
,
557 FSCTL_SET_COMPRESSION
,
559 sizeof(CompressionState
),
562 if (Status
== STATUS_PENDING
)
564 /* Wait for completion */
565 KeWaitForSingleObject(Event
,
572 /* Return the disposition */
573 *LogDisposition
= IoStatusBlock
.Information
;
576 /* We're done, close handles and free buffers */
577 if (NameBuffer
) ExFreePool(NameBuffer
);
578 ObDereferenceObject(Event
);
579 ZwClose(EventHandle
);
580 return STATUS_SUCCESS
;