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 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE); 58 59 /* Create the global system partition name */ 60 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); 61 RtlInitAnsiString(&ArcString, Buffer); 62 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE); 63 64 /* Allocate memory for the string */ 65 Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL); 66 IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool, 67 Length, 68 TAG_IO); 69 if (IoLoaderArcBootDeviceName) 70 { 71 /* Copy the name */ 72 RtlCopyMemory(IoLoaderArcBootDeviceName, 73 LoaderBlock->ArcBootDeviceName, 74 Length); 75 } 76 77 /* Check if we only found a disk, but we're booting from CD-ROM */ 78 if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom")) 79 { 80 /* Then disable single-disk mode, since there's a CD drive out there */ 81 SingleDisk = FALSE; 82 } 83 84 /* Build the boot strings */ 85 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName); 86 87 /* If we are doing remote booting */ 88 if (IoRemoteBootClient) 89 { 90 /* Yes, we have found boot device */ 91 FoundBoot = TRUE; 92 93 /* Get NT device name */ 94 RtlInitAnsiString(&LanmanRedirector, "\\Device\\LanmanRedirector"); 95 Status = RtlAnsiStringToUnicodeString(&SystemDevice, &LanmanRedirector, TRUE); 96 if (!NT_SUCCESS(Status)) 97 { 98 return Status; 99 } 100 101 /* Get ARC booting device name (in net(0) something) */ 102 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); 103 RtlInitAnsiString(&ArcString, Buffer); 104 Status = RtlAnsiStringToUnicodeString(&BootDeviceName, &ArcString, TRUE); 105 if (NT_SUCCESS(Status)) 106 { 107 /* Map ARC to NT name */ 108 IoAssignArcName(&BootDeviceName, &SystemDevice); 109 RtlFreeUnicodeString(&BootDeviceName); 110 111 /* Now, get loader path name */ 112 RtlInitAnsiString(&LoaderPathNameA, LoaderBlock->NtHalPathName); 113 Status = RtlAnsiStringToUnicodeString(&LoaderPathNameW, &LoaderPathNameA, TRUE); 114 if (!NT_SUCCESS(Status)) 115 { 116 RtlFreeUnicodeString(&SystemDevice); 117 return Status; 118 } 119 120 /* And set it has system partition */ 121 IopStoreSystemPartitionInformation(&SystemDevice, &LoaderPathNameW); 122 } 123 124 RtlFreeUnicodeString(&SystemDevice); 125 126 /* Don't quit here, even if everything went fine! 127 * We need IopCreateArcNamesDisk to properly map 128 * devices with symlinks. 129 * It will return success if the mapping process went fine 130 * even if it didn't find boot device. 131 * It won't reset boot device finding status as well. 132 */ 133 } 134 135 /* Loop every disk and try to find boot disk */ 136 Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot); 137 /* If it succeeded but we didn't find boot device, try to browse Cds */ 138 if (NT_SUCCESS(Status) && !FoundBoot) 139 { 140 Status = IopCreateArcNamesCd(LoaderBlock); 141 } 142 143 /* Return success */ 144 return Status; 145 } 146 147 CODE_SEG("INIT") 148 NTSTATUS 149 NTAPI 150 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 151 { 152 PIRP Irp; 153 KEVENT Event; 154 NTSTATUS Status; 155 PLIST_ENTRY NextEntry; 156 PFILE_OBJECT FileObject; 157 PDEVICE_OBJECT DeviceObject; 158 LARGE_INTEGER StartingOffset; 159 IO_STATUS_BLOCK IoStatusBlock; 160 PULONG PartitionBuffer = NULL; 161 CHAR Buffer[128], ArcBuffer[128]; 162 BOOLEAN NotEnabledPresent = FALSE; 163 STORAGE_DEVICE_NUMBER DeviceNumber; 164 ANSI_STRING DeviceStringA, ArcNameStringA; 165 PWSTR SymbolicLinkList, lSymbolicLinkList; 166 PARC_DISK_SIGNATURE ArcDiskSignature = NULL; 167 UNICODE_STRING DeviceStringW, ArcNameStringW; 168 ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0; 169 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation; 170 171 /* Get all the Cds present in the system */ 172 CdRomCount = IoGetConfigurationInformation()->CdRomCount; 173 174 /* Get enabled Cds and check if result matches 175 * For the record, enabled Cds (or even disk) are Cds/disks 176 * that have been successfully handled by MountMgr driver 177 * and that already own their device name. This is the "new" way 178 * to handle them, that came with NT5. 179 * Currently, Windows 2003 provides an ARC names creation based 180 * on both enabled drives and not enabled drives (lack from 181 * the driver). 182 * Given the current ReactOS state, that's good for us. 183 * To sum up, this is NOT a hack or whatsoever. 184 */ 185 Status = IopFetchConfigurationInformation(&SymbolicLinkList, 186 GUID_DEVINTERFACE_CDROM, 187 CdRomCount, 188 &EnabledDisks); 189 if (!NT_SUCCESS(Status)) 190 { 191 NotEnabledPresent = TRUE; 192 } 193 /* Save symbolic link list address in order to free it after */ 194 lSymbolicLinkList = SymbolicLinkList; 195 /* For the moment, we won't fail */ 196 Status = STATUS_SUCCESS; 197 198 /* Browse all the ARC devices trying to find the one matching boot device */ 199 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; 200 NextEntry != &ArcDiskInformation->DiskSignatureListHead; 201 NextEntry = NextEntry->Flink) 202 { 203 ArcDiskSignature = CONTAINING_RECORD(NextEntry, 204 ARC_DISK_SIGNATURE, 205 ListEntry); 206 207 if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0) 208 { 209 break; 210 } 211 212 ArcDiskSignature = NULL; 213 } 214 215 /* Not found... Not booting from a Cd */ 216 if (!ArcDiskSignature) 217 { 218 DPRINT("Failed finding a cd that could match current boot device\n"); 219 goto Cleanup; 220 } 221 222 /* Allocate needed space for reading Cd */ 223 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO); 224 if (!PartitionBuffer) 225 { 226 DPRINT("Failed allocating resources!\n"); 227 /* Here, we fail, BUT we return success, some Microsoft joke */ 228 goto Cleanup; 229 } 230 231 /* If we have more enabled Cds, take that into account */ 232 if (EnabledDisks > CdRomCount) 233 { 234 CdRomCount = EnabledDisks; 235 } 236 237 /* If we'll have to browse for none enabled Cds, fix higher count */ 238 if (NotEnabledPresent && !EnabledDisks) 239 { 240 CdRomCount += 5; 241 } 242 243 /* Finally, if in spite of all that work, we still don't have Cds, leave */ 244 if (!CdRomCount) 245 { 246 goto Cleanup; 247 } 248 249 /* Start browsing Cds */ 250 for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++) 251 { 252 /* Check if we have an enabled disk */ 253 if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL) 254 { 255 /* Create its device name using first symbolic link */ 256 RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList); 257 /* Then, update symbolic links list */ 258 lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); 259 260 /* Get its associated device object and file object */ 261 Status = IoGetDeviceObjectPointer(&DeviceStringW, 262 FILE_READ_ATTRIBUTES, 263 &FileObject, 264 &DeviceObject); 265 /* Failure? Good bye! */ 266 if (!NT_SUCCESS(Status)) 267 { 268 goto Cleanup; 269 } 270 271 /* Now, we'll ask the device its device number */ 272 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, 273 DeviceObject, 274 NULL, 275 0, 276 &DeviceNumber, 277 sizeof(DeviceNumber), 278 FALSE, 279 &Event, 280 &IoStatusBlock); 281 /* Failure? Good bye! */ 282 if (!Irp) 283 { 284 /* Dereference file object before leaving */ 285 ObDereferenceObject(FileObject); 286 Status = STATUS_INSUFFICIENT_RESOURCES; 287 goto Cleanup; 288 } 289 290 /* Call the driver, and wait for it if needed */ 291 KeInitializeEvent(&Event, NotificationEvent, FALSE); 292 Status = IoCallDriver(DeviceObject, Irp); 293 if (Status == STATUS_PENDING) 294 { 295 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 296 Status = IoStatusBlock.Status; 297 } 298 if (!NT_SUCCESS(Status)) 299 { 300 ObDereferenceObject(FileObject); 301 goto Cleanup; 302 } 303 304 /* Finally, build proper device name */ 305 sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber); 306 RtlInitAnsiString(&DeviceStringA, Buffer); 307 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 308 if (!NT_SUCCESS(Status)) 309 { 310 ObDereferenceObject(FileObject); 311 goto Cleanup; 312 } 313 } 314 else 315 { 316 /* Create device name for the cd */ 317 sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++); 318 RtlInitAnsiString(&DeviceStringA, Buffer); 319 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 320 if (!NT_SUCCESS(Status)) 321 { 322 goto Cleanup; 323 } 324 325 /* Get its device object */ 326 Status = IoGetDeviceObjectPointer(&DeviceStringW, 327 FILE_READ_ATTRIBUTES, 328 &FileObject, 329 &DeviceObject); 330 if (!NT_SUCCESS(Status)) 331 { 332 RtlFreeUnicodeString(&DeviceStringW); 333 goto Cleanup; 334 } 335 } 336 337 /* Initiate data for reading cd and compute checksum */ 338 StartingOffset.QuadPart = 0x8000; 339 CheckSum = 0; 340 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 341 DeviceObject, 342 PartitionBuffer, 343 2048, 344 &StartingOffset, 345 &Event, 346 &IoStatusBlock); 347 if (Irp) 348 { 349 /* Call the driver, and wait for it if needed */ 350 KeInitializeEvent(&Event, NotificationEvent, FALSE); 351 Status = IoCallDriver(DeviceObject, Irp); 352 if (Status == STATUS_PENDING) 353 { 354 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 355 Status = IoStatusBlock.Status; 356 } 357 358 /* If reading succeeded, compute checksum by adding data, 2048 bytes checksum */ 359 if (NT_SUCCESS(Status)) 360 { 361 for (i = 0; i < 2048 / sizeof(ULONG); i++) 362 { 363 CheckSum += PartitionBuffer[i]; 364 } 365 } 366 } 367 368 /* Dereference file object */ 369 ObDereferenceObject(FileObject); 370 371 /* If checksums are matching, we have the proper cd */ 372 if (CheckSum + ArcDiskSignature->CheckSum == 0) 373 { 374 /* Create ARC name */ 375 sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); 376 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 377 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); 378 if (NT_SUCCESS(Status)) 379 { 380 /* Create symbolic link */ 381 IoAssignArcName(&ArcNameStringW, &DeviceStringW); 382 RtlFreeUnicodeString(&ArcNameStringW); 383 DPRINT("Boot device found\n"); 384 } 385 386 /* And quit, whatever happens */ 387 RtlFreeUnicodeString(&DeviceStringW); 388 goto Cleanup; 389 } 390 391 /* Free string before trying another disk */ 392 RtlFreeUnicodeString(&DeviceStringW); 393 } 394 395 Cleanup: 396 if (PartitionBuffer) 397 { 398 ExFreePoolWithTag(PartitionBuffer, TAG_IO); 399 } 400 401 if (SymbolicLinkList) 402 { 403 ExFreePool(SymbolicLinkList); 404 } 405 406 return Status; 407 } 408 409 CODE_SEG("INIT") 410 NTSTATUS 411 NTAPI 412 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 413 IN BOOLEAN SingleDisk, 414 OUT PBOOLEAN FoundBoot) 415 { 416 PIRP Irp; 417 PVOID Data; 418 KEVENT Event; 419 NTSTATUS Status; 420 PLIST_ENTRY NextEntry; 421 PFILE_OBJECT FileObject; 422 DISK_GEOMETRY DiskGeometry; 423 PDEVICE_OBJECT DeviceObject; 424 LARGE_INTEGER StartingOffset; 425 PULONG PartitionBuffer = NULL; 426 IO_STATUS_BLOCK IoStatusBlock; 427 CHAR Buffer[128], ArcBuffer[128]; 428 BOOLEAN NotEnabledPresent = FALSE; 429 STORAGE_DEVICE_NUMBER DeviceNumber; 430 PARC_DISK_SIGNATURE ArcDiskSignature; 431 PWSTR SymbolicLinkList, lSymbolicLinkList; 432 PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL; 433 UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW; 434 ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0; 435 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation; 436 ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA; 437 438 /* Initialise device number */ 439 DeviceNumber.DeviceNumber = ULONG_MAX; 440 /* Get all the disks present in the system */ 441 DiskCount = IoGetConfigurationInformation()->DiskCount; 442 443 /* Get enabled disks and check if result matches */ 444 Status = IopFetchConfigurationInformation(&SymbolicLinkList, 445 GUID_DEVINTERFACE_DISK, 446 DiskCount, 447 &EnabledDisks); 448 if (!NT_SUCCESS(Status)) 449 { 450 NotEnabledPresent = TRUE; 451 } 452 453 /* Save symbolic link list address in order to free it after */ 454 lSymbolicLinkList = SymbolicLinkList; 455 456 /* Build the boot strings */ 457 RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName); 458 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName); 459 460 /* If we have more enabled disks, take that into account */ 461 if (EnabledDisks > DiskCount) 462 { 463 DiskCount = EnabledDisks; 464 } 465 466 /* If we'll have to browse for none enabled disks, fix higher count */ 467 if (NotEnabledPresent && !EnabledDisks) 468 { 469 DiskCount += 20; 470 } 471 472 /* Finally, if in spite of all that work, we still don't have disks, leave */ 473 if (!DiskCount) 474 { 475 goto Cleanup; 476 } 477 478 /* Start browsing disks */ 479 for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++) 480 { 481 ASSERT(DriveLayout == NULL); 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(DeviceNumber), 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(DiskGeometry), 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 the first 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 ExFreePoolWithTag(PartitionBuffer, TAG_IO); 658 ObDereferenceObject(FileObject); 659 Status = STATUS_INSUFFICIENT_RESOURCES; 660 goto Cleanup; 661 } 662 663 /* Call the driver to perform reading */ 664 KeInitializeEvent(&Event, NotificationEvent, FALSE); 665 Status = IoCallDriver(DeviceObject, Irp); 666 if (Status == STATUS_PENDING) 667 { 668 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 669 Status = IoStatusBlock.Status; 670 } 671 672 /* If reading succeeded, calculate checksum by adding data */ 673 if (NT_SUCCESS(Status)) 674 { 675 for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG); i++) 676 { 677 CheckSum += PartitionBuffer[i]; 678 } 679 } 680 681 /* Release now unnecessary resources */ 682 ExFreePoolWithTag(PartitionBuffer, TAG_IO); 683 ObDereferenceObject(FileObject); 684 685 /* If we failed, release drive layout before going to next disk */ 686 if (!NT_SUCCESS(Status)) 687 { 688 ExFreePool(DriveLayout); 689 DriveLayout = NULL; 690 continue; 691 } 692 693 /* Browse each ARC disk */ 694 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; 695 NextEntry != &ArcDiskInformation->DiskSignatureListHead; 696 NextEntry = NextEntry->Flink) 697 { 698 ArcDiskSignature = CONTAINING_RECORD(NextEntry, 699 ARC_DISK_SIGNATURE, 700 ListEntry); 701 702 /* If they match, i.e. 703 * - There's only one disk for both BIOS and detected/enabled 704 * - Signatures are matching 705 * - Checksums are matching 706 * - This is MBR 707 */ 708 if (((SingleDisk && DiskCount == 1) || 709 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) && 710 (ArcDiskSignature->CheckSum + CheckSum == 0))) && 711 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)) 712 { 713 /* Create device name */ 714 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber); 715 RtlInitAnsiString(&DeviceStringA, Buffer); 716 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 717 if (!NT_SUCCESS(Status)) 718 { 719 goto Cleanup; 720 } 721 722 /* Create ARC name */ 723 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName); 724 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 725 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); 726 if (!NT_SUCCESS(Status)) 727 { 728 RtlFreeUnicodeString(&DeviceStringW); 729 goto Cleanup; 730 } 731 732 /* Link both */ 733 IoAssignArcName(&ArcNameStringW, &DeviceStringW); 734 735 /* And release resources */ 736 RtlFreeUnicodeString(&ArcNameStringW); 737 RtlFreeUnicodeString(&DeviceStringW); 738 739 /* Now, browse for every partition */ 740 for (i = 1; i <= DriveLayout->PartitionCount; i++) 741 { 742 /* Create device name */ 743 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i); 744 RtlInitAnsiString(&DeviceStringA, Buffer); 745 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 746 if (!NT_SUCCESS(Status)) 747 { 748 goto Cleanup; 749 } 750 751 /* Create partial ARC name */ 752 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i); 753 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 754 755 /* Is that boot device? */ 756 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE)) 757 { 758 DPRINT("Found boot device\n"); 759 *FoundBoot = TRUE; 760 } 761 762 /* Is that system partition? */ 763 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE)) 764 { 765 /* Create HAL path name */ 766 RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName); 767 Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE); 768 if (!NT_SUCCESS(Status)) 769 { 770 RtlFreeUnicodeString(&DeviceStringW); 771 goto Cleanup; 772 } 773 774 /* Then store those information to registry */ 775 IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW); 776 RtlFreeUnicodeString(&HalPathStringW); 777 } 778 779 /* Create complete ARC name */ 780 sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i); 781 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 782 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); 783 if (!NT_SUCCESS(Status)) 784 { 785 RtlFreeUnicodeString(&DeviceStringW); 786 goto Cleanup; 787 } 788 789 /* Link device name & ARC name */ 790 IoAssignArcName(&ArcNameStringW, &DeviceStringW); 791 792 /* Release strings */ 793 RtlFreeUnicodeString(&ArcNameStringW); 794 RtlFreeUnicodeString(&DeviceStringW); 795 } 796 } 797 else 798 { 799 /* Debugging feedback: Warn in case there's a valid partition, 800 * a matching signature, BUT a non-matching checksum: this can 801 * be the sign of a duplicate signature, or even worse a virus 802 * played with the partition table. */ 803 if (ArcDiskSignature->ValidPartitionTable && 804 (ArcDiskSignature->Signature == Signature) && 805 (ArcDiskSignature->CheckSum + CheckSum != 0)) 806 { 807 DPRINT("Be careful, you have a duplicate disk signature, or a virus altered your MBR!\n"); 808 } 809 } 810 } 811 812 /* Finally, release drive layout */ 813 ExFreePool(DriveLayout); 814 DriveLayout = NULL; 815 } 816 817 Status = STATUS_SUCCESS; 818 819 Cleanup: 820 if (DriveLayout) 821 { 822 ExFreePool(DriveLayout); 823 } 824 825 if (SymbolicLinkList) 826 { 827 ExFreePool(SymbolicLinkList); 828 } 829 830 return Status; 831 } 832 833 CODE_SEG("INIT") 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