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