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