[CMAKE]
[reactos.git] / ntoskrnl / io / iomgr / arcname.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/arcname.c
5 * PURPOSE: ARC Path Initialization Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
20 PCHAR IoLoaderArcBootDeviceName;
21
22 /* FUNCTIONS *****************************************************************/
23
24 NTSTATUS
25 INIT_FUNCTION
26 NTAPI
27 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock
28 );
29
30 NTSTATUS
31 INIT_FUNCTION
32 NTAPI
33 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
34 IN BOOLEAN SingleDisk,
35 IN PBOOLEAN FoundBoot
36 );
37
38 NTSTATUS
39 INIT_FUNCTION
40 NTAPI
41 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
42 {
43 PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
44 CHAR Buffer[128];
45 ANSI_STRING ArcSystemString, ArcString;
46 BOOLEAN SingleDisk;
47 ULONG Length;
48 NTSTATUS Status;
49 BOOLEAN FoundBoot = FALSE;
50
51 /* Check if we only have one disk on the machine */
52 SingleDisk = ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
53 (&ArcDiskInfo->DiskSignatureListHead);
54
55 /* Create the global HAL partition name */
56 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
57 RtlInitAnsiString(&ArcString, Buffer);
58 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
59
60 /* Create the global system partition name */
61 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
62 RtlInitAnsiString(&ArcString, Buffer);
63 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
64
65 /* Allocate memory for the string */
66 Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
67 IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
68 Length,
69 TAG_IO);
70 if (IoLoaderArcBootDeviceName)
71 {
72 /* Copy the name */
73 RtlCopyMemory(IoLoaderArcBootDeviceName,
74 LoaderBlock->ArcBootDeviceName,
75 Length);
76 }
77
78 /* Check if we only found a disk, but we're booting from CD-ROM */
79 if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
80 {
81 /* Then disable single-disk mode, since there's a CD drive out there */
82 SingleDisk = FALSE;
83 }
84
85 /* Build the boot strings */
86 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
87
88 /* FIXME: Handle IoRemoteBootClient here and create appropriate symbolic link */
89
90 /* Loop every disk and try to find boot disk */
91 Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot);
92 /* If it succeed but we didn't find boot device, try to browse Cds */
93 if (NT_SUCCESS(Status) && !FoundBoot)
94 {
95 Status = IopCreateArcNamesCd(LoaderBlock);
96 }
97
98 /* Return success */
99 return Status;
100 }
101
102 NTSTATUS
103 INIT_FUNCTION
104 NTAPI
105 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
106 {
107 PIRP Irp;
108 KEVENT Event;
109 NTSTATUS Status;
110 PLIST_ENTRY NextEntry;
111 PFILE_OBJECT FileObject;
112 PDEVICE_OBJECT DeviceObject;
113 LARGE_INTEGER StartingOffset;
114 IO_STATUS_BLOCK IoStatusBlock;
115 PULONG PartitionBuffer = NULL;
116 CHAR Buffer[128], ArcBuffer[128];
117 BOOLEAN NotEnabledPresent = FALSE;
118 STORAGE_DEVICE_NUMBER DeviceNumber;
119 ANSI_STRING DeviceStringA, ArcNameStringA;
120 PWSTR SymbolicLinkList, lSymbolicLinkList;
121 PARC_DISK_SIGNATURE ArcDiskSignature = NULL;
122 UNICODE_STRING DeviceStringW, ArcNameStringW;
123 ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0;
124 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
125
126 /* Get all the Cds present in the system */
127 CdRomCount = IoGetConfigurationInformation()->CdRomCount;
128
129 /* Get enabled Cds and check if result matches
130 * For the record, enabled Cds (or even disk) are Cds/disks
131 * that have been successfully handled by MountMgr driver
132 * and that already own their device name. This is the "new" way
133 * to handle them, that came with NT5.
134 * Currently, Windows 2003 provides an arc names creation based
135 * on both enabled drives and not enabled drives (lack from
136 * the driver).
137 * Given the current ReactOS state, that's good for us.
138 * To sum up, this is NOT a hack or whatsoever.
139 */
140 Status = IopFetchConfigurationInformation(&SymbolicLinkList,
141 GUID_DEVINTERFACE_CDROM,
142 CdRomCount,
143 &EnabledDisks);
144 if (!NT_SUCCESS(Status))
145 {
146 NotEnabledPresent = TRUE;
147 }
148 /* Save symbolic link list address in order to free it after */
149 lSymbolicLinkList = SymbolicLinkList;
150 /* For the moment, we won't fail */
151 Status = STATUS_SUCCESS;
152
153 /* Browse all the ARC devices trying to find the one matching boot device */
154 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
155 NextEntry != &ArcDiskInformation->DiskSignatureListHead;
156 NextEntry = NextEntry->Flink)
157 {
158 ArcDiskSignature = CONTAINING_RECORD(NextEntry,
159 ARC_DISK_SIGNATURE,
160 ListEntry);
161
162 if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0)
163 {
164 break;
165 }
166
167 ArcDiskSignature = NULL;
168 }
169
170 /* Not found... Not booting from a Cd */
171 if (!ArcDiskSignature)
172 {
173 DPRINT("Failed finding a cd that could match current boot device\n");
174 goto Cleanup;
175 }
176
177 /* Allocate needed space for reading Cd */
178 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO);
179 if (!PartitionBuffer)
180 {
181 DPRINT("Failed allocating resources!\n");
182 /* Here, we fail, BUT we return success, some Microsoft joke */
183 goto Cleanup;
184 }
185
186 /* If we have more enabled Cds, take that into account */
187 if (EnabledDisks > CdRomCount)
188 {
189 CdRomCount = EnabledDisks;
190 }
191
192 /* If we'll have to browse for none enabled Cds, fix higher count */
193 if (NotEnabledPresent && !EnabledDisks)
194 {
195 CdRomCount += 5;
196 }
197
198 /* Finally, if in spite of all that work, we still don't have Cds, leave */
199 if (!CdRomCount)
200 {
201 goto Cleanup;
202 }
203
204 /* Start browsing Cds */
205 for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++)
206 {
207 /* Check if we have an enabled disk */
208 if (SymbolicLinkList && *SymbolicLinkList != UNICODE_NULL)
209 {
210 /* Create its device name using first symbolic link */
211 RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
212 /* Then, update symbolic links list */
213 lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
214
215 /* Get its associated device object and file object */
216 Status = IoGetDeviceObjectPointer(&DeviceStringW,
217 FILE_READ_ATTRIBUTES,
218 &FileObject,
219 &DeviceObject);
220 /* Failure? Good bye! */
221 if (!NT_SUCCESS(Status))
222 {
223 goto Cleanup;
224 }
225
226 /* Now, we'll ask the device its device number */
227 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
228 DeviceObject,
229 NULL,
230 0,
231 &DeviceNumber,
232 sizeof(STORAGE_DEVICE_NUMBER),
233 FALSE,
234 &Event,
235 &IoStatusBlock);
236 /* Failure? Good bye! */
237 if (!Irp)
238 {
239 /* Dereference file object before leaving */
240 ObDereferenceObject(FileObject);
241 Status = STATUS_INSUFFICIENT_RESOURCES;
242 goto Cleanup;
243 }
244
245 /* Call the driver, and wait for it if needed */
246 KeInitializeEvent(&Event, NotificationEvent, FALSE);
247 Status = IoCallDriver(DeviceObject, Irp);
248 if (Status == STATUS_PENDING)
249 {
250 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
251 Status = IoStatusBlock.Status;
252 }
253 if (!NT_SUCCESS(Status))
254 {
255 ObDereferenceObject(FileObject);
256 goto Cleanup;
257 }
258
259 /* Finally, build proper device name */
260 sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber);
261 RtlInitAnsiString(&DeviceStringA, Buffer);
262 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
263 if (!NT_SUCCESS(Status))
264 {
265 ObDereferenceObject(FileObject);
266 goto Cleanup;
267 }
268 }
269 else
270 {
271 /* Create device name for the cd */
272 sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++);
273 RtlInitAnsiString(&DeviceStringA, Buffer);
274 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
275 if (!NT_SUCCESS(Status))
276 {
277 goto Cleanup;
278 }
279
280 /* Get its device object */
281 Status = IoGetDeviceObjectPointer(&DeviceStringW,
282 FILE_READ_ATTRIBUTES,
283 &FileObject,
284 &DeviceObject);
285 if (!NT_SUCCESS(Status))
286 {
287 RtlFreeUnicodeString(&DeviceStringW);
288 goto Cleanup;
289 }
290 }
291
292 /* Initiate data for reading cd and compute checksum */
293 StartingOffset.QuadPart = 0x8000;
294 CheckSum = 0;
295 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
296 DeviceObject,
297 PartitionBuffer,
298 2048,
299 &StartingOffset,
300 &Event,
301 &IoStatusBlock);
302 if (Irp)
303 {
304 /* Call the driver, and wait for it if needed */
305 KeInitializeEvent(&Event, NotificationEvent, FALSE);
306 Status = IoCallDriver(DeviceObject, Irp);
307 if (Status == STATUS_PENDING)
308 {
309 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
310 Status = IoStatusBlock.Status;
311 }
312
313 /* Reading succeed, compute checksum by adding data, 2048 bytes checksum */
314 if (NT_SUCCESS(Status))
315 {
316 for (i = 0; i < 2048 / sizeof(ULONG); i++)
317 {
318 CheckSum += PartitionBuffer[i];
319 }
320 }
321 }
322
323 /* Dereference file object */
324 ObDereferenceObject(FileObject);
325
326 /* If checksums are matching, we have the proper cd */
327 if (CheckSum + ArcDiskSignature->CheckSum == 0)
328 {
329 /* Create ARC name */
330 sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
331 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
332 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
333 if (NT_SUCCESS(Status))
334 {
335 /* Create symbolic link */
336 IoCreateSymbolicLink(&ArcNameStringW, &DeviceStringW);
337 RtlFreeUnicodeString(&ArcNameStringW);
338 DPRINT1("Boot device found\n");
339 }
340
341 /* And quit, whatever happens */
342 RtlFreeUnicodeString(&DeviceStringW);
343 goto Cleanup;
344 }
345
346 /* Free string before trying another disk */
347 RtlFreeUnicodeString(&DeviceStringW);
348 }
349
350 Cleanup:
351 if (PartitionBuffer)
352 {
353 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
354 }
355
356 if (SymbolicLinkList)
357 {
358 ExFreePool(SymbolicLinkList);
359 }
360
361 return Status;
362 }
363
364 NTSTATUS
365 INIT_FUNCTION
366 NTAPI
367 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
368 IN BOOLEAN SingleDisk,
369 IN PBOOLEAN FoundBoot)
370 {
371 PIRP Irp;
372 PVOID Data;
373 KEVENT Event;
374 NTSTATUS Status;
375 PLIST_ENTRY NextEntry;
376 PFILE_OBJECT FileObject;
377 DISK_GEOMETRY DiskGeometry;
378 PDEVICE_OBJECT DeviceObject;
379 LARGE_INTEGER StartingOffset;
380 PULONG PartitionBuffer = NULL;
381 IO_STATUS_BLOCK IoStatusBlock;
382 CHAR Buffer[128], ArcBuffer[128];
383 BOOLEAN NotEnabledPresent = FALSE;
384 STORAGE_DEVICE_NUMBER DeviceNumber;
385 PARC_DISK_SIGNATURE ArcDiskSignature;
386 PWSTR SymbolicLinkList, lSymbolicLinkList;
387 PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
388 UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW;
389 ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0;
390 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
391 ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA;
392
393 /* Initialise device number */
394 DeviceNumber.DeviceNumber = 0xFFFFFFFF;
395 /* Get all the disks present in the system */
396 DiskCount = IoGetConfigurationInformation()->DiskCount;
397
398 /* Get enabled disks and check if result matches */
399 Status = IopFetchConfigurationInformation(&SymbolicLinkList,
400 GUID_DEVINTERFACE_DISK,
401 DiskCount,
402 &EnabledDisks);
403 if (!NT_SUCCESS(Status))
404 {
405 NotEnabledPresent = TRUE;
406 }
407
408 /* Save symbolic link list address in order to free it after */
409 lSymbolicLinkList = SymbolicLinkList;
410
411 /* Build the boot strings */
412 RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
413 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
414
415 /* If we have more enabled disks, take that into account */
416 if (EnabledDisks > DiskCount)
417 {
418 DiskCount = EnabledDisks;
419 }
420
421 /* If we'll have to browse for none enabled disks, fix higher count */
422 if (NotEnabledPresent && !EnabledDisks)
423 {
424 DiskCount += 20;
425 }
426
427 /* Finally, if in spite of all that work, we still don't have disks, leave */
428 if (!DiskCount)
429 {
430 goto Cleanup;
431 }
432
433 /* Start browsing disks */
434 for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
435 {
436 /* Check if we have an enabled disk */
437 if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
438 {
439 /* Create its device name using first symbolic link */
440 RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
441 /* Then, update symbolic links list */
442 lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
443
444 /* Get its associated device object and file object */
445 Status = IoGetDeviceObjectPointer(&DeviceStringW,
446 FILE_READ_ATTRIBUTES,
447 &FileObject,
448 &DeviceObject);
449 if (NT_SUCCESS(Status))
450 {
451 /* Now, we'll ask the device its device number */
452 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
453 DeviceObject,
454 NULL,
455 0,
456 &DeviceNumber,
457 sizeof(STORAGE_DEVICE_NUMBER),
458 FALSE,
459 &Event,
460 &IoStatusBlock);
461 /* Missing resources is a shame... No need to go farther */
462 if (!Irp)
463 {
464 ObDereferenceObject(FileObject);
465 Status = STATUS_INSUFFICIENT_RESOURCES;
466 goto Cleanup;
467 }
468
469 /* Call the driver, and wait for it if needed */
470 KeInitializeEvent(&Event, NotificationEvent, FALSE);
471 Status = IoCallDriver(DeviceObject, Irp);
472 if (Status == STATUS_PENDING)
473 {
474 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
475 Status = IoStatusBlock.Status;
476 }
477
478 /* If we didn't get the appriopriate data, just skip that disk */
479 if (!NT_SUCCESS(Status))
480 {
481 ObDereferenceObject(FileObject);
482 continue;
483 }
484 }
485
486 /* End of enabled disks enumeration */
487 if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL)
488 {
489 /* No enabled disk worked, reset field */
490 if (DeviceNumber.DeviceNumber == 0xFFFFFFFF)
491 {
492 DeviceNumber.DeviceNumber = 0;
493 }
494
495 /* Update disk number to enable the following not enabled disks */
496 if (DeviceNumber.DeviceNumber > DiskNumber)
497 {
498 DiskNumber = DeviceNumber.DeviceNumber;
499 }
500
501 /* Increase a bit more */
502 DiskCount = DiskNumber + 20;
503 }
504 }
505 else
506 {
507 /* Create device name for the disk */
508 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
509 RtlInitAnsiString(&DeviceStringA, Buffer);
510 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
511 if (!NT_SUCCESS(Status))
512 {
513 goto Cleanup;
514 }
515
516 /* Get its device object */
517 Status = IoGetDeviceObjectPointer(&DeviceStringW,
518 FILE_READ_ATTRIBUTES,
519 &FileObject,
520 &DeviceObject);
521
522 RtlFreeUnicodeString(&DeviceStringW);
523 /* This is a security measure, to ensure DiskNumber will be used */
524 DeviceNumber.DeviceNumber = 0xFFFFFFFF;
525 }
526
527 /* Something failed somewhere earlier, just skip the disk */
528 if (!NT_SUCCESS(Status))
529 {
530 continue;
531 }
532
533 /* Let's ask the disk for its geometry */
534 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
535 DeviceObject,
536 NULL,
537 0,
538 &DiskGeometry,
539 sizeof(DISK_GEOMETRY),
540 FALSE,
541 &Event,
542 &IoStatusBlock);
543 /* Missing resources is a shame... No need to go farther */
544 if (!Irp)
545 {
546 ObDereferenceObject(FileObject);
547 Status = STATUS_INSUFFICIENT_RESOURCES;
548 goto Cleanup;
549 }
550
551 /* Call the driver, and wait for it if needed */
552 KeInitializeEvent(&Event, NotificationEvent, FALSE);
553 Status = IoCallDriver(DeviceObject, Irp);
554 if (Status == STATUS_PENDING)
555 {
556 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
557 Status = IoStatusBlock.Status;
558 }
559 /* Failure, skip disk */
560 if (!NT_SUCCESS(Status))
561 {
562 ObDereferenceObject(FileObject);
563 continue;
564 }
565
566 /* Read the partition table */
567 Status = IoReadPartitionTableEx(DeviceObject,
568 &DriveLayout);
569 if (!NT_SUCCESS(Status))
570 {
571 ObDereferenceObject(FileObject);
572 continue;
573 }
574
575 /* Ensure we have at least 512 bytes per sector */
576 if (DiskGeometry.BytesPerSector < 512)
577 {
578 DiskGeometry.BytesPerSector = 512;
579 }
580
581 /* Check MBR type against EZ Drive type */
582 StartingOffset.QuadPart = 0;
583 HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data);
584 if (Data)
585 {
586 /* If MBR is of the EZ Drive type, we'll read after it */
587 StartingOffset.QuadPart = DiskGeometry.BytesPerSector;
588 ExFreePool(Data);
589 }
590
591 /* Allocate for reading enough data for checksum */
592 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO);
593 if (!PartitionBuffer)
594 {
595 ObDereferenceObject(FileObject);
596 Status = STATUS_INSUFFICIENT_RESOURCES;
597 goto Cleanup;
598 }
599
600 /* Read a sector for computing checksum */
601 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
602 DeviceObject,
603 PartitionBuffer,
604 DiskGeometry.BytesPerSector,
605 &StartingOffset,
606 &Event,
607 &IoStatusBlock);
608 if (!Irp)
609 {
610 ObDereferenceObject(FileObject);
611 Status = STATUS_INSUFFICIENT_RESOURCES;
612 goto Cleanup;
613 }
614
615 /* Call the driver to perform reading */
616 KeInitializeEvent(&Event, NotificationEvent, FALSE);
617 Status = IoCallDriver(DeviceObject, Irp);
618 if (Status == STATUS_PENDING)
619 {
620 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
621 Status = IoStatusBlock.Status;
622 }
623 if (!NT_SUCCESS(Status))
624 {
625 ExFreePool(DriveLayout);
626 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
627 ObDereferenceObject(FileObject);
628 continue;
629 }
630
631 ObDereferenceObject(FileObject);
632
633 /* Calculate checksum, that's an easy computation, just adds read data */
634 for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++)
635 {
636 CheckSum += PartitionBuffer[i];
637 }
638
639 /* Browse each ARC disk */
640 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
641 NextEntry != &ArcDiskInformation->DiskSignatureListHead;
642 NextEntry = NextEntry->Flink)
643 {
644 ArcDiskSignature = CONTAINING_RECORD(NextEntry,
645 ARC_DISK_SIGNATURE,
646 ListEntry);
647
648 /* If they matches, ie
649 * - There's only one disk for both BIOS and detected/enabled
650 * - Signatures are matching
651 * - Checksums are matching
652 * - This is MBR
653 */
654 if (((SingleDisk && DiskCount == 1) ||
655 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) &&
656 (ArcDiskSignature->CheckSum + CheckSum == 0))) &&
657 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
658 {
659 /* Create device name */
660 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != 0xFFFFFFFF) ? DeviceNumber.DeviceNumber : DiskNumber);
661 RtlInitAnsiString(&DeviceStringA, Buffer);
662 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
663 if (!NT_SUCCESS(Status))
664 {
665 goto Cleanup;
666 }
667
668 /* Create ARC name */
669 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
670 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
671 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
672 if (!NT_SUCCESS(Status))
673 {
674 RtlFreeUnicodeString(&DeviceStringW);
675 goto Cleanup;
676 }
677
678 /* Link both */
679 IoCreateSymbolicLink(&ArcNameStringW, &DeviceStringW);
680
681 /* And release resources */
682 RtlFreeUnicodeString(&ArcNameStringW);
683 RtlFreeUnicodeString(&DeviceStringW);
684
685 /* Now, browse for every partition */
686 for (i = 1; i <= DriveLayout->PartitionCount; i++)
687 {
688 /* Create device name */
689 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != 0xFFFFFFFF) ? DeviceNumber.DeviceNumber : DiskNumber, i);
690 RtlInitAnsiString(&DeviceStringA, Buffer);
691 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
692 if (!NT_SUCCESS(Status))
693 {
694 goto Cleanup;
695 }
696
697 /* Create partial ARC name */
698 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i);
699 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
700
701 /* Is that boot device? */
702 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
703 {
704 DPRINT("Found boot device\n");
705 *FoundBoot = TRUE;
706 }
707
708 /* Is that system partition? */
709 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
710 {
711 /* Create HAL path name */
712 RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName);
713 Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE);
714 if (!NT_SUCCESS(Status))
715 {
716 RtlFreeUnicodeString(&DeviceStringW);
717 goto Cleanup;
718 }
719
720 /* Then store those information to registry */
721 IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW);
722 RtlFreeUnicodeString(&HalPathStringW);
723 }
724
725 /* Create complete ARC name */
726 sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i);
727 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
728 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
729 if (!NT_SUCCESS(Status))
730 {
731 RtlFreeUnicodeString(&DeviceStringW);
732 goto Cleanup;
733 }
734
735 /* Link device name & ARC name */
736 IoCreateSymbolicLink(&ArcNameStringW, &DeviceStringW);
737
738 /* Release strings */
739 RtlFreeUnicodeString(&ArcNameStringW);
740 RtlFreeUnicodeString(&DeviceStringW);
741 }
742 }
743 else
744 {
745 /* In case there's a valid partition, a matching signature,
746 BUT a none matching checksum, or there's a duplicate
747 signature, or even worse a virus played with partition
748 table */
749 if (ArcDiskSignature->Signature == Signature &&
750 (ArcDiskSignature->CheckSum + CheckSum != 0) &&
751 ArcDiskSignature->ValidPartitionTable)
752 {
753 DPRINT("Be careful, or you have a duplicate disk signature, or a virus altered your MBR!\n");
754 }
755 }
756 }
757
758 /* Release memory before jumping to next item */
759 ExFreePool(DriveLayout);
760 DriveLayout = NULL;
761 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
762 PartitionBuffer = NULL;
763 }
764
765 Status = STATUS_SUCCESS;
766
767 Cleanup:
768 if (SymbolicLinkList)
769 {
770 ExFreePool(SymbolicLinkList);
771 }
772
773 if (DriveLayout)
774 {
775 ExFreePool(DriveLayout);
776 }
777
778 if (PartitionBuffer)
779 {
780 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
781 }
782
783 return Status;
784 }
785
786 NTSTATUS
787 NTAPI
788 INIT_FUNCTION
789 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
790 OUT PANSI_STRING NtBootPath)
791 {
792 OBJECT_ATTRIBUTES ObjectAttributes;
793 NTSTATUS Status;
794 CHAR Buffer[256], AnsiBuffer[256];
795 WCHAR ArcNameBuffer[64];
796 ANSI_STRING TargetString, ArcString, TempString;
797 UNICODE_STRING LinkName, TargetName, ArcName;
798 HANDLE LinkHandle;
799
800 /* Create the Unicode name for the current ARC boot device */
801 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
802 RtlInitAnsiString(&TargetString, Buffer);
803 Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
804 if (!NT_SUCCESS(Status)) return FALSE;
805
806 /* Initialize the attributes and open the link */
807 InitializeObjectAttributes(&ObjectAttributes,
808 &TargetName,
809 OBJ_CASE_INSENSITIVE,
810 NULL,
811 NULL);
812 Status = NtOpenSymbolicLinkObject(&LinkHandle,
813 SYMBOLIC_LINK_ALL_ACCESS,
814 &ObjectAttributes);
815 if (!NT_SUCCESS(Status))
816 {
817 /* We failed, free the string */
818 RtlFreeUnicodeString(&TargetName);
819 return FALSE;
820 }
821
822 /* Query the current \\SystemRoot */
823 ArcName.Buffer = ArcNameBuffer;
824 ArcName.Length = 0;
825 ArcName.MaximumLength = sizeof(ArcNameBuffer);
826 Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
827 if (!NT_SUCCESS(Status))
828 {
829 /* We failed, free the string */
830 RtlFreeUnicodeString(&TargetName);
831 return FALSE;
832 }
833
834 /* Convert it to Ansi */
835 ArcString.Buffer = AnsiBuffer;
836 ArcString.Length = 0;
837 ArcString.MaximumLength = sizeof(AnsiBuffer);
838 Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
839 AnsiBuffer[ArcString.Length] = ANSI_NULL;
840
841 /* Close the link handle and free the name */
842 ObCloseHandle(LinkHandle, KernelMode);
843 RtlFreeUnicodeString(&TargetName);
844
845 /* Setup the system root name again */
846 RtlInitAnsiString(&TempString, "\\SystemRoot");
847 Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
848 if (!NT_SUCCESS(Status)) return FALSE;
849
850 /* Open the symbolic link for it */
851 InitializeObjectAttributes(&ObjectAttributes,
852 &LinkName,
853 OBJ_CASE_INSENSITIVE,
854 NULL,
855 NULL);
856 Status = NtOpenSymbolicLinkObject(&LinkHandle,
857 SYMBOLIC_LINK_ALL_ACCESS,
858 &ObjectAttributes);
859 if (!NT_SUCCESS(Status)) return FALSE;
860
861 /* Destroy it */
862 NtMakeTemporaryObject(LinkHandle);
863 ObCloseHandle(LinkHandle, KernelMode);
864
865 /* Now create the new name for it */
866 sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
867
868 /* Copy it into the passed parameter and null-terminate it */
869 RtlCopyString(NtBootPath, &ArcString);
870 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
871
872 /* Setup the Unicode-name for the new symbolic link value */
873 RtlInitAnsiString(&TargetString, Buffer);
874 InitializeObjectAttributes(&ObjectAttributes,
875 &LinkName,
876 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
877 NULL,
878 NULL);
879 Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
880 if (!NT_SUCCESS(Status)) return FALSE;
881
882 /* Create it */
883 Status = NtCreateSymbolicLinkObject(&LinkHandle,
884 SYMBOLIC_LINK_ALL_ACCESS,
885 &ObjectAttributes,
886 &ArcName);
887
888 /* Free all the strings and close the handle and return success */
889 RtlFreeUnicodeString(&ArcName);
890 RtlFreeUnicodeString(&LinkName);
891 ObCloseHandle(LinkHandle, KernelMode);
892 return TRUE;
893 }
894
895 BOOLEAN
896 NTAPI
897 IopVerifyDiskSignature(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
898 IN PARC_DISK_SIGNATURE ArcDiskSignature,
899 OUT PULONG Signature)
900 {
901 /* First condition: having a valid partition table */
902 if (!ArcDiskSignature->ValidPartitionTable)
903 {
904 return FALSE;
905 }
906
907 /* If that partition table is the MBR */
908 if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)
909 {
910 /* Then check MBR signature */
911 if (DriveLayout->Mbr.Signature == ArcDiskSignature->Signature)
912 {
913 /* And return it */
914 if (Signature)
915 {
916 *Signature = DriveLayout->Mbr.Signature;
917 }
918
919 return TRUE;
920 }
921 }
922 /* If that partition table is the GPT */
923 else if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
924 {
925 /* Check we are using GPT and compare GUID */
926 if (ArcDiskSignature->IsGpt &&
927 (((PULONG)ArcDiskSignature->GptSignature)[0] == DriveLayout->Gpt.DiskId.Data1 &&
928 ((PUSHORT)ArcDiskSignature->GptSignature)[2] == DriveLayout->Gpt.DiskId.Data2 &&
929 ((PUSHORT)ArcDiskSignature->GptSignature)[3] == DriveLayout->Gpt.DiskId.Data3 &&
930 ((PULONGLONG)ArcDiskSignature->GptSignature)[1] == ((PULONGLONG)DriveLayout->Gpt.DiskId.Data4)[0]))
931 {
932 /* There's no signature to give, so we just zero output */
933 if (Signature)
934 {
935 *Signature = 0;
936 }
937 return TRUE;
938 }
939 }
940
941 /* If we fall here, it means that something went wrong, so return that */
942 return FALSE;
943 }
944
945 /* EOF */