[CMAKE]
[reactos.git] / 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 *RegistryHive,
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 FILE_STANDARD_INFORMATION FileInformation;
32 IO_STATUS_BLOCK IoStatusBlock;
33 FILE_FS_SIZE_INFORMATION FileSizeInformation;
34 NTSTATUS Status;
35 ULONG Cluster;
36
37 /* Assume failure */
38 *RegistryHive = NULL;
39
40 /*
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.
47 */
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)))
53 {
54 /* Fail the request */
55 return STATUS_INVALID_PARAMETER;
56 }
57
58 /* Check if this is a primary hive */
59 if (Primary)
60 {
61 /* Get the cluster size */
62 Status = ZwQueryVolumeInformationFile(Primary,
63 &IoStatusBlock,
64 &FileSizeInformation,
65 sizeof(FILE_FS_SIZE_INFORMATION),
66 FileFsSizeInformation);
67 if (!NT_SUCCESS(Status)) return Status;
68
69 /* Make sure it's not larger then the block size */
70 if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE)
71 {
72 /* Fail */
73 return STATUS_REGISTRY_IO_FAILED;
74 }
75
76 /* Otherwise, calculate the cluster */
77 Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE;
78 Cluster = max(1, Cluster);
79 }
80 else
81 {
82 /* Otherwise use cluster 1 */
83 Cluster = 1;
84 }
85
86 /* Allocate the hive */
87 Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CM);
88 if (!Hive) return STATUS_INSUFFICIENT_RESOURCES;
89
90 /* Setup null fields */
91 Hive->UnloadEvent = NULL;
92 Hive->RootKcb = NULL;
93 Hive->Frozen = FALSE;
94 Hive->UnloadWorkItem = NULL;
95 Hive->GrowOnlyMode = FALSE;
96 Hive->GrowOffset = 0;
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;
103
104 /* Set loading flag */
105 Hive->HiveIsLoading = TRUE;
106
107 /* Set the current thread as creator */
108 Hive->CreatorOwner = KeGetCurrentThread();
109
110 /* Initialize lists */
111 InitializeListHead(&Hive->KcbConvertListHead);
112 InitializeListHead(&Hive->KnodeConvertListHead);
113 InitializeListHead(&Hive->TrustClassEntry);
114
115 /* Allocate the view log */
116 Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool,
117 sizeof(KGUARDED_MUTEX),
118 TAG_CM);
119 if (!Hive->ViewLock) return STATUS_INSUFFICIENT_RESOURCES;
120
121 /* Allocate the flush lock */
122 Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool,
123 sizeof(ERESOURCE),
124 TAG_CM);
125 if (!Hive->FlusherLock) return STATUS_INSUFFICIENT_RESOURCES;
126
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;
131
132 /* Initailize the guarded mutex */
133 KeInitializeGuardedMutex(Hive->ViewLock);
134 Hive->ViewLockOwner = NULL;
135
136 /* Initialize the flush lock */
137 ExInitializeResourceLite(Hive->FlusherLock);
138
139 /* Setup hive locks */
140 ExInitializePushLock((PULONG_PTR)&Hive->HiveLock);
141 Hive->HiveLockOwner = NULL;
142 ExInitializePushLock((PULONG_PTR)&Hive->WriterLock);
143 Hive->WriterLockOwner = NULL;
144 ExInitializePushLock((PULONG_PTR)&Hive->SecurityLock);
145 Hive->HiveSecurityLockOwner = NULL;
146
147 /* Clear file names */
148 RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0);
149 RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0);
150
151 /* Initialize the view list */
152 CmpInitHiveViewList(Hive);
153
154 /* Initailize the security cache */
155 CmpInitSecurityCache(Hive);
156
157 /* Setup flags */
158 Hive->Flags = 0;
159 Hive->FlushCount = 0;
160
161 /* Set flags */
162 Hive->Flags = HiveFlags;
163
164 /* Check if this is a primary */
165 if (Primary)
166 {
167 /* Check how large the file is */
168 ZwQueryInformationFile(Primary,
169 &IoStatusBlock,
170 &FileInformation,
171 sizeof(FileInformation),
172 FileStandardInformation);
173 Cluster = FileInformation.EndOfFile.LowPart;
174 }
175
176 /* Initialize it */
177 Status = HvInitialize(&Hive->Hive,
178 OperationType,
179 FileType,
180 HiveFlags,
181 HiveData,
182 CmpAllocate,
183 CmpFree,
184 CmpFileSetSize,
185 CmpFileWrite,
186 CmpFileRead,
187 CmpFileFlush,
188 Cluster,
189 (PUNICODE_STRING)FileName);
190 if (!NT_SUCCESS(Status))
191 {
192 /* Clear allocations and fail */
193 ExFreePool(Hive->ViewLock);
194 ExFreePool(Hive->FlusherLock);
195 ExFreePool(Hive);
196 return Status;
197 }
198
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))
204 {
205 /* Verify integrity */
206 if (CmCheckRegistry((PCMHIVE)Hive, TRUE))
207 {
208 /* Free all alocations */
209 ExFreePool(Hive->ViewLock);
210 ExFreePool(Hive->FlusherLock);
211 ExFreePool(Hive);
212 return STATUS_REGISTRY_CORRUPT;
213 }
214 }
215
216 /* Lock the hive list */
217 ExAcquirePushLockExclusive(&CmpHiveListHeadLock);
218
219 /* Insert this hive */
220 InsertHeadList(&CmpHiveListHead, &Hive->HiveList);
221
222 /* Release the lock */
223 ExReleasePushLock(&CmpHiveListHeadLock);
224
225 /* Return the hive and success */
226 *RegistryHive = (PCMHIVE)Hive;
227 return STATUS_SUCCESS;
228 }
229
230 NTSTATUS
231 NTAPI
232 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,
233 IN PCWSTR Extension OPTIONAL,
234 IN PHANDLE Primary,
235 IN PHANDLE Log,
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)
242 {
243 HANDLE EventHandle;
244 PKEVENT Event;
245 NTSTATUS Status;
246 UNICODE_STRING FullName, ExtensionName;
247 PWCHAR NameBuffer;
248 USHORT Length;
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;
255
256 /* Create event */
257 Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event);
258 if (!NT_SUCCESS(Status)) return Status;
259
260 /* Initialize the full name */
261 RtlInitEmptyUnicodeString(&FullName, NULL, 0);
262 Length = BaseName->Length;
263
264 /* Check if we have an extension */
265 if (Extension)
266 {
267 /* Update the name length */
268 Length += wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
269
270 /* Allocate the buffer for the full name */
271 NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
272 if (!NameBuffer)
273 {
274 /* Fail */
275 ObDereferenceObject(Event);
276 ZwClose(EventHandle);
277 return STATUS_NO_MEMORY;
278 }
279
280 /* Build the full name */
281 FullName.Buffer = NameBuffer;
282 FullName.MaximumLength = Length;
283 RtlAppendUnicodeStringToString(&FullName, BaseName);
284 }
285 else
286 {
287 /* The base name is the full name */
288 FullName = *BaseName;
289 NameBuffer = NULL;
290 }
291
292 /* Initialize the attributes */
293 InitializeObjectAttributes(&ObjectAttributes,
294 &FullName,
295 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
296 NULL,
297 NULL);
298
299 /* Check if we can create the hive */
300 if ((CreateAllowed) && !(CmpShareSystemHives))
301 {
302 /* Open only or create */
303 CreateDisposition = FILE_OPEN_IF;
304 }
305 else
306 {
307 /* Open only */
308 CreateDisposition = FILE_OPEN;
309 }
310
311 /* Setup the flags */
312 IoFlags = FILE_OPEN_FOR_BACKUP_INTENT |
313 FILE_NO_COMPRESSION |
314 FILE_RANDOM_ACCESS |
315 (NoBuffering) ? FILE_NO_INTERMEDIATE_BUFFERING : 0;
316
317 /* Set share and access modes */
318 if ((CmpMiniNTBoot) && (CmpShareSystemHives))
319 {
320 /* We're on Live CD or otherwise sharing */
321 DesiredAccess = FILE_READ_DATA;
322 ShareMode = FILE_SHARE_READ;
323 }
324 else
325 {
326 /* We want to write exclusively */
327 ShareMode = 0;
328 DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA;
329 }
330
331 /* Default attributes */
332 AttributeFlags = FILE_ATTRIBUTE_NORMAL;
333
334 /* Now create the file */
335 Status = ZwCreateFile(Primary,
336 DesiredAccess,
337 &ObjectAttributes,
338 &IoStatusBlock,
339 NULL,
340 AttributeFlags,
341 ShareMode,
342 CreateDisposition,
343 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags,
344 NULL,
345 0);
346 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
347 {
348 /* We opened it, mark it as a system hive */
349 Status = ZwFsControlFile(*Primary,
350 EventHandle,
351 NULL,
352 NULL,
353 &IoStatusBlock,
354 FSCTL_MARK_AS_SYSTEM_HIVE,
355 NULL,
356 0,
357 NULL,
358 0);
359 if (Status == STATUS_PENDING)
360 {
361 /* Wait for completion */
362 KeWaitForSingleObject(Event,
363 Executive,
364 KernelMode,
365 FALSE,
366 NULL);
367 Status = IoStatusBlock.Status;
368 }
369
370 /* If we don't support it, ignore the failure */
371 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
372
373 /* If we failed, close the handle */
374 if (!NT_SUCCESS(Status)) ZwClose(*Primary);
375 }
376
377 /* Check if anything failed until now */
378 if (!NT_SUCCESS(Status))
379 {
380 /* Close handles and free buffers */
381 if (NameBuffer) ExFreePool(NameBuffer);
382 ObDereferenceObject(Event);
383 ZwClose(EventHandle);
384 return Status;
385 }
386
387 /* Disable compression */
388 CompressionState = 0;
389 Status = ZwFsControlFile(*Primary,
390 EventHandle,
391 NULL,
392 NULL,
393 &IoStatusBlock,
394 FSCTL_SET_COMPRESSION,
395 &CompressionState,
396 sizeof(CompressionState),
397 NULL,
398 0);
399 if (Status == STATUS_PENDING)
400 {
401 /* Wait for completion */
402 KeWaitForSingleObject(Event,
403 Executive,
404 KernelMode,
405 FALSE,
406 NULL);
407 }
408
409 /* Get the disposition */
410 *PrimaryDisposition = IoStatusBlock.Information;
411 if (IoStatusBlock.Information != FILE_CREATED)
412 {
413 /* Check how large the file is */
414 Status = ZwQueryInformationFile(*Primary,
415 &IoStatusBlock,
416 &FileInformation,
417 sizeof(FileInformation),
418 FileStandardInformation);
419 if (NT_SUCCESS(Status))
420 {
421 /* Check if it's 0 bytes */
422 if (!FileInformation.EndOfFile.QuadPart)
423 {
424 /* Assume it's a new file */
425 *PrimaryDisposition = FILE_CREATED;
426 }
427 }
428 }
429
430 /* Check if the caller wants cluster size returned */
431 if (ClusterSize)
432 {
433 /* Query it */
434 Status = ZwQueryVolumeInformationFile(*Primary,
435 &IoStatusBlock,
436 &FsSizeInformation,
437 sizeof(FsSizeInformation),
438 FileFsSizeInformation);
439 if (!NT_SUCCESS(Status))
440 {
441 /* Close handles and free buffers */
442 if (NameBuffer) ExFreePool(NameBuffer);
443 ObDereferenceObject(Event);
444 ZwClose(EventHandle);
445 return Status;
446 }
447
448 /* Check if the sector size is invalid */
449 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE)
450 {
451 /* Close handles and free buffers */
452 if (NameBuffer) ExFreePool(NameBuffer);
453 ObDereferenceObject(Event);
454 ZwClose(EventHandle);
455 return STATUS_CANNOT_LOAD_REGISTRY_FILE;
456 }
457
458 /* Return cluster size */
459 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE);
460 }
461
462 /* Check if we don't need to create a log file */
463 if (!Extension)
464 {
465 /* We're done, close handles */
466 ObDereferenceObject(Event);
467 ZwClose(EventHandle);
468 return STATUS_SUCCESS;
469 }
470
471 /* Check if we can create the hive */
472 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
473 if (*PrimaryDisposition == FILE_CREATED)
474 {
475 /* Over-write the existing log file, since this is a new hive */
476 CreateDisposition = FILE_SUPERSEDE;
477 }
478
479 /* Setup the name */
480 RtlInitUnicodeString(&ExtensionName, Extension);
481 RtlAppendUnicodeStringToString(&FullName, &ExtensionName);
482
483 /* Initialize the attributes */
484 InitializeObjectAttributes(&ObjectAttributes,
485 &FullName,
486 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
487 NULL,
488 NULL);
489
490 /* Setup the flags */
491 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
492
493 /* Check if this is a log file */
494 if (!_wcsnicmp(Extension, L".log", 4))
495 {
496 /* Hide log files */
497 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN;
498 }
499
500 /* Now create the file */
501 Status = ZwCreateFile(Log,
502 DesiredAccess,
503 &ObjectAttributes,
504 &IoStatusBlock,
505 NULL,
506 AttributeFlags,
507 ShareMode,
508 CreateDisposition,
509 IoFlags,
510 NULL,
511 0);
512 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
513 {
514 /* We opened it, mark it as a system hive */
515 Status = ZwFsControlFile(*Log,
516 EventHandle,
517 NULL,
518 NULL,
519 &IoStatusBlock,
520 FSCTL_MARK_AS_SYSTEM_HIVE,
521 NULL,
522 0,
523 NULL,
524 0);
525 if (Status == STATUS_PENDING)
526 {
527 /* Wait for completion */
528 KeWaitForSingleObject(Event,
529 Executive,
530 KernelMode,
531 FALSE,
532 NULL);
533 Status = IoStatusBlock.Status;
534 }
535
536 /* If we don't support it, ignore the failure */
537 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
538
539 /* If we failed, close the handle */
540 if (!NT_SUCCESS(Status)) ZwClose(*Log);
541 }
542
543 /* Check if anything failed until now */
544 if (!NT_SUCCESS(Status))
545 {
546 /* Clear the handle */
547 *Log = NULL;
548 }
549 else
550 {
551 /* Disable compression */
552 Status = ZwFsControlFile(*Log,
553 EventHandle,
554 NULL,
555 NULL,
556 &IoStatusBlock,
557 FSCTL_SET_COMPRESSION,
558 &CompressionState,
559 sizeof(CompressionState),
560 NULL,
561 0);
562 if (Status == STATUS_PENDING)
563 {
564 /* Wait for completion */
565 KeWaitForSingleObject(Event,
566 Executive,
567 KernelMode,
568 FALSE,
569 NULL);
570 }
571
572 /* Return the disposition */
573 *LogDisposition = IoStatusBlock.Information;
574 }
575
576 /* We're done, close handles and free buffers */
577 if (NameBuffer) ExFreePool(NameBuffer);
578 ObDereferenceObject(Event);
579 ZwClose(EventHandle);
580 return STATUS_SUCCESS;
581 }