[CMLIB]
[reactos.git] / reactos / 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)
120 {
121 /* Cleanup allocation and fail */
122 ExFreePoolWithTag(Hive, TAG_CM);
123 return STATUS_INSUFFICIENT_RESOURCES;
124 }
125
126 /* Allocate the flush lock */
127 Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool,
128 sizeof(ERESOURCE),
129 TAG_CM);
130 if (!Hive->FlusherLock)
131 {
132 /* Cleanup allocations and fail */
133 ExFreePoolWithTag(Hive->ViewLock, TAG_CM);
134 ExFreePoolWithTag(Hive, TAG_CM);
135 return STATUS_INSUFFICIENT_RESOURCES;
136 }
137
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;
142
143 /* Initailize the guarded mutex */
144 KeInitializeGuardedMutex(Hive->ViewLock);
145 Hive->ViewLockOwner = NULL;
146
147 /* Initialize the flush lock */
148 ExInitializeResourceLite(Hive->FlusherLock);
149
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;
157
158 /* Clear file names */
159 RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0);
160 RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0);
161
162 /* Initialize the view list */
163 CmpInitHiveViewList(Hive);
164
165 /* Initailize the security cache */
166 CmpInitSecurityCache(Hive);
167
168 /* Setup flags */
169 Hive->Flags = 0;
170 Hive->FlushCount = 0;
171
172 /* Set flags */
173 Hive->Flags = HiveFlags;
174
175 /* Check if this is a primary */
176 if (Primary)
177 {
178 /* Check how large the file is */
179 ZwQueryInformationFile(Primary,
180 &IoStatusBlock,
181 &FileInformation,
182 sizeof(FileInformation),
183 FileStandardInformation);
184 Cluster = FileInformation.EndOfFile.LowPart;
185 }
186
187 /* Initialize it */
188 Status = HvInitialize(&Hive->Hive,
189 OperationType,
190 FileType,
191 HiveFlags,
192 HiveData,
193 CmpAllocate,
194 CmpFree,
195 CmpFileSetSize,
196 CmpFileWrite,
197 CmpFileRead,
198 CmpFileFlush,
199 Cluster,
200 FileName);
201 if (!NT_SUCCESS(Status))
202 {
203 /* Cleanup allocations and fail */
204 ExFreePoolWithTag(Hive->FlusherLock, TAG_CM);
205 ExFreePoolWithTag(Hive->ViewLock, TAG_CM);
206 ExFreePoolWithTag(Hive, TAG_CM);
207 return Status;
208 }
209
210 /* Check if we should verify the registry */
211 if ((OperationType == HINIT_FILE) ||
212 (OperationType == HINIT_MEMORY) ||
213 (OperationType == HINIT_MEMORY_INPLACE) ||
214 (OperationType == HINIT_MAPFILE))
215 {
216 /* Verify integrity */
217 if (CmCheckRegistry((PCMHIVE)Hive, TRUE))
218 {
219 /* Cleanup allocations and fail */
220 ExFreePoolWithTag(Hive->FlusherLock, TAG_CM);
221 ExFreePoolWithTag(Hive->ViewLock, TAG_CM);
222 ExFreePoolWithTag(Hive, TAG_CM);
223 return STATUS_REGISTRY_CORRUPT;
224 }
225 }
226
227 /* Lock the hive list */
228 ExAcquirePushLockExclusive(&CmpHiveListHeadLock);
229
230 /* Insert this hive */
231 InsertHeadList(&CmpHiveListHead, &Hive->HiveList);
232
233 /* Release the lock */
234 ExReleasePushLock(&CmpHiveListHeadLock);
235
236 /* Return the hive and success */
237 *RegistryHive = (PCMHIVE)Hive;
238 return STATUS_SUCCESS;
239 }
240
241 NTSTATUS
242 NTAPI
243 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,
244 IN PCWSTR Extension OPTIONAL,
245 OUT PHANDLE Primary,
246 OUT PHANDLE Log,
247 OUT PULONG PrimaryDisposition,
248 OUT PULONG LogDisposition,
249 IN BOOLEAN CreateAllowed,
250 IN BOOLEAN MarkAsSystemHive,
251 IN BOOLEAN NoBuffering,
252 OUT PULONG ClusterSize OPTIONAL)
253 {
254 HANDLE EventHandle;
255 PKEVENT Event;
256 NTSTATUS Status;
257 UNICODE_STRING FullName, ExtensionName;
258 PWCHAR NameBuffer;
259 USHORT Length;
260 OBJECT_ATTRIBUTES ObjectAttributes;
261 IO_STATUS_BLOCK IoStatusBlock;
262 ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags;
263 USHORT CompressionState;
264 FILE_STANDARD_INFORMATION FileInformation;
265 FILE_FS_SIZE_INFORMATION FsSizeInformation;
266
267 /* Create event */
268 Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event);
269 if (!NT_SUCCESS(Status)) return Status;
270
271 /* Initialize the full name */
272 RtlInitEmptyUnicodeString(&FullName, NULL, 0);
273 Length = BaseName->Length;
274
275 /* Check if we have an extension */
276 if (Extension)
277 {
278 /* Update the name length */
279 Length += (USHORT)wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
280
281 /* Allocate the buffer for the full name */
282 NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
283 if (!NameBuffer)
284 {
285 /* Fail */
286 ObDereferenceObject(Event);
287 ZwClose(EventHandle);
288 return STATUS_NO_MEMORY;
289 }
290
291 /* Build the full name */
292 FullName.Buffer = NameBuffer;
293 FullName.MaximumLength = Length;
294 RtlAppendUnicodeStringToString(&FullName, BaseName);
295 }
296 else
297 {
298 /* The base name is the full name */
299 FullName = *BaseName;
300 NameBuffer = NULL;
301 }
302
303 /* Initialize the attributes */
304 InitializeObjectAttributes(&ObjectAttributes,
305 &FullName,
306 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
307 NULL,
308 NULL);
309
310 /* Check if we can create the hive */
311 if ((CreateAllowed) && !(CmpShareSystemHives))
312 {
313 /* Open only or create */
314 CreateDisposition = FILE_OPEN_IF;
315 }
316 else
317 {
318 /* Open only */
319 CreateDisposition = FILE_OPEN;
320 }
321
322 /* Setup the flags */
323 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot
324 IoFlags = //FILE_OPEN_FOR_BACKUP_INTENT |
325 FILE_NO_COMPRESSION |
326 FILE_RANDOM_ACCESS |
327 (NoBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0);
328
329 /* Set share and access modes */
330 if ((CmpMiniNTBoot) && (CmpShareSystemHives))
331 {
332 /* We're on Live CD or otherwise sharing */
333 DesiredAccess = FILE_READ_DATA;
334 ShareMode = FILE_SHARE_READ;
335 }
336 else
337 {
338 /* We want to write exclusively */
339 ShareMode = 0;
340 DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA;
341 }
342
343 /* Default attributes */
344 AttributeFlags = FILE_ATTRIBUTE_NORMAL;
345
346 /* Now create the file */
347 Status = ZwCreateFile(Primary,
348 DesiredAccess | SYNCHRONIZE,
349 &ObjectAttributes,
350 &IoStatusBlock,
351 NULL,
352 AttributeFlags,
353 ShareMode,
354 CreateDisposition,
355 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags,
356 NULL,
357 0);
358 /* Check if anything failed until now */
359 if (!NT_SUCCESS(Status))
360 {
361 /* Close handles and free buffers */
362 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
363 ObDereferenceObject(Event);
364 ZwClose(EventHandle);
365 DPRINT1("ZwCreateFile failed : %lx.\n", Status);
366 *Primary = NULL;
367 return Status;
368 }
369
370 if (MarkAsSystemHive)
371 {
372 /* We opened it, mark it as a system hive */
373 Status = ZwFsControlFile(*Primary,
374 EventHandle,
375 NULL,
376 NULL,
377 &IoStatusBlock,
378 FSCTL_MARK_AS_SYSTEM_HIVE,
379 NULL,
380 0,
381 NULL,
382 0);
383 if (Status == STATUS_PENDING)
384 {
385 /* Wait for completion */
386 KeWaitForSingleObject(Event,
387 Executive,
388 KernelMode,
389 FALSE,
390 NULL);
391 Status = IoStatusBlock.Status;
392 }
393
394 /* If we don't support it, ignore the failure */
395 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
396
397 if (!NT_SUCCESS(Status))
398 {
399 /* Close handles and free buffers */
400 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
401 ObDereferenceObject(Event);
402 ZwClose(EventHandle);
403 ZwClose(*Primary);
404 *Primary = NULL;
405 return Status;
406 }
407 }
408
409 /* Disable compression */
410 CompressionState = 0;
411 Status = ZwFsControlFile(*Primary,
412 EventHandle,
413 NULL,
414 NULL,
415 &IoStatusBlock,
416 FSCTL_SET_COMPRESSION,
417 &CompressionState,
418 sizeof(CompressionState),
419 NULL,
420 0);
421 if (Status == STATUS_PENDING)
422 {
423 /* Wait for completion */
424 KeWaitForSingleObject(Event,
425 Executive,
426 KernelMode,
427 FALSE,
428 NULL);
429 }
430
431 /* Get the disposition */
432 *PrimaryDisposition = (ULONG)IoStatusBlock.Information;
433 if (IoStatusBlock.Information != FILE_CREATED)
434 {
435 /* Check how large the file is */
436 Status = ZwQueryInformationFile(*Primary,
437 &IoStatusBlock,
438 &FileInformation,
439 sizeof(FileInformation),
440 FileStandardInformation);
441 if (NT_SUCCESS(Status))
442 {
443 /* Check if it's 0 bytes */
444 if (!FileInformation.EndOfFile.QuadPart)
445 {
446 /* Assume it's a new file */
447 *PrimaryDisposition = FILE_CREATED;
448 }
449 }
450 }
451
452 /* Check if the caller wants cluster size returned */
453 if (ClusterSize)
454 {
455 /* Query it */
456 Status = ZwQueryVolumeInformationFile(*Primary,
457 &IoStatusBlock,
458 &FsSizeInformation,
459 sizeof(FsSizeInformation),
460 FileFsSizeInformation);
461 if (!NT_SUCCESS(Status))
462 {
463 /* Close handles and free buffers */
464 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
465 ObDereferenceObject(Event);
466 ZwClose(EventHandle);
467 return Status;
468 }
469
470 /* Check if the sector size is invalid */
471 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE)
472 {
473 /* Close handles and free buffers */
474 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
475 ObDereferenceObject(Event);
476 ZwClose(EventHandle);
477 return STATUS_CANNOT_LOAD_REGISTRY_FILE;
478 }
479
480 /* Return cluster size */
481 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE);
482 }
483
484 /* Check if we don't need to create a log file */
485 if (!Extension)
486 {
487 /* We're done, close handles */
488 ObDereferenceObject(Event);
489 ZwClose(EventHandle);
490 return STATUS_SUCCESS;
491 }
492
493 /* Check if we can create the hive */
494 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
495 if (*PrimaryDisposition == FILE_CREATED)
496 {
497 /* Over-write the existing log file, since this is a new hive */
498 CreateDisposition = FILE_SUPERSEDE;
499 }
500
501 /* Setup the name */
502 RtlInitUnicodeString(&ExtensionName, Extension);
503 RtlAppendUnicodeStringToString(&FullName, &ExtensionName);
504
505 /* Initialize the attributes */
506 InitializeObjectAttributes(&ObjectAttributes,
507 &FullName,
508 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
509 NULL,
510 NULL);
511
512 /* Setup the flags */
513 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
514
515 /* Check if this is a log file */
516 if (!_wcsnicmp(Extension, L".log", 4))
517 {
518 /* Hide log files */
519 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN;
520 }
521
522 /* Now create the file */
523 Status = ZwCreateFile(Log,
524 DesiredAccess,
525 &ObjectAttributes,
526 &IoStatusBlock,
527 NULL,
528 AttributeFlags,
529 ShareMode,
530 CreateDisposition,
531 IoFlags,
532 NULL,
533 0);
534 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
535 {
536 /* We opened it, mark it as a system hive */
537 Status = ZwFsControlFile(*Log,
538 EventHandle,
539 NULL,
540 NULL,
541 &IoStatusBlock,
542 FSCTL_MARK_AS_SYSTEM_HIVE,
543 NULL,
544 0,
545 NULL,
546 0);
547 if (Status == STATUS_PENDING)
548 {
549 /* Wait for completion */
550 KeWaitForSingleObject(Event,
551 Executive,
552 KernelMode,
553 FALSE,
554 NULL);
555 Status = IoStatusBlock.Status;
556 }
557
558 /* If we don't support it, ignore the failure */
559 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS;
560
561 /* If we failed, close the handle */
562 if (!NT_SUCCESS(Status)) ZwClose(*Log);
563 }
564
565 /* Check if anything failed until now */
566 if (!NT_SUCCESS(Status))
567 {
568 /* Clear the handle */
569 *Log = NULL;
570 }
571 else
572 {
573 /* Disable compression */
574 Status = ZwFsControlFile(*Log,
575 EventHandle,
576 NULL,
577 NULL,
578 &IoStatusBlock,
579 FSCTL_SET_COMPRESSION,
580 &CompressionState,
581 sizeof(CompressionState),
582 NULL,
583 0);
584 if (Status == STATUS_PENDING)
585 {
586 /* Wait for completion */
587 KeWaitForSingleObject(Event,
588 Executive,
589 KernelMode,
590 FALSE,
591 NULL);
592 }
593
594 /* Return the disposition */
595 *LogDisposition = (ULONG)IoStatusBlock.Information;
596 }
597
598 /* We're done, close handles and free buffers */
599 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM);
600 ObDereferenceObject(Event);
601 ZwClose(EventHandle);
602 return STATUS_SUCCESS;
603 }