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