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
),
121 /* Cleanup allocation and fail */
122 ExFreePoolWithTag(Hive
, TAG_CM
);
123 return STATUS_INSUFFICIENT_RESOURCES
;
126 /* Allocate the flush lock */
127 Hive
->FlusherLock
= ExAllocatePoolWithTag(NonPagedPool
,
130 if (!Hive
->FlusherLock
)
132 /* Cleanup allocations and fail */
133 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CM
);
134 ExFreePoolWithTag(Hive
, TAG_CM
);
135 return STATUS_INSUFFICIENT_RESOURCES
;
138 /* Setup the handles */
139 Hive
->FileHandles
[HFILE_TYPE_PRIMARY
] = Primary
;
140 Hive
->FileHandles
[HFILE_TYPE_LOG
] = Log
;
141 Hive
->FileHandles
[HFILE_TYPE_EXTERNAL
] = External
;
143 /* Initailize the guarded mutex */
144 KeInitializeGuardedMutex(Hive
->ViewLock
);
145 Hive
->ViewLockOwner
= NULL
;
147 /* Initialize the flush lock */
148 ExInitializeResourceLite(Hive
->FlusherLock
);
150 /* Setup hive locks */
151 ExInitializePushLock(&Hive
->HiveLock
);
152 Hive
->HiveLockOwner
= NULL
;
153 ExInitializePushLock(&Hive
->WriterLock
);
154 Hive
->WriterLockOwner
= NULL
;
155 ExInitializePushLock(&Hive
->SecurityLock
);
156 Hive
->HiveSecurityLockOwner
= NULL
;
158 /* Clear file names */
159 RtlInitEmptyUnicodeString(&Hive
->FileUserName
, NULL
, 0);
160 RtlInitEmptyUnicodeString(&Hive
->FileFullPath
, NULL
, 0);
162 /* Initialize the view list */
163 CmpInitHiveViewList(Hive
);
165 /* Initailize the security cache */
166 CmpInitSecurityCache(Hive
);
170 Hive
->FlushCount
= 0;
173 Hive
->Flags
= HiveFlags
;
175 /* Check if this is a primary */
178 /* Check how large the file is */
179 ZwQueryInformationFile(Primary
,
182 sizeof(FileInformation
),
183 FileStandardInformation
);
184 Cluster
= FileInformation
.EndOfFile
.LowPart
;
188 Status
= HvInitialize(&Hive
->Hive
,
201 if (!NT_SUCCESS(Status
))
203 /* Cleanup allocations and fail */
204 ExDeleteResourceLite(Hive
->FlusherLock
);
205 ExFreePoolWithTag(Hive
->FlusherLock
, TAG_CM
);
206 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CM
);
207 ExFreePoolWithTag(Hive
, TAG_CM
);
211 /* Check if we should verify the registry */
212 if ((OperationType
== HINIT_FILE
) ||
213 (OperationType
== HINIT_MEMORY
) ||
214 (OperationType
== HINIT_MEMORY_INPLACE
) ||
215 (OperationType
== HINIT_MAPFILE
))
217 /* Verify integrity */
218 ULONG CheckStatus
= CmCheckRegistry(Hive
, CheckFlags
);
219 if (CheckStatus
!= 0)
221 /* Cleanup allocations and fail */
222 ExDeleteResourceLite(Hive
->FlusherLock
);
223 ExFreePoolWithTag(Hive
->FlusherLock
, TAG_CM
);
224 ExFreePoolWithTag(Hive
->ViewLock
, TAG_CM
);
225 ExFreePoolWithTag(Hive
, TAG_CM
);
226 return STATUS_REGISTRY_CORRUPT
;
230 /* Lock the hive list */
231 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
233 /* Insert this hive */
234 InsertHeadList(&CmpHiveListHead
, &Hive
->HiveList
);
236 /* Release the lock */
237 ExReleasePushLock(&CmpHiveListHeadLock
);
239 /* Return the hive and success */
240 *RegistryHive
= (PCMHIVE
)Hive
;
241 return STATUS_SUCCESS
;
246 CmpDestroyHive(IN PCMHIVE CmHive
)
248 /* Remove the hive from the list */
249 ExAcquirePushLockExclusive(&CmpHiveListHeadLock
);
250 RemoveEntryList(&CmHive
->HiveList
);
251 ExReleasePushLock(&CmpHiveListHeadLock
);
253 /* Delete the flusher lock */
254 ExDeleteResourceLite(CmHive
->FlusherLock
);
255 ExFreePoolWithTag(CmHive
->FlusherLock
, TAG_CM
);
257 /* Delete the view lock */
258 ExFreePoolWithTag(CmHive
->ViewLock
, TAG_CM
);
261 HvFree(&CmHive
->Hive
);
263 return STATUS_SUCCESS
;
268 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName
,
269 IN PCWSTR Extension OPTIONAL
,
272 OUT PULONG PrimaryDisposition
,
273 OUT PULONG LogDisposition
,
274 IN BOOLEAN CreateAllowed
,
275 IN BOOLEAN MarkAsSystemHive
,
276 IN BOOLEAN NoBuffering
,
277 OUT PULONG ClusterSize OPTIONAL
)
282 UNICODE_STRING FullName
, ExtensionName
;
285 OBJECT_ATTRIBUTES ObjectAttributes
;
286 IO_STATUS_BLOCK IoStatusBlock
;
287 ULONG AttributeFlags
, ShareMode
, DesiredAccess
, CreateDisposition
, IoFlags
;
288 USHORT CompressionState
;
289 FILE_STANDARD_INFORMATION FileInformation
;
290 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
293 Status
= CmpCreateEvent(NotificationEvent
, &EventHandle
, &Event
);
294 if (!NT_SUCCESS(Status
)) return Status
;
296 /* Initialize the full name */
297 RtlInitEmptyUnicodeString(&FullName
, NULL
, 0);
298 Length
= BaseName
->Length
;
300 /* Check if we have an extension */
303 /* Update the name length */
304 Length
+= (USHORT
)wcslen(Extension
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
306 /* Allocate the buffer for the full name */
307 NameBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
311 ObDereferenceObject(Event
);
312 ZwClose(EventHandle
);
313 return STATUS_NO_MEMORY
;
316 /* Build the full name */
317 FullName
.Buffer
= NameBuffer
;
318 FullName
.MaximumLength
= Length
;
319 RtlAppendUnicodeStringToString(&FullName
, BaseName
);
323 /* The base name is the full name */
324 FullName
= *BaseName
;
328 /* Initialize the attributes */
329 InitializeObjectAttributes(&ObjectAttributes
,
331 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
335 /* Check if we can create the hive */
336 if ((CreateAllowed
) && !(CmpShareSystemHives
))
338 /* Open only or create */
339 CreateDisposition
= FILE_OPEN_IF
;
344 CreateDisposition
= FILE_OPEN
;
347 /* Setup the flags */
348 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot
349 IoFlags
= //FILE_OPEN_FOR_BACKUP_INTENT |
350 FILE_NO_COMPRESSION
|
352 (NoBuffering
? FILE_NO_INTERMEDIATE_BUFFERING
: 0);
354 /* Set share and access modes */
355 if ((CmpMiniNTBoot
) && (CmpShareSystemHives
))
357 /* We're on Live CD or otherwise sharing */
358 DesiredAccess
= FILE_READ_DATA
;
359 ShareMode
= FILE_SHARE_READ
;
363 /* We want to write exclusively */
365 DesiredAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
368 /* Default attributes */
369 AttributeFlags
= FILE_ATTRIBUTE_NORMAL
;
371 /* Now create the file */
372 Status
= ZwCreateFile(Primary
,
373 DesiredAccess
| SYNCHRONIZE
,
380 FILE_SYNCHRONOUS_IO_NONALERT
| IoFlags
,
383 /* Check if anything failed until now */
384 if (!NT_SUCCESS(Status
))
386 /* Close handles and free buffers */
387 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
388 ObDereferenceObject(Event
);
389 ZwClose(EventHandle
);
390 DPRINT1("ZwCreateFile failed : %lx.\n", Status
);
395 if (MarkAsSystemHive
)
397 /* We opened it, mark it as a system hive */
398 Status
= ZwFsControlFile(*Primary
,
403 FSCTL_MARK_AS_SYSTEM_HIVE
,
408 if (Status
== STATUS_PENDING
)
410 /* Wait for completion */
411 KeWaitForSingleObject(Event
,
416 Status
= IoStatusBlock
.Status
;
419 /* If we don't support it, ignore the failure */
420 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
422 if (!NT_SUCCESS(Status
))
424 /* Close handles and free buffers */
425 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
426 ObDereferenceObject(Event
);
427 ZwClose(EventHandle
);
434 /* Disable compression */
435 CompressionState
= 0;
436 Status
= ZwFsControlFile(*Primary
,
441 FSCTL_SET_COMPRESSION
,
443 sizeof(CompressionState
),
446 if (Status
== STATUS_PENDING
)
448 /* Wait for completion */
449 KeWaitForSingleObject(Event
,
456 /* Get the disposition */
457 *PrimaryDisposition
= (ULONG
)IoStatusBlock
.Information
;
458 if (IoStatusBlock
.Information
!= FILE_CREATED
)
460 /* Check how large the file is */
461 Status
= ZwQueryInformationFile(*Primary
,
464 sizeof(FileInformation
),
465 FileStandardInformation
);
466 if (NT_SUCCESS(Status
))
468 /* Check if it's 0 bytes */
469 if (!FileInformation
.EndOfFile
.QuadPart
)
471 /* Assume it's a new file */
472 *PrimaryDisposition
= FILE_CREATED
;
477 /* Check if the caller wants cluster size returned */
481 Status
= ZwQueryVolumeInformationFile(*Primary
,
484 sizeof(FsSizeInformation
),
485 FileFsSizeInformation
);
486 if (!NT_SUCCESS(Status
))
488 /* Close handles and free buffers */
489 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
490 ObDereferenceObject(Event
);
491 ZwClose(EventHandle
);
495 /* Check if the sector size is invalid */
496 if (FsSizeInformation
.BytesPerSector
> HBLOCK_SIZE
)
498 /* Close handles and free buffers */
499 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
500 ObDereferenceObject(Event
);
501 ZwClose(EventHandle
);
502 return STATUS_CANNOT_LOAD_REGISTRY_FILE
;
505 /* Return cluster size */
506 *ClusterSize
= max(1, FsSizeInformation
.BytesPerSector
/ HSECTOR_SIZE
);
509 /* Check if we don't need to create a log file */
512 /* We're done, close handles */
513 ObDereferenceObject(Event
);
514 ZwClose(EventHandle
);
515 return STATUS_SUCCESS
;
518 /* Check if we can create the hive */
519 CreateDisposition
= CmpShareSystemHives
? FILE_OPEN
: FILE_OPEN_IF
;
520 if (*PrimaryDisposition
== FILE_CREATED
)
522 /* Over-write the existing log file, since this is a new hive */
523 CreateDisposition
= FILE_SUPERSEDE
;
527 RtlInitUnicodeString(&ExtensionName
, Extension
);
528 RtlAppendUnicodeStringToString(&FullName
, &ExtensionName
);
530 /* Initialize the attributes */
531 InitializeObjectAttributes(&ObjectAttributes
,
533 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
537 /* Setup the flags */
538 IoFlags
= FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
;
540 /* Check if this is a log file */
541 if (!_wcsnicmp(Extension
, L
".log", 4))
544 AttributeFlags
|= FILE_ATTRIBUTE_HIDDEN
;
547 /* Now create the file */
548 Status
= ZwCreateFile(Log
,
559 if ((NT_SUCCESS(Status
)) && (MarkAsSystemHive
))
561 /* We opened it, mark it as a system hive */
562 Status
= ZwFsControlFile(*Log
,
567 FSCTL_MARK_AS_SYSTEM_HIVE
,
572 if (Status
== STATUS_PENDING
)
574 /* Wait for completion */
575 KeWaitForSingleObject(Event
,
580 Status
= IoStatusBlock
.Status
;
583 /* If we don't support it, ignore the failure */
584 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) Status
= STATUS_SUCCESS
;
586 /* If we failed, close the handle */
587 if (!NT_SUCCESS(Status
)) ZwClose(*Log
);
590 /* Check if anything failed until now */
591 if (!NT_SUCCESS(Status
))
593 /* Clear the handle */
598 /* Disable compression */
599 Status
= ZwFsControlFile(*Log
,
604 FSCTL_SET_COMPRESSION
,
606 sizeof(CompressionState
),
609 if (Status
== STATUS_PENDING
)
611 /* Wait for completion */
612 KeWaitForSingleObject(Event
,
619 /* Return the disposition */
620 *LogDisposition
= (ULONG
)IoStatusBlock
.Information
;
623 /* We're done, close handles and free buffers */
624 if (NameBuffer
) ExFreePoolWithTag(NameBuffer
, TAG_CM
);
625 ObDereferenceObject(Event
);
626 ZwClose(EventHandle
);
627 return STATUS_SUCCESS
;