1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/fstub/disksup.c 5 * PURPOSE: I/O HAL Routines for Disk Access 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Eric Kohl 8 * Casper S. Hornstrup (chorns@users.sourceforge.net) 9 * Pierre Schweitzer 10 */ 11 12 /* INCLUDES ******************************************************************/ 13 14 #include <ntoskrnl.h> 15 #define NDEBUG 16 #include <debug.h> 17 #include <internal/hal.h> 18 19 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:"; 20 21 #define AUTO_DRIVE MAXULONG 22 23 #define PARTITION_MAGIC 0xaa55 24 25 #define EFI_PMBR_OSTYPE_EFI 0xEE 26 27 #include <pshpack1.h> 28 29 typedef struct _REG_DISK_MOUNT_INFO 30 { 31 ULONG Signature; 32 LARGE_INTEGER StartingOffset; 33 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO; 34 35 #include <poppack.h> 36 37 typedef enum _DISK_MANAGER 38 { 39 NoDiskManager, 40 OntrackDiskManager, 41 EZ_Drive 42 } DISK_MANAGER; 43 44 typedef enum _PARTITION_TYPE 45 { 46 BootablePartition, 47 PrimaryPartition, 48 LogicalPartition, 49 FtPartition, 50 UnknownPartition, 51 DataPartition 52 } PARTITION_TYPE, *PPARTITION_TYPE; 53 54 NTSTATUS 55 FASTCALL 56 HalpQueryDriveLayout(IN PUNICODE_STRING DeviceName, 57 OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo) 58 { 59 IO_STATUS_BLOCK StatusBlock; 60 PDEVICE_OBJECT DeviceObject = NULL; 61 PFILE_OBJECT FileObject; 62 KEVENT Event; 63 PIRP Irp; 64 NTSTATUS Status; 65 ULONG BufferSize; 66 PDRIVE_LAYOUT_INFORMATION Buffer; 67 PAGED_CODE(); 68 69 /* Get device pointers */ 70 Status = IoGetDeviceObjectPointer(DeviceName, 71 FILE_READ_ATTRIBUTES, 72 &FileObject, 73 &DeviceObject); 74 if (!NT_SUCCESS(Status)) 75 { 76 return Status; 77 } 78 79 /* Get attached device object */ 80 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 81 ObDereferenceObject(FileObject); 82 83 /* Do not handle removable media */ 84 if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) 85 { 86 ObDereferenceObject(DeviceObject); 87 return STATUS_NO_MEDIA; 88 } 89 90 /* We'll loop until our buffer is big enough */ 91 Buffer = NULL; 92 BufferSize = 0x1000; 93 KeInitializeEvent(&Event, NotificationEvent, FALSE); 94 do 95 { 96 /* If we already had a buffer, it means it's not big 97 * enough, so free and multiply size by two 98 */ 99 if (Buffer != NULL) 100 { 101 ExFreePoolWithTag(Buffer, TAG_FSTUB); 102 BufferSize *= 2; 103 } 104 105 /* Allocate buffer for output buffer */ 106 Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_FSTUB); 107 if (Buffer == NULL) 108 { 109 Status = STATUS_NO_MEMORY; 110 break; 111 } 112 113 /* Build the IRP to query drive layout */ 114 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT, 115 DeviceObject, 116 NULL, 117 0, 118 Buffer, 119 BufferSize, 120 FALSE, 121 &Event, 122 &StatusBlock); 123 if (Irp == NULL) 124 { 125 Status = STATUS_INSUFFICIENT_RESOURCES; 126 break; 127 } 128 129 /* Call the driver and wait if appropriate */ 130 Status = IoCallDriver(DeviceObject, Irp); 131 if (Status == STATUS_PENDING) 132 { 133 KeWaitForSingleObject(&Event, 134 Executive, 135 KernelMode, 136 FALSE, 137 NULL); 138 Status = StatusBlock.Status; 139 } 140 /* If buffer is too small, keep looping */ 141 } while (Status == STATUS_BUFFER_TOO_SMALL); 142 143 /* We're done with the device */ 144 ObDereferenceObject(DeviceObject); 145 146 /* If querying worked, then return the buffer to the caller */ 147 if (NT_SUCCESS(Status)) 148 { 149 ASSERT(Buffer != NULL); 150 *LayoutInfo = Buffer; 151 } 152 /* Else, release the buffer if still allocated and fail */ 153 else 154 { 155 if (Buffer != NULL) 156 { 157 ExFreePoolWithTag(Buffer, TAG_FSTUB); 158 } 159 } 160 161 return Status; 162 } 163 164 NTSTATUS 165 HalpQueryPartitionType(IN PUNICODE_STRING DeviceName, 166 IN PDRIVE_LAYOUT_INFORMATION LayoutInfo, 167 OUT PPARTITION_TYPE PartitionType) 168 { 169 USHORT i; 170 PIRP Irp; 171 KEVENT Event; 172 NTSTATUS Status; 173 PFILE_OBJECT FileObject; 174 PDEVICE_OBJECT DeviceObject; 175 IO_STATUS_BLOCK IoStatusBlock; 176 PARTITION_INFORMATION_EX PartitionInfo; 177 178 PAGED_CODE(); 179 180 /* Get device pointers */ 181 Status = IoGetDeviceObjectPointer(DeviceName, 182 FILE_READ_ATTRIBUTES, 183 &FileObject, 184 &DeviceObject); 185 if (!NT_SUCCESS(Status)) 186 { 187 return Status; 188 } 189 190 /* Get attached device object */ 191 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 192 ObDereferenceObject(FileObject); 193 194 /* Assume logical partition for removable devices */ 195 if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) 196 { 197 ObDereferenceObject(DeviceObject); 198 *PartitionType = LogicalPartition; 199 return STATUS_SUCCESS; 200 } 201 202 /* For the others, query partition info */ 203 KeInitializeEvent(&Event, NotificationEvent, FALSE); 204 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX, 205 DeviceObject, 206 NULL, 207 0, 208 &PartitionInfo, 209 sizeof(PartitionInfo), 210 FALSE, 211 &Event, 212 &IoStatusBlock); 213 if (Irp == NULL) 214 { 215 ObDereferenceObject(DeviceObject); 216 return STATUS_INSUFFICIENT_RESOURCES; 217 } 218 219 Status = IoCallDriver(DeviceObject, Irp); 220 if (Status == STATUS_PENDING) 221 { 222 KeWaitForSingleObject(&Event, 223 Executive, 224 KernelMode, 225 FALSE, 226 NULL); 227 Status = IoStatusBlock.Status; 228 } 229 230 /* We're done with the device */ 231 ObDereferenceObject(DeviceObject); 232 233 /* If we failed querying partition info, try to return something 234 * if caller didn't provide a precise layout, assume logical 235 * partition and fake success. Otherwise, just fail. 236 */ 237 if (!NT_SUCCESS(Status)) 238 { 239 if (LayoutInfo == NULL) 240 { 241 *PartitionType = LogicalPartition; 242 return STATUS_SUCCESS; 243 } 244 245 return Status; 246 } 247 248 /* First, handle non MBR style (easy cases) */ 249 if (PartitionInfo.PartitionStyle != PARTITION_STYLE_MBR) 250 { 251 /* If not GPT, we don't know what it is */ 252 if (PartitionInfo.PartitionStyle != PARTITION_STYLE_GPT) 253 { 254 *PartitionType = UnknownPartition; 255 return STATUS_SUCCESS; 256 } 257 258 /* Check whether that's data partition */ 259 if (RtlCompareMemory(&PartitionInfo.Gpt.PartitionType, 260 &PARTITION_BASIC_DATA_GUID, 261 sizeof(GUID)) == sizeof(GUID)) 262 { 263 *PartitionType = DataPartition; 264 return STATUS_SUCCESS; 265 } 266 267 /* Otherwise, we don't know */ 268 *PartitionType = UnknownPartition; 269 return STATUS_SUCCESS; 270 } 271 272 /* If we don't recognize partition type, return unknown */ 273 if (!IsRecognizedPartition(PartitionInfo.Mbr.PartitionType)) 274 { 275 *PartitionType = UnknownPartition; 276 return STATUS_SUCCESS; 277 } 278 279 /* Check if that's a FT volume */ 280 if (IsFTPartition(PartitionInfo.Mbr.PartitionType)) 281 { 282 *PartitionType = FtPartition; 283 return STATUS_SUCCESS; 284 } 285 286 /* If the caller didn't provide the complete layout, just return */ 287 if (LayoutInfo == NULL) 288 { 289 *PartitionType = LogicalPartition; 290 return STATUS_SUCCESS; 291 } 292 293 /* Now, evaluate the partition to the 4 in the input layout */ 294 for (i = 0; i < 4; ++i) 295 { 296 /* If we find a partition matching */ 297 if (LayoutInfo->PartitionEntry[i].StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart) 298 { 299 /* Return boot if boot flag is set */ 300 if (PartitionInfo.Mbr.BootIndicator) 301 { 302 *PartitionType = BootablePartition; 303 } 304 /* Primary otherwise */ 305 else 306 { 307 *PartitionType = PrimaryPartition; 308 } 309 310 return STATUS_SUCCESS; 311 } 312 } 313 314 /* Otherwise, assume logical */ 315 *PartitionType = LogicalPartition; 316 return STATUS_SUCCESS; 317 } 318 319 PULONG 320 IopComputeHarddiskDerangements(IN ULONG DiskCount) 321 { 322 PIRP Irp; 323 KEVENT Event; 324 ULONG i, j, k; 325 PULONG Devices; 326 NTSTATUS Status; 327 WCHAR Buffer[100]; 328 UNICODE_STRING ArcName; 329 PFILE_OBJECT FileObject; 330 PDEVICE_OBJECT DeviceObject; 331 IO_STATUS_BLOCK IoStatusBlock; 332 STORAGE_DEVICE_NUMBER DeviceNumber; 333 334 /* No disks, nothing to do */ 335 if (DiskCount == 0) 336 { 337 return NULL; 338 } 339 340 /* Allocate a buffer big enough to hold all the disks */ 341 Devices = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, 342 sizeof(ULONG) * DiskCount, 343 TAG_FSTUB); 344 if (Devices == NULL) 345 { 346 return NULL; 347 } 348 349 /* Now, we'll query all the disks */ 350 for (i = 0; i < DiskCount; ++i) 351 { 352 /* Using their ARC name */ 353 swprintf(Buffer, L"\\ArcName\\multi(0)disk(0)rdisk(%d)", i); 354 RtlInitUnicodeString(&ArcName, Buffer); 355 /* Get the attached DeviceObject */ 356 if (NT_SUCCESS(IoGetDeviceObjectPointer(&ArcName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject))) 357 { 358 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 359 ObDereferenceObject(FileObject); 360 361 /* And query it for device number */ 362 KeInitializeEvent(&Event, NotificationEvent, FALSE); 363 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, 364 DeviceObject, 365 NULL, 366 0, 367 &DeviceNumber, 368 sizeof(DeviceNumber), 369 FALSE, 370 &Event, 371 &IoStatusBlock); 372 if (Irp != NULL) 373 { 374 Status = IoCallDriver(DeviceObject, Irp); 375 if (Status == STATUS_PENDING) 376 { 377 KeWaitForSingleObject(&Event, 378 Executive, 379 KernelMode, 380 FALSE, 381 NULL); 382 Status = IoStatusBlock.Status; 383 } 384 385 ObDereferenceObject(DeviceObject); 386 387 /* In case of a success remember device number */ 388 if (NT_SUCCESS(Status)) 389 { 390 Devices[i] = DeviceNumber.DeviceNumber; 391 /* Move on, not to fall into our default case */ 392 continue; 393 } 394 } 395 else 396 { 397 ObDereferenceObject(DeviceObject); 398 } 399 400 /* Default case, for failures, set -1 */ 401 Devices[i] = -1; 402 } 403 } 404 405 /* Now, we'll check all device numbers */ 406 for (i = 0; i < DiskCount; ++i) 407 { 408 /* First of all, check if we're at the right place */ 409 for (j = 0; j < DiskCount; ++j) 410 { 411 if (Devices[j] == i) 412 { 413 break; 414 } 415 } 416 417 /* If not, perform the change */ 418 if (j >= DiskCount) 419 { 420 k = 0; 421 while (Devices[k] != -1) 422 { 423 if (++k >= DiskCount) 424 { 425 break; 426 } 427 } 428 429 if (k < DiskCount) 430 { 431 Devices[k] = i; 432 } 433 } 434 } 435 436 /* Return our device derangement map */ 437 return Devices; 438 } 439 440 NTSTATUS 441 HalpNextMountLetter(IN PUNICODE_STRING DeviceName, 442 OUT PUCHAR DriveLetter) 443 { 444 PIRP Irp; 445 KEVENT Event; 446 NTSTATUS Status; 447 UNICODE_STRING MountMgr; 448 PFILE_OBJECT FileObject; 449 PDEVICE_OBJECT DeviceObject; 450 IO_STATUS_BLOCK IoStatusBlock; 451 PMOUNTMGR_DRIVE_LETTER_TARGET Target; 452 MOUNTMGR_DRIVE_LETTER_INFORMATION LetterInfo; 453 454 /* To get next mount letter, we need the MountMgr */ 455 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); 456 Status = IoGetDeviceObjectPointer(&MountMgr, 457 FILE_READ_ATTRIBUTES, 458 &FileObject, 459 &DeviceObject); 460 if (!NT_SUCCESS(Status)) 461 { 462 return Status; 463 } 464 465 /* Allocate our input buffer */ 466 Target = ExAllocatePoolWithTag(PagedPool, 467 DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName), 468 TAG_FSTUB); 469 if (Target == NULL) 470 { 471 ObDereferenceObject(FileObject); 472 return STATUS_INSUFFICIENT_RESOURCES; 473 } 474 475 /* And fill it with the device hat needs a drive letter */ 476 Target->DeviceNameLength = DeviceName->Length; 477 RtlCopyMemory(&Target->DeviceName[0], DeviceName->Buffer, DeviceName->Length); 478 479 /* Call the mount manager */ 480 KeInitializeEvent(&Event, NotificationEvent, FALSE); 481 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, 482 DeviceObject, 483 Target, 484 DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName), 485 &LetterInfo, 486 sizeof(LetterInfo), 487 FALSE, 488 &Event, 489 &IoStatusBlock); 490 if (Irp == NULL) 491 { 492 ExFreePoolWithTag(Target, TAG_FSTUB); 493 ObDereferenceObject(FileObject); 494 return STATUS_INSUFFICIENT_RESOURCES; 495 } 496 497 Status = IoCallDriver(DeviceObject, Irp); 498 if (Status == STATUS_PENDING) 499 { 500 KeWaitForSingleObject(&Event, 501 Executive, 502 KernelMode, 503 FALSE, 504 NULL); 505 Status = IoStatusBlock.Status; 506 } 507 508 ExFreePoolWithTag(Target, TAG_FSTUB); 509 ObDereferenceObject(FileObject); 510 511 DPRINT("Done: %d %c\n", LetterInfo.DriveLetterWasAssigned, 512 LetterInfo.CurrentDriveLetter); 513 514 /* Return the drive letter the MountMgr potentially assigned */ 515 *DriveLetter = LetterInfo.CurrentDriveLetter; 516 517 /* Also return the success */ 518 return Status; 519 } 520 521 NTSTATUS 522 HalpSetMountLetter(IN PUNICODE_STRING DeviceName, 523 UCHAR DriveLetter) 524 { 525 PIRP Irp; 526 KEVENT Event; 527 NTSTATUS Status; 528 WCHAR Buffer[30]; 529 ULONG InputBufferLength; 530 PFILE_OBJECT FileObject; 531 PDEVICE_OBJECT DeviceObject; 532 IO_STATUS_BLOCK IoStatusBlock; 533 UNICODE_STRING DosDevice, MountMgr; 534 PMOUNTMGR_CREATE_POINT_INPUT InputBuffer; 535 536 /* Setup the DosDevice name */ 537 swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter); 538 RtlInitUnicodeString(&DosDevice, Buffer); 539 540 /* Allocate the input buffer for the MountMgr */ 541 InputBufferLength = DosDevice.Length + DeviceName->Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT); 542 InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB); 543 if (InputBuffer == NULL) 544 { 545 return STATUS_INSUFFICIENT_RESOURCES; 546 } 547 548 /* Fill the input buffer */ 549 InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT); 550 InputBuffer->SymbolicLinkNameLength = DosDevice.Length; 551 InputBuffer->DeviceNameOffset = DosDevice.Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT); 552 InputBuffer->DeviceNameLength = DeviceName->Length; 553 RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length); 554 RtlCopyMemory((PVOID)((ULONG_PTR)InputBuffer + InputBuffer->DeviceNameOffset), 555 DeviceName->Buffer, 556 DeviceName->Length); 557 558 /* Get the MountMgr device pointer, to send the IOCTL */ 559 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); 560 Status = IoGetDeviceObjectPointer(&MountMgr, 561 FILE_READ_ATTRIBUTES, 562 &FileObject, 563 &DeviceObject); 564 if (!NT_SUCCESS(Status)) 565 { 566 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 567 return Status; 568 } 569 570 /* Call the MountMgr */ 571 KeInitializeEvent(&Event, NotificationEvent, FALSE); 572 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT, 573 DeviceObject, 574 InputBuffer, 575 InputBufferLength, 576 NULL, 577 0, 578 FALSE, 579 &Event, 580 &IoStatusBlock); 581 if (Irp == NULL) 582 { 583 ObDereferenceObject(FileObject); 584 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 585 return STATUS_INSUFFICIENT_RESOURCES; 586 } 587 588 Status = IoCallDriver(DeviceObject, Irp); 589 if (Status == STATUS_PENDING) 590 { 591 KeWaitForSingleObject(&Event, 592 Executive, 593 KernelMode, 594 FALSE, 595 NULL); 596 Status = IoStatusBlock.Status; 597 } 598 599 ObDereferenceObject(FileObject); 600 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 601 602 /* Return the MountMgr status */ 603 return Status; 604 } 605 606 UCHAR 607 HalpNextDriveLetter(IN PUNICODE_STRING DeviceName, 608 IN PSTRING NtDeviceName, 609 OUT PUCHAR NtSystemPath, 610 BOOLEAN IsRemovable) 611 { 612 UCHAR i; 613 WCHAR Buffer[40]; 614 UCHAR DriveLetter; 615 UNICODE_STRING FloppyString, CdString, NtDeviceNameU, DosDevice; 616 617 /* Quick path, ask directly the mount manager to assign the next 618 * free drive letter 619 */ 620 if (NT_SUCCESS(HalpNextMountLetter(DeviceName, &DriveLetter))) 621 { 622 return DriveLetter; 623 } 624 625 /* We'll allow MountMgr to fail only for non vital path */ 626 if (NtDeviceName == NULL || NtSystemPath == NULL) 627 { 628 return -1; 629 } 630 631 /* And for removable devices */ 632 if (!IsRemovable) 633 { 634 return 0; 635 } 636 637 /* Removable might be floppy or cdrom */ 638 RtlInitUnicodeString(&FloppyString, L"\\Device\\Floppy"); 639 RtlInitUnicodeString(&CdString, L"\\Device\\CdRom"); 640 641 /* If floppy, start at A */ 642 if (RtlPrefixUnicodeString(&FloppyString, DeviceName, TRUE)) 643 { 644 DriveLetter = 'A'; 645 } 646 /* If CD start C */ 647 else if (RtlPrefixUnicodeString(&CdString, DeviceName, TRUE)) 648 { 649 DriveLetter = 'D'; 650 } 651 /* For the rest start at C */ 652 else 653 { 654 DriveLetter = 'C'; 655 } 656 657 /* Now, try to assign a drive letter manually with the MountMgr */ 658 for (i = DriveLetter; i <= 'Z'; ++i) 659 { 660 if (NT_SUCCESS(HalpSetMountLetter(DeviceName, i))) 661 { 662 /* If it worked, if we were managing system path, update manually */ 663 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE))) 664 { 665 if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE)) 666 { 667 *NtSystemPath = i; 668 } 669 670 RtlFreeUnicodeString(&NtDeviceNameU); 671 } 672 673 return i; 674 } 675 } 676 677 /* Last fall back, we're not on a PnP device... */ 678 for (i = DriveLetter; i <= 'Z'; ++i) 679 { 680 /* We'll link manually, without MountMgr knowing anything about the device */ 681 swprintf(Buffer, L"\\DosDevices\\%c:", i); 682 RtlInitUnicodeString(&DosDevice, Buffer); 683 684 /* If linking worked, then the letter was free ;-) */ 685 if (NT_SUCCESS(IoCreateSymbolicLink(&DosDevice, DeviceName))) 686 { 687 /* If it worked, if we were managing system path, update manually */ 688 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE))) 689 { 690 if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE)) 691 { 692 *NtSystemPath = i; 693 } 694 695 RtlFreeUnicodeString(&NtDeviceNameU); 696 } 697 698 return i; 699 } 700 } 701 702 /* We're done, nothing happened */ 703 return 0; 704 } 705 706 BOOLEAN 707 HalpIsOldStyleFloppy(PUNICODE_STRING DeviceName) 708 { 709 PIRP Irp; 710 KEVENT Event; 711 NTSTATUS Status; 712 MOUNTDEV_NAME DevName; 713 PFILE_OBJECT FileObject; 714 PDEVICE_OBJECT DeviceObject; 715 IO_STATUS_BLOCK IoStatusBlock; 716 PAGED_CODE(); 717 718 /* Get the attached device object to our device */ 719 if (!NT_SUCCESS(IoGetDeviceObjectPointer(DeviceName, 720 FILE_READ_ATTRIBUTES, 721 &FileObject, 722 &DeviceObject))) 723 { 724 return FALSE; 725 } 726 727 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 728 ObDereferenceObject(FileObject); 729 730 /* Query its device name (ie, check floppy.sys implements MountMgr interface) */ 731 KeInitializeEvent(&Event, NotificationEvent, FALSE); 732 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 733 DeviceObject, 734 NULL, 735 0, 736 &DevName, 737 sizeof(DevName), 738 FALSE, 739 &Event, 740 &IoStatusBlock); 741 if (Irp == NULL) 742 { 743 ObDereferenceObject(DeviceObject); 744 return FALSE; 745 } 746 747 Status = IoCallDriver(DeviceObject, Irp); 748 if (Status == STATUS_PENDING) 749 { 750 KeWaitForSingleObject(&Event, 751 Executive, 752 KernelMode, 753 FALSE, 754 NULL); 755 Status = IoStatusBlock.Status; 756 } 757 758 /* If status is not STATUS_BUFFER_OVERFLOW, it means 759 * it's pre-mountmgr driver, aka "Old style". 760 */ 761 ObDereferenceObject(DeviceObject); 762 return (Status != STATUS_BUFFER_OVERFLOW); 763 } 764 765 NTSTATUS 766 HalpDeleteMountLetter(UCHAR DriveLetter) 767 { 768 PIRP Irp; 769 KEVENT Event; 770 NTSTATUS Status; 771 WCHAR Buffer[30]; 772 ULONG InputBufferLength; 773 PFILE_OBJECT FileObject; 774 PDEVICE_OBJECT DeviceObject; 775 IO_STATUS_BLOCK IoStatusBlock; 776 PMOUNTMGR_MOUNT_POINT InputBuffer; 777 UNICODE_STRING DosDevice, MountMgr; 778 PMOUNTMGR_MOUNT_POINTS OutputBuffer; 779 780 /* Setup the device name of the letter to delete */ 781 swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter); 782 RtlInitUnicodeString(&DosDevice, Buffer); 783 784 /* Allocate the input buffer for MountMgr */ 785 InputBufferLength = DosDevice.Length + sizeof(MOUNTMGR_MOUNT_POINT); 786 InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB); 787 if (InputBuffer == NULL) 788 { 789 return STATUS_INSUFFICIENT_RESOURCES; 790 } 791 792 /* Fill it in */ 793 RtlZeroMemory(InputBuffer, InputBufferLength); 794 InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 795 InputBuffer->SymbolicLinkNameLength = DosDevice.Length; 796 RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length); 797 798 /* Allocate big enough output buffer (we don't care about the output) */ 799 OutputBuffer = ExAllocatePoolWithTag(PagedPool, 0x1000, TAG_FSTUB); 800 if (OutputBuffer == NULL) 801 { 802 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 803 return STATUS_INSUFFICIENT_RESOURCES; 804 } 805 806 /* Get the device pointer to the MountMgr */ 807 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); 808 Status = IoGetDeviceObjectPointer(&MountMgr, 809 FILE_READ_ATTRIBUTES, 810 &FileObject, 811 &DeviceObject); 812 if (!NT_SUCCESS(Status)) 813 { 814 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); 815 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 816 return Status; 817 } 818 819 /* Call the mount manager to delete the drive letter */ 820 KeInitializeEvent(&Event, NotificationEvent, FALSE); 821 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS, 822 DeviceObject, 823 InputBuffer, 824 InputBufferLength, 825 OutputBuffer, 826 0x1000, 827 FALSE, 828 &Event, 829 &IoStatusBlock); 830 if (Irp == NULL) 831 { 832 ObDereferenceObject(FileObject); 833 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); 834 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 835 return STATUS_INSUFFICIENT_RESOURCES; 836 } 837 838 Status = IoCallDriver(DeviceObject, Irp); 839 if (Status == STATUS_PENDING) 840 { 841 KeWaitForSingleObject(&Event, 842 Executive, 843 KernelMode, 844 FALSE, 845 NULL); 846 Status = IoStatusBlock.Status; 847 } 848 849 ObDereferenceObject(FileObject); 850 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); 851 ExFreePoolWithTag(InputBuffer, TAG_FSTUB); 852 853 return Status; 854 } 855 856 VOID 857 HalpEnableAutomaticDriveLetterAssignment(VOID) 858 { 859 PIRP Irp; 860 KEVENT Event; 861 NTSTATUS Status; 862 UNICODE_STRING MountMgr; 863 PFILE_OBJECT FileObject; 864 PDEVICE_OBJECT DeviceObject; 865 IO_STATUS_BLOCK IoStatusBlock; 866 867 /* Get the device pointer to the MountMgr */ 868 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); 869 Status = IoGetDeviceObjectPointer(&MountMgr, 870 FILE_READ_ATTRIBUTES, 871 &FileObject, 872 &DeviceObject); 873 if (!NT_SUCCESS(Status)) 874 { 875 return; 876 } 877 878 /* Just send an IOCTL to enable the feature */ 879 KeInitializeEvent(&Event, NotificationEvent, FALSE); 880 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS, 881 DeviceObject, 882 NULL, 883 0, 884 NULL, 885 0, 886 FALSE, 887 &Event, 888 &IoStatusBlock); 889 if (Irp == NULL) 890 { 891 return; 892 } 893 894 Status = IoCallDriver(DeviceObject, Irp); 895 if (Status == STATUS_PENDING) 896 { 897 KeWaitForSingleObject(&Event, 898 Executive, 899 KernelMode, 900 FALSE, 901 NULL); 902 Status = IoStatusBlock.Status; 903 } 904 905 ObDereferenceObject(FileObject); 906 907 return; 908 } 909 910 VOID 911 FASTCALL 912 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 913 IN PSTRING NtDeviceName, 914 OUT PUCHAR NtSystemPath, 915 OUT PSTRING NtSystemPathString) 916 { 917 USHORT i; 918 PULONG Devices; 919 NTSTATUS Status; 920 WCHAR Buffer[50]; 921 HANDLE FileHandle; 922 UCHAR DriveLetter; 923 BOOLEAN SystemFound; 924 IO_STATUS_BLOCK StatusBlock; 925 PARTITION_TYPE PartitionType; 926 ANSI_STRING StringA1, StringA2; 927 PSTR Buffer1, Buffer2, LoadOptions; 928 OBJECT_ATTRIBUTES ObjectAttributes; 929 PDRIVE_LAYOUT_INFORMATION LayoutInfo; 930 PCONFIGURATION_INFORMATION ConfigInfo; 931 UNICODE_STRING StringU1, StringU2, StringU3; 932 ULONG Increment, DiskCount, RealDiskCount, HarddiskCount, PartitionCount, SystemPartition; 933 934 PAGED_CODE(); 935 936 /* Get our disk count */ 937 ConfigInfo = IoGetConfigurationInformation(); 938 DiskCount = ConfigInfo->DiskCount; 939 RealDiskCount = 0; 940 941 /* Allocate two generic string buffers we'll use and reuser later on */ 942 Buffer1 = ExAllocatePoolWithTag(NonPagedPool, 128, TAG_FSTUB); 943 Buffer2 = ExAllocatePoolWithTag(NonPagedPool, 64, TAG_FSTUB); 944 if (Buffer1 == NULL || Buffer2 == NULL) 945 { 946 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); 947 } 948 949 /* In case of a remote boot, setup system path */ 950 if (IoRemoteBootClient) 951 { 952 PSTR Last, Saved; 953 954 /* Find last \ */ 955 Last = strrchr(LoaderBlock->NtBootPathName, '\\'); 956 Saved = NULL; 957 /* Misformed name, fail */ 958 if (Last == NULL) 959 { 960 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); 961 } 962 963 /* In case the name was terminated by a \... */ 964 if (Last[1] == ANSI_NULL) 965 { 966 /* Erase it, save position and find the previous \ */ 967 *Last = ANSI_NULL; 968 Saved = Last; 969 Last = strrchr(LoaderBlock->NtBootPathName, '\\'); 970 *Saved = '\\'; 971 } 972 973 /* Misformed name, fail */ 974 if (Last == NULL) 975 { 976 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); 977 } 978 979 /* For a remote boot, assign X drive letter */ 980 NtSystemPath[0] = 'X'; 981 NtSystemPath[1] = ':'; 982 /* And copy the end of the boot path */ 983 strcpy((PSTR)&NtSystemPath[2], Last); 984 985 /* If we had to remove the trailing \, remove it here too */ 986 if (Saved != NULL) 987 { 988 NtSystemPath[strlen((PSTR)NtSystemPath) - 1] = ANSI_NULL; 989 } 990 991 /* Setup output string */ 992 RtlInitString(NtSystemPathString, (PSTR)NtSystemPath); 993 } 994 995 /* For each of our disks, create the physical device DOS device */ 996 Increment = 0; 997 if (DiskCount != 0) 998 { 999 for (i = 0; i < DiskCount; ++i) 1000 { 1001 /* Setup the origin name */ 1002 sprintf(Buffer1, "\\Device\\Harddisk%d\\Partition%d", i, 0); 1003 RtlInitAnsiString(&StringA1, Buffer1); 1004 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, &StringA1, TRUE))) 1005 { 1006 /* We cannot fail */ 1007 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); 1008 } 1009 1010 /* Open the device */ 1011 InitializeObjectAttributes(&ObjectAttributes, 1012 &StringU1, 1013 OBJ_CASE_INSENSITIVE, 1014 NULL, 1015 NULL); 1016 Status = ZwOpenFile(&FileHandle, 1017 SYNCHRONIZE | FILE_READ_DATA, 1018 &ObjectAttributes, 1019 &StatusBlock, 1020 FILE_SHARE_READ, 1021 FILE_SYNCHRONOUS_IO_NONALERT); 1022 if (NT_SUCCESS(Status)) 1023 { 1024 /* If we managed, create the link */ 1025 sprintf(Buffer2, "\\DosDevices\\PhysicalDrive%d", i); 1026 RtlInitAnsiString(&StringA2, Buffer2); 1027 Status = RtlAnsiStringToUnicodeString(&StringU2, &StringA2, TRUE); 1028 if (NT_SUCCESS(Status)) 1029 { 1030 IoCreateSymbolicLink(&StringU2, &StringU1); 1031 RtlFreeUnicodeString(&StringU2); 1032 } 1033 1034 ZwClose(FileHandle); 1035 1036 RealDiskCount = i + 1; 1037 } 1038 1039 RtlFreeUnicodeString(&StringU1); 1040 1041 if (!NT_SUCCESS(Status)) 1042 { 1043 if (Increment < 50) 1044 { 1045 ++Increment; 1046 ++DiskCount; 1047 } 1048 } 1049 } 1050 } 1051 1052 /* We done for our buffers */ 1053 ExFreePoolWithTag(Buffer1, TAG_FSTUB); 1054 ExFreePoolWithTag(Buffer2, TAG_FSTUB); 1055 1056 /* Upcase our load options, if any */ 1057 if (LoaderBlock->LoadOptions != NULL) 1058 { 1059 LoadOptions = _strupr(LoaderBlock->LoadOptions); 1060 } 1061 else 1062 { 1063 LoadOptions = NULL; 1064 } 1065 1066 /* If we boot with /MININT (system hive as volatile) option, assign X letter to boot device */ 1067 if (LoadOptions != NULL && 1068 strstr(LoadOptions, "MININT") != 0 && 1069 NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE))) 1070 { 1071 if (NT_SUCCESS(HalpSetMountLetter(&StringU1, 'X'))) 1072 { 1073 *NtSystemPath = 'X'; 1074 } 1075 1076 RtlFreeUnicodeString(&StringU1); 1077 } 1078 1079 /* Compute our disks derangements */ 1080 DiskCount -= Increment; 1081 if (RealDiskCount > DiskCount) 1082 { 1083 DiskCount = RealDiskCount; 1084 } 1085 Devices = IopComputeHarddiskDerangements(DiskCount); 1086 1087 /* Now, start browsing all our disks for assigning drive letters 1088 * Here, we'll only handle boot partition and primary partitions 1089 */ 1090 HarddiskCount = 0; 1091 for (i = 0; i < DiskCount; ++i) 1092 { 1093 /* Get device ID according to derangements map */ 1094 if (Devices != NULL) 1095 { 1096 HarddiskCount = Devices[i]; 1097 } 1098 1099 /* Query disk layout */ 1100 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); 1101 RtlInitUnicodeString(&StringU1, Buffer); 1102 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) 1103 { 1104 LayoutInfo = NULL; 1105 } 1106 1107 /* Assume we didn't find system */ 1108 SystemFound = FALSE; 1109 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, 1); 1110 RtlInitUnicodeString(&StringU1, Buffer); 1111 /* Query partition info for our disk */ 1112 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1113 { 1114 /* It failed, retry for all the partitions */ 1115 for (PartitionCount = 1; ; ++PartitionCount) 1116 { 1117 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1118 RtlInitUnicodeString(&StringU1, Buffer); 1119 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1120 { 1121 break; 1122 } 1123 1124 /* We found a primary partition, assign a drive letter */ 1125 if (PartitionType == PrimaryPartition) 1126 { 1127 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); 1128 break; 1129 } 1130 } 1131 } 1132 else 1133 { 1134 /* All right */ 1135 for (PartitionCount = 2; ; ++PartitionCount) 1136 { 1137 /* If our partition is bootable (MBR) or data (GPT), that's system partition */ 1138 if (PartitionType == BootablePartition || PartitionType == DataPartition) 1139 { 1140 SystemFound = TRUE; 1141 1142 /* Assign a drive letter and stop here if MBR */ 1143 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); 1144 if (PartitionType == BootablePartition) 1145 { 1146 break; 1147 } 1148 } 1149 1150 /* Keep looping on all the partitions */ 1151 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1152 RtlInitUnicodeString(&StringU1, Buffer); 1153 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1154 { 1155 /* Mount every primary partition if we didn't find system */ 1156 if (!SystemFound) 1157 { 1158 for (PartitionCount = 1; ; ++PartitionCount) 1159 { 1160 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1161 RtlInitUnicodeString(&StringU1, Buffer); 1162 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1163 { 1164 break; 1165 } 1166 1167 if (PartitionType == PrimaryPartition) 1168 { 1169 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); 1170 break; 1171 } 1172 } 1173 } 1174 1175 break; 1176 } 1177 } 1178 } 1179 1180 /* Free layout, we'll reallocate it for next device */ 1181 if (LayoutInfo != NULL) 1182 { 1183 ExFreePoolWithTag(LayoutInfo, TAG_FSTUB); 1184 } 1185 1186 HarddiskCount = i + 1; 1187 } 1188 1189 /* Now, assign logical partitions */ 1190 for (i = 0; i < DiskCount; ++i) 1191 { 1192 /* Get device ID according to derangements map */ 1193 if (Devices != NULL) 1194 { 1195 HarddiskCount = Devices[i]; 1196 } 1197 else 1198 { 1199 HarddiskCount = i; 1200 } 1201 1202 /* Query device layout */ 1203 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); 1204 RtlInitUnicodeString(&StringU1, Buffer); 1205 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) 1206 { 1207 LayoutInfo = NULL; 1208 } 1209 1210 /* And assign drive letter to logical partitions */ 1211 for (PartitionCount = 1; ; ++PartitionCount) 1212 { 1213 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1214 RtlInitUnicodeString(&StringU1, Buffer); 1215 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1216 { 1217 break; 1218 } 1219 1220 if (PartitionType == LogicalPartition) 1221 { 1222 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); 1223 } 1224 } 1225 1226 /* Free layout, we'll reallocate it for next device */ 1227 if (LayoutInfo != NULL) 1228 { 1229 ExFreePoolWithTag(LayoutInfo, 0); 1230 } 1231 } 1232 1233 /* Now, assign drive letters to everything else */ 1234 for (i = 0; i < DiskCount; ++i) 1235 { 1236 /* Get device ID according to derangements map */ 1237 if (Devices != NULL) 1238 { 1239 HarddiskCount = Devices[i]; 1240 } 1241 else 1242 { 1243 HarddiskCount = i; 1244 } 1245 1246 /* Query device layout */ 1247 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); 1248 RtlInitUnicodeString(&StringU1, Buffer); 1249 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) 1250 { 1251 LayoutInfo = NULL; 1252 } 1253 1254 /* Save system partition if any */ 1255 SystemPartition = 0; 1256 for (PartitionCount = 1; ; ++PartitionCount) 1257 { 1258 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1259 RtlInitUnicodeString(&StringU1, Buffer); 1260 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1261 { 1262 break; 1263 } 1264 1265 if ((PartitionType == BootablePartition || PartitionType == PrimaryPartition) && (SystemPartition == 0)) 1266 { 1267 SystemPartition = PartitionCount; 1268 } 1269 } 1270 1271 /* And assign drive letter to anything but system partition */ 1272 for (PartitionCount = 1; ; ++PartitionCount) 1273 { 1274 if (PartitionCount != SystemPartition) 1275 { 1276 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); 1277 RtlInitUnicodeString(&StringU1, Buffer); 1278 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) 1279 { 1280 if (LayoutInfo != NULL) 1281 { 1282 ExFreePoolWithTag(LayoutInfo, 0); 1283 } 1284 1285 break; 1286 } 1287 1288 if (PartitionType == PrimaryPartition || PartitionType == FtPartition) 1289 { 1290 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); 1291 } 1292 } 1293 } 1294 } 1295 1296 /* We're done with disks, if we have a device map, free it */ 1297 if (Devices != NULL) 1298 { 1299 ExFreePoolWithTag(Devices, TAG_FSTUB); 1300 } 1301 1302 /* Now, assign drive letter to floppy drives */ 1303 for (i = 0; i < ConfigInfo->FloppyCount; ++i) 1304 { 1305 swprintf(Buffer, L"\\Device\\Floppy%d", i); 1306 RtlInitUnicodeString(&StringU1, Buffer); 1307 if (HalpIsOldStyleFloppy(&StringU1)) 1308 { 1309 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE); 1310 } 1311 } 1312 1313 /* And CD drives */ 1314 for (i = 0; i < ConfigInfo->CdRomCount; ++i) 1315 { 1316 swprintf(Buffer, L"\\Device\\CdRom%d", i); 1317 RtlInitUnicodeString(&StringU1, Buffer); 1318 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE); 1319 } 1320 1321 /* If not remote boot, handle NtDeviceName */ 1322 if (!IoRemoteBootClient && NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE))) 1323 { 1324 /* Assign it a drive letter */ 1325 DriveLetter = HalpNextDriveLetter(&StringU1, NULL, NULL, TRUE); 1326 if (DriveLetter != 0) 1327 { 1328 if (DriveLetter != 0xFF) 1329 { 1330 *NtSystemPath = DriveLetter; 1331 } 1332 } 1333 /* If it fails through mount manager, retry manually */ 1334 else 1335 { 1336 RtlInitUnicodeString(&StringU2, L"\\Device\\Floppy"); 1337 RtlInitUnicodeString(&StringU3, L"\\Device\\CdRom"); 1338 1339 if (RtlPrefixUnicodeString(&StringU2, &StringU1, TRUE)) 1340 { 1341 DriveLetter = 'A'; 1342 } 1343 else if (RtlPrefixUnicodeString(&StringU3, &StringU1, TRUE)) 1344 { 1345 DriveLetter = 'D'; 1346 } 1347 else 1348 { 1349 DriveLetter = 'C'; 1350 } 1351 1352 /* Try any drive letter */ 1353 while (HalpSetMountLetter(&StringU1, DriveLetter) != STATUS_SUCCESS) 1354 { 1355 ++DriveLetter; 1356 1357 if (DriveLetter > 'Z') 1358 { 1359 break; 1360 } 1361 } 1362 1363 /* If we're beyond Z (ie, no slot left) */ 1364 if (DriveLetter > 'Z') 1365 { 1366 /* Delete Z, and reuse it for system */ 1367 HalpDeleteMountLetter('Z'); 1368 HalpSetMountLetter(&StringU1, 'Z'); 1369 *NtSystemPath = 'Z'; 1370 } 1371 else 1372 { 1373 /* Return matching drive letter */ 1374 *NtSystemPath = DriveLetter; 1375 } 1376 } 1377 1378 RtlFreeUnicodeString(&StringU1); 1379 } 1380 1381 /* Enable auto assignement for mountmgr */ 1382 HalpEnableAutomaticDriveLetterAssignment(); 1383 } 1384 1385 /* PRIVATE FUNCTIONS *********************************************************/ 1386 1387 NTSTATUS 1388 NTAPI 1389 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject, 1390 IN PDISK_GEOMETRY Geometry, 1391 OUT PULONGLONG RealSectorCount) 1392 { 1393 PIRP Irp; 1394 IO_STATUS_BLOCK IoStatusBlock; 1395 PKEVENT Event; 1396 NTSTATUS Status; 1397 PARTITION_INFORMATION PartitionInfo; 1398 PAGED_CODE(); 1399 1400 /* Allocate a non-paged event */ 1401 Event = ExAllocatePoolWithTag(NonPagedPool, 1402 sizeof(KEVENT), 1403 TAG_FILE_SYSTEM); 1404 if (!Event) return STATUS_INSUFFICIENT_RESOURCES; 1405 1406 /* Initialize it */ 1407 KeInitializeEvent(Event, NotificationEvent, FALSE); 1408 1409 /* Build the IRP */ 1410 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 1411 DeviceObject, 1412 NULL, 1413 0UL, 1414 Geometry, 1415 sizeof(DISK_GEOMETRY), 1416 FALSE, 1417 Event, 1418 &IoStatusBlock); 1419 if (!Irp) 1420 { 1421 /* Fail, free the event */ 1422 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1423 return STATUS_INSUFFICIENT_RESOURCES; 1424 } 1425 1426 /* Call the driver and check if it's pending */ 1427 Status = IoCallDriver(DeviceObject, Irp); 1428 if (Status == STATUS_PENDING) 1429 { 1430 /* Wait on the driver */ 1431 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 1432 Status = IoStatusBlock.Status; 1433 } 1434 1435 /* Check if the driver returned success */ 1436 if(NT_SUCCESS(Status)) 1437 { 1438 /* Build another IRP */ 1439 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO, 1440 DeviceObject, 1441 NULL, 1442 0UL, 1443 &PartitionInfo, 1444 sizeof(PARTITION_INFORMATION), 1445 FALSE, 1446 Event, 1447 &IoStatusBlock); 1448 if (!Irp) 1449 { 1450 /* Fail, free the event */ 1451 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1452 return STATUS_INSUFFICIENT_RESOURCES; 1453 } 1454 1455 /* Reset event */ 1456 KeClearEvent(Event); 1457 1458 /* Call the driver and check if it's pending */ 1459 Status = IoCallDriver(DeviceObject, Irp); 1460 if (Status == STATUS_PENDING) 1461 { 1462 /* Wait on the driver */ 1463 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 1464 Status = IoStatusBlock.Status; 1465 } 1466 1467 /* Check if the driver returned success */ 1468 if(NT_SUCCESS(Status)) 1469 { 1470 /* Get the number of sectors */ 1471 *RealSectorCount = (PartitionInfo.PartitionLength.QuadPart / 1472 Geometry->BytesPerSector); 1473 } 1474 } 1475 1476 /* Free the event and return the Status */ 1477 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1478 return Status; 1479 } 1480 1481 BOOLEAN 1482 NTAPI 1483 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry, 1484 IN ULONGLONG MaxOffset, 1485 IN ULONGLONG MaxSector) 1486 { 1487 ULONGLONG EndingSector; 1488 PAGED_CODE(); 1489 1490 /* Unused partitions are considered valid */ 1491 if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE; 1492 1493 /* Get the last sector of the partition */ 1494 EndingSector = GET_STARTING_SECTOR(Entry) + GET_PARTITION_LENGTH(Entry); 1495 1496 /* Check if it's more then the maximum sector */ 1497 if (EndingSector > MaxSector) 1498 { 1499 /* Invalid partition */ 1500 DPRINT1("FSTUB: entry is invalid\n"); 1501 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry)); 1502 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry)); 1503 DPRINT1("FSTUB: end %#I64x\n", EndingSector); 1504 DPRINT1("FSTUB: max %#I64x\n", MaxSector); 1505 return FALSE; 1506 } 1507 else if(GET_STARTING_SECTOR(Entry) > MaxOffset) 1508 { 1509 /* Invalid partition */ 1510 DPRINT1("FSTUB: entry is invalid\n"); 1511 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry)); 1512 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry)); 1513 DPRINT1("FSTUB: end %#I64x\n", EndingSector); 1514 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset); 1515 return FALSE; 1516 } 1517 1518 /* It's fine, return success */ 1519 return TRUE; 1520 } 1521 1522 VOID 1523 NTAPI 1524 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset, 1525 IN PLARGE_INTEGER PartitionLength, 1526 IN CCHAR ShiftCount, 1527 IN ULONG SectorsPerTrack, 1528 IN ULONG NumberOfTracks, 1529 IN ULONG ConventionalCylinders, 1530 OUT PPARTITION_DESCRIPTOR PartitionDescriptor) 1531 { 1532 LARGE_INTEGER FirstSector, SectorCount; 1533 ULONG LastSector, Remainder, SectorsPerCylinder; 1534 ULONG StartingCylinder, EndingCylinder; 1535 ULONG StartingTrack, EndingTrack; 1536 ULONG StartingSector, EndingSector; 1537 PAGED_CODE(); 1538 1539 /* Calculate the number of sectors for each cylinder */ 1540 SectorsPerCylinder = SectorsPerTrack * NumberOfTracks; 1541 1542 /* Calculate the first sector, and the sector count */ 1543 FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount; 1544 SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount; 1545 1546 /* Now calculate the last sector */ 1547 LastSector = FirstSector.LowPart + SectorCount.LowPart - 1; 1548 1549 /* Calculate the first and last cylinders */ 1550 StartingCylinder = FirstSector.LowPart / SectorsPerCylinder; 1551 EndingCylinder = LastSector / SectorsPerCylinder; 1552 1553 /* Set the default number of cylinders */ 1554 if (!ConventionalCylinders) ConventionalCylinders = 1024; 1555 1556 /* Normalize the values */ 1557 if (StartingCylinder >= ConventionalCylinders) 1558 { 1559 /* Set the maximum to 1023 */ 1560 StartingCylinder = ConventionalCylinders - 1; 1561 } 1562 if (EndingCylinder >= ConventionalCylinders) 1563 { 1564 /* Set the maximum to 1023 */ 1565 EndingCylinder = ConventionalCylinders - 1; 1566 } 1567 1568 /* Calculate the starting head and sector that still remain */ 1569 Remainder = FirstSector.LowPart % SectorsPerCylinder; 1570 StartingTrack = Remainder / SectorsPerTrack; 1571 StartingSector = Remainder % SectorsPerTrack; 1572 1573 /* Calculate the ending head and sector that still remain */ 1574 Remainder = LastSector % SectorsPerCylinder; 1575 EndingTrack = Remainder / SectorsPerTrack; 1576 EndingSector = Remainder % SectorsPerTrack; 1577 1578 /* Set cylinder data for the MSB */ 1579 PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder; 1580 PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder; 1581 1582 /* Set the track data */ 1583 PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack; 1584 PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack; 1585 1586 /* Update cylinder data for the LSB */ 1587 StartingCylinder = ((StartingSector + 1) & 0x3F) | 1588 ((StartingCylinder >> 2) & 0xC0); 1589 EndingCylinder = ((EndingSector + 1) & 0x3F) | 1590 ((EndingCylinder >> 2) & 0xC0); 1591 1592 /* Set the cylinder data for the LSB */ 1593 PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder; 1594 PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder; 1595 } 1596 1597 VOID 1598 FASTCALL 1599 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject, 1600 IN PULONG ConventionalCylinders, 1601 IN PLONGLONG DiskSize) 1602 { 1603 PDISK_GEOMETRY DiskGeometry = NULL; 1604 PIO_STATUS_BLOCK IoStatusBlock = NULL; 1605 PKEVENT Event = NULL; 1606 PIRP Irp; 1607 NTSTATUS Status; 1608 1609 /* Set defaults */ 1610 *ConventionalCylinders = 0; 1611 *DiskSize = 0; 1612 1613 /* Allocate the structure in nonpaged pool */ 1614 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool, 1615 sizeof(DISK_GEOMETRY), 1616 TAG_FILE_SYSTEM); 1617 if (!DiskGeometry) goto Cleanup; 1618 1619 /* Allocate the status block in nonpaged pool */ 1620 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool, 1621 sizeof(IO_STATUS_BLOCK), 1622 TAG_FILE_SYSTEM); 1623 if (!IoStatusBlock) goto Cleanup; 1624 1625 /* Allocate the event in nonpaged pool too */ 1626 Event = ExAllocatePoolWithTag(NonPagedPool, 1627 sizeof(KEVENT), 1628 TAG_FILE_SYSTEM); 1629 if (!Event) goto Cleanup; 1630 1631 /* Initialize the event */ 1632 KeInitializeEvent(Event, NotificationEvent, FALSE); 1633 1634 /* Build the IRP */ 1635 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 1636 DeviceObject, 1637 NULL, 1638 0, 1639 DiskGeometry, 1640 sizeof(DISK_GEOMETRY), 1641 FALSE, 1642 Event, 1643 IoStatusBlock); 1644 if (!Irp) goto Cleanup; 1645 1646 /* Now call the driver */ 1647 Status = IoCallDriver(DeviceObject, Irp); 1648 if (Status == STATUS_PENDING) 1649 { 1650 /* Wait for it to complete */ 1651 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 1652 Status = IoStatusBlock->Status; 1653 } 1654 1655 /* Check driver status */ 1656 if (NT_SUCCESS(Status)) 1657 { 1658 /* Return the cylinder count */ 1659 *ConventionalCylinders = DiskGeometry->Cylinders.LowPart; 1660 1661 /* Make sure it's not larger then 1024 */ 1662 if (DiskGeometry->Cylinders.LowPart >= 1024) 1663 { 1664 /* Otherwise, normalize the value */ 1665 *ConventionalCylinders = 1024; 1666 } 1667 1668 /* Calculate the disk size */ 1669 *DiskSize = DiskGeometry->Cylinders.QuadPart * 1670 DiskGeometry->TracksPerCylinder * 1671 DiskGeometry->SectorsPerTrack * 1672 DiskGeometry->BytesPerSector; 1673 } 1674 1675 Cleanup: 1676 /* Free all the pointers */ 1677 if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1678 if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM); 1679 if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM); 1680 return; 1681 } 1682 1683 VOID 1684 FASTCALL 1685 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject, 1686 IN ULONG SectorSize, 1687 IN ULONG MbrTypeIdentifier, 1688 OUT PVOID *MbrBuffer) 1689 { 1690 LARGE_INTEGER Offset; 1691 PUCHAR Buffer; 1692 ULONG BufferSize; 1693 KEVENT Event; 1694 IO_STATUS_BLOCK IoStatusBlock; 1695 PIRP Irp; 1696 PPARTITION_DESCRIPTOR PartitionDescriptor; 1697 NTSTATUS Status; 1698 PIO_STACK_LOCATION IoStackLocation; 1699 Offset.QuadPart = 0; 1700 1701 /* Assume failure */ 1702 *MbrBuffer = NULL; 1703 1704 /* Normalize the buffer size */ 1705 BufferSize = max(SectorSize, 512); 1706 1707 /* Allocate the buffer */ 1708 Buffer = ExAllocatePoolWithTag(NonPagedPool, 1709 PAGE_SIZE > BufferSize ? 1710 PAGE_SIZE : BufferSize, 1711 TAG_FILE_SYSTEM); 1712 if (!Buffer) return; 1713 1714 /* Initialize the Event */ 1715 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1716 1717 /* Build the IRP */ 1718 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1719 DeviceObject, 1720 Buffer, 1721 BufferSize, 1722 &Offset, 1723 &Event, 1724 &IoStatusBlock); 1725 if (!Irp) 1726 { 1727 /* Failed */ 1728 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1729 return; 1730 } 1731 1732 /* Make sure to override volume verification */ 1733 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1734 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1735 1736 /* Call the driver */ 1737 Status = IoCallDriver(DeviceObject, Irp); 1738 if (Status == STATUS_PENDING) 1739 { 1740 /* Wait for completion */ 1741 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1742 Status = IoStatusBlock.Status; 1743 } 1744 1745 /* Check driver Status */ 1746 if (NT_SUCCESS(Status)) 1747 { 1748 /* Validate the MBR Signature */ 1749 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1750 { 1751 /* Failed */ 1752 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1753 return; 1754 } 1755 1756 /* Get the partition entry */ 1757 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1758 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1759 1760 /* Make sure it's what the caller wanted */ 1761 if (PartitionDescriptor->PartitionType != MbrTypeIdentifier) 1762 { 1763 /* It's not, free our buffer */ 1764 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1765 } 1766 else 1767 { 1768 /* Check if this is a secondary entry */ 1769 if (PartitionDescriptor->PartitionType == 0x54) 1770 { 1771 /* Return our buffer, but at sector 63 */ 1772 *(PULONG)Buffer = 63; 1773 *MbrBuffer = Buffer; 1774 } 1775 else if (PartitionDescriptor->PartitionType == 0x55) 1776 { 1777 /* EZ Drive, return the buffer directly */ 1778 *MbrBuffer = Buffer; 1779 } 1780 else 1781 { 1782 /* Otherwise crash on debug builds */ 1783 ASSERT(PartitionDescriptor->PartitionType == 0x55); 1784 } 1785 } 1786 } 1787 } 1788 1789 VOID 1790 NTAPI 1791 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor, 1792 IN ULONGLONG MaxOffset) 1793 { 1794 ULONG PartitionMaxOffset, PartitionLength; 1795 PAGED_CODE(); 1796 1797 /* Compute partition length (according to MBR entry) */ 1798 PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor); 1799 /* In case the partition length goes beyond disk size... */ 1800 if (PartitionMaxOffset > MaxOffset) 1801 { 1802 /* Resize partition to its maximum real length */ 1803 PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor)); 1804 SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength); 1805 } 1806 } 1807 1808 NTSTATUS 1809 FASTCALL 1810 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, 1811 IN ULONG SectorSize, 1812 IN BOOLEAN ReturnRecognizedPartitions, 1813 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer) 1814 { 1815 KEVENT Event; 1816 IO_STATUS_BLOCK IoStatusBlock; 1817 PIRP Irp; 1818 PPARTITION_DESCRIPTOR PartitionDescriptor; 1819 CCHAR Entry; 1820 NTSTATUS Status; 1821 PPARTITION_INFORMATION PartitionInfo; 1822 PUCHAR Buffer = NULL; 1823 ULONG BufferSize = 2048, InputSize; 1824 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL; 1825 LONG j = -1, i = -1, k; 1826 DISK_GEOMETRY DiskGeometry; 1827 LONGLONG EndSector, MaxSector, StartOffset; 1828 ULONGLONG MaxOffset; 1829 LARGE_INTEGER Offset, VolumeOffset; 1830 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE; 1831 BOOLEAN IsValid, IsEmpty = TRUE; 1832 PVOID MbrBuffer; 1833 PIO_STACK_LOCATION IoStackLocation; 1834 UCHAR PartitionType; 1835 LARGE_INTEGER HiddenSectors64; 1836 VolumeOffset.QuadPart = Offset.QuadPart = 0; 1837 PAGED_CODE(); 1838 1839 /* Allocate the buffer */ 1840 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 1841 BufferSize, 1842 TAG_FILE_SYSTEM); 1843 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES; 1844 1845 /* Normalize the buffer size */ 1846 InputSize = max(512, SectorSize); 1847 1848 /* Check for EZ Drive */ 1849 HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer); 1850 if (MbrBuffer) 1851 { 1852 /* EZ Drive found, bias the offset */ 1853 IsEzDrive = TRUE; 1854 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 1855 Offset.QuadPart = 512; 1856 } 1857 1858 /* Get drive geometry */ 1859 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset); 1860 if (!NT_SUCCESS(Status)) 1861 { 1862 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1863 *PartitionBuffer = NULL; 1864 return Status; 1865 } 1866 1867 /* Get the end and maximum sector */ 1868 EndSector = MaxOffset; 1869 MaxSector = MaxOffset << 1; 1870 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n", 1871 MaxOffset, MaxSector); 1872 1873 /* Allocate our buffer */ 1874 Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM); 1875 if (!Buffer) 1876 { 1877 /* Fail, free the input buffer */ 1878 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1879 *PartitionBuffer = NULL; 1880 return STATUS_INSUFFICIENT_RESOURCES; 1881 } 1882 1883 /* Start partition loop */ 1884 do 1885 { 1886 /* Assume the partition is valid */ 1887 IsValid = TRUE; 1888 1889 /* Initialize the event */ 1890 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1891 1892 /* Clear the buffer and build the IRP */ 1893 RtlZeroMemory(Buffer, InputSize); 1894 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1895 DeviceObject, 1896 Buffer, 1897 InputSize, 1898 &Offset, 1899 &Event, 1900 &IoStatusBlock); 1901 if (!Irp) 1902 { 1903 /* Failed */ 1904 Status = STATUS_INSUFFICIENT_RESOURCES; 1905 break; 1906 } 1907 1908 /* Make sure to disable volume verification */ 1909 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1910 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1911 1912 /* Call the driver */ 1913 Status = IoCallDriver(DeviceObject, Irp); 1914 if (Status == STATUS_PENDING) 1915 { 1916 /* Wait for completion */ 1917 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1918 Status = IoStatusBlock.Status; 1919 } 1920 1921 /* Normalize status code and check for failure */ 1922 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS; 1923 if (!NT_SUCCESS(Status)) break; 1924 1925 /* If we biased for EZ-Drive, unbias now */ 1926 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 1927 1928 /* Make sure this is a valid MBR */ 1929 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1930 { 1931 /* It's not, fail */ 1932 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in " 1933 "partition table %d\n", j + 1); 1934 break; 1935 } 1936 1937 /* At this point we have a valid MBR */ 1938 MbrFound = TRUE; 1939 1940 /* Check if we weren't given an offset */ 1941 if (!Offset.QuadPart) 1942 { 1943 /* Then read the signature off the disk */ 1944 (*PartitionBuffer)->Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1]; 1945 } 1946 1947 /* Get the partition descriptor array */ 1948 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1949 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1950 1951 /* Start looping partitions */ 1952 j++; 1953 DPRINT("FSTUB: Partition Table %d:\n", j); 1954 for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++) 1955 { 1956 /* Get the partition type */ 1957 PartitionType = PartitionDescriptor->PartitionType; 1958 1959 /* Print debug messages */ 1960 DPRINT("Partition Entry %d,%d: type %#x %s\n", 1961 j, 1962 Entry, 1963 PartitionType, 1964 (PartitionDescriptor->ActiveFlag) ? "Active" : ""); 1965 DPRINT("\tOffset %#08lx for %#08lx Sectors\n", 1966 GET_STARTING_SECTOR(PartitionDescriptor), 1967 GET_PARTITION_LENGTH(PartitionDescriptor)); 1968 1969 /* Check whether we're facing a protective MBR */ 1970 if (PartitionType == EFI_PMBR_OSTYPE_EFI) 1971 { 1972 /* Partition length might be bigger than disk size */ 1973 FstubFixupEfiPartition(PartitionDescriptor, 1974 MaxOffset); 1975 } 1976 1977 /* Make sure that the partition is valid, unless it's the first */ 1978 if (!(HalpIsValidPartitionEntry(PartitionDescriptor, 1979 MaxOffset, 1980 MaxSector)) && (j == 0)) 1981 { 1982 /* It's invalid, so fail */ 1983 IsValid = FALSE; 1984 break; 1985 } 1986 1987 /* Check if it's a container */ 1988 if (IsContainerPartition(PartitionType)) 1989 { 1990 /* Increase the count of containers */ 1991 if (++k != 1) 1992 { 1993 /* More then one table is invalid */ 1994 DPRINT1("FSTUB: Multiple container partitions found in " 1995 "partition table %d\n - table is invalid\n", 1996 j); 1997 IsValid = FALSE; 1998 break; 1999 } 2000 } 2001 2002 /* Check if the partition is supposedly empty */ 2003 if (IsEmpty) 2004 { 2005 /* But check if it actually has a start and/or length */ 2006 if ((GET_STARTING_SECTOR(PartitionDescriptor)) || 2007 (GET_PARTITION_LENGTH(PartitionDescriptor))) 2008 { 2009 /* So then it's not really empty */ 2010 IsEmpty = FALSE; 2011 } 2012 } 2013 2014 /* Check if the caller wanted only recognized partitions */ 2015 if (ReturnRecognizedPartitions) 2016 { 2017 /* Then check if this one is unused, or a container */ 2018 if ((PartitionType == PARTITION_ENTRY_UNUSED) || 2019 IsContainerPartition(PartitionType)) 2020 { 2021 /* Skip it, since the caller doesn't want it */ 2022 continue; 2023 } 2024 } 2025 2026 /* Increase the structure count and check if they can fit */ 2027 if ((sizeof(DRIVE_LAYOUT_INFORMATION) + 2028 (++i * sizeof(PARTITION_INFORMATION))) > 2029 BufferSize) 2030 { 2031 /* Allocate a new buffer that's twice as big */ 2032 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool, 2033 BufferSize << 1, 2034 TAG_FILE_SYSTEM); 2035 if (!DriveLayoutInfo) 2036 { 2037 /* Out of memory, unto this extra structure */ 2038 --i; 2039 Status = STATUS_INSUFFICIENT_RESOURCES; 2040 break; 2041 } 2042 2043 /* Copy the contents of the old buffer */ 2044 RtlMoveMemory(DriveLayoutInfo, 2045 *PartitionBuffer, 2046 BufferSize); 2047 2048 /* Free the old buffer and set this one as the new one */ 2049 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 2050 *PartitionBuffer = DriveLayoutInfo; 2051 2052 /* Double the size */ 2053 BufferSize <<= 1; 2054 } 2055 2056 /* Now get the current structure being filled and initialize it */ 2057 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i]; 2058 PartitionInfo->PartitionType = PartitionType; 2059 PartitionInfo->RewritePartition = FALSE; 2060 2061 /* Check if we're dealing with a partition that's in use */ 2062 if (PartitionType != PARTITION_ENTRY_UNUSED) 2063 { 2064 /* Check if it's bootable */ 2065 PartitionInfo->BootIndicator = PartitionDescriptor-> 2066 ActiveFlag & 0x80 ? 2067 TRUE : FALSE; 2068 2069 /* Check if its' a container */ 2070 if (IsContainerPartition(PartitionType)) 2071 { 2072 /* Then don't recognize it and use the volume offset */ 2073 PartitionInfo->RecognizedPartition = FALSE; 2074 StartOffset = VolumeOffset.QuadPart; 2075 } 2076 else 2077 { 2078 /* Then recognize it and use the partition offset */ 2079 PartitionInfo->RecognizedPartition = TRUE; 2080 StartOffset = Offset.QuadPart; 2081 } 2082 2083 /* Get the starting offset */ 2084 PartitionInfo->StartingOffset.QuadPart = 2085 StartOffset + 2086 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor), 2087 SectorSize); 2088 2089 /* Calculate the number of hidden sectors */ 2090 HiddenSectors64.QuadPart = (PartitionInfo-> 2091 StartingOffset.QuadPart - 2092 StartOffset) / 2093 SectorSize; 2094 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart; 2095 2096 /* Get the partition length */ 2097 PartitionInfo->PartitionLength.QuadPart = 2098 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor), 2099 SectorSize); 2100 2101 /* Get the partition number */ 2102 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0; 2103 } 2104 else 2105 { 2106 /* Otherwise, clear all the relevant fields */ 2107 PartitionInfo->BootIndicator = FALSE; 2108 PartitionInfo->RecognizedPartition = FALSE; 2109 PartitionInfo->StartingOffset.QuadPart = 0; 2110 PartitionInfo->PartitionLength.QuadPart = 0; 2111 PartitionInfo->HiddenSectors = 0; 2112 2113 PartitionInfo->PartitionNumber = 0; 2114 } 2115 } 2116 2117 /* Finish debug log, and check for failure */ 2118 DPRINT("\n"); 2119 if (!NT_SUCCESS(Status)) break; 2120 2121 /* Also check if we hit an invalid entry here */ 2122 if (!IsValid) 2123 { 2124 /* We did, so break out of the loop minus one entry */ 2125 j--; 2126 break; 2127 } 2128 2129 /* Reset the offset */ 2130 Offset.QuadPart = 0; 2131 2132 /* Go back to the descriptor array and loop it */ 2133 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 2134 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 2135 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 2136 { 2137 /* Check if this is a container partition, since we skipped them */ 2138 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 2139 { 2140 /* Get its offset */ 2141 Offset.QuadPart = VolumeOffset.QuadPart + 2142 UInt32x32To64( 2143 GET_STARTING_SECTOR(PartitionDescriptor), 2144 SectorSize); 2145 2146 /* If this is a primary partition, this is the volume offset */ 2147 if (IsPrimary) VolumeOffset = Offset; 2148 2149 /* Also update the maximum sector */ 2150 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor); 2151 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector); 2152 break; 2153 } 2154 } 2155 2156 /* Loop the next partitions, which are not primary anymore */ 2157 IsPrimary = FALSE; 2158 } while (Offset.HighPart | Offset.LowPart); 2159 2160 /* Check if this is a removable device that's probably a super-floppy */ 2161 if ((DiskGeometry.MediaType == RemovableMedia) && 2162 (j == 0) && (MbrFound) && (IsEmpty)) 2163 { 2164 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer; 2165 2166 /* Read the jump bytes to detect super-floppy */ 2167 if ((BootSectorInfo->JumpByte[0] == 0xeb) || 2168 (BootSectorInfo->JumpByte[0] == 0xe9)) 2169 { 2170 /* Super floppes don't have typical MBRs, so skip them */ 2171 DPRINT1("FSTUB: Jump byte %#x found along with empty partition " 2172 "table - disk is a super floppy and has no valid MBR\n", 2173 BootSectorInfo->JumpByte); 2174 j = -1; 2175 } 2176 } 2177 2178 /* Check if we're still at partition -1 */ 2179 if (j == -1) 2180 { 2181 /* The likely cause is the super floppy detection above */ 2182 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia)) 2183 { 2184 /* Print out debugging information */ 2185 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a " 2186 "super-floppy\n", 2187 DeviceObject); 2188 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x " 2189 "bytes large\n", 2190 EndSector, EndSector * DiskGeometry.BytesPerSector); 2191 2192 /* We should at least have some sectors */ 2193 if (EndSector > 0) 2194 { 2195 /* Get the entry we'll use */ 2196 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0]; 2197 2198 /* Fill it out with data for a super-floppy */ 2199 PartitionInfo->RewritePartition = FALSE; 2200 PartitionInfo->RecognizedPartition = TRUE; 2201 PartitionInfo->PartitionType = PARTITION_FAT_16; 2202 PartitionInfo->BootIndicator = FALSE; 2203 PartitionInfo->HiddenSectors = 0; 2204 PartitionInfo->StartingOffset.QuadPart = 0; 2205 PartitionInfo->PartitionLength.QuadPart = (EndSector * 2206 DiskGeometry. 2207 BytesPerSector); 2208 2209 /* FIXME: REACTOS HACK */ 2210 PartitionInfo->PartitionNumber = 0; 2211 2212 /* Set the signature and set the count back to 0 */ 2213 (*PartitionBuffer)->Signature = 1; 2214 i = 0; 2215 } 2216 } 2217 else 2218 { 2219 /* Otherwise, this isn't a super floppy, so set an invalid count */ 2220 i = -1; 2221 } 2222 } 2223 2224 /* Set the partition count */ 2225 (*PartitionBuffer)->PartitionCount = ++i; 2226 2227 /* If we have no count, delete the signature */ 2228 if (!i) (*PartitionBuffer)->Signature = 0; 2229 2230 /* Free the buffer and check for success */ 2231 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 2232 if (!NT_SUCCESS(Status)) 2233 { 2234 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 2235 *PartitionBuffer = NULL; 2236 } 2237 2238 /* Return status */ 2239 return Status; 2240 } 2241 2242 NTSTATUS 2243 FASTCALL 2244 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 2245 IN ULONG SectorSize, 2246 IN ULONG PartitionNumber, 2247 IN ULONG PartitionType) 2248 { 2249 PIRP Irp; 2250 KEVENT Event; 2251 IO_STATUS_BLOCK IoStatusBlock; 2252 NTSTATUS Status; 2253 LARGE_INTEGER Offset, VolumeOffset; 2254 PUCHAR Buffer = NULL; 2255 ULONG BufferSize; 2256 ULONG i = 0; 2257 ULONG Entry; 2258 PPARTITION_DESCRIPTOR PartitionDescriptor; 2259 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE; 2260 PVOID MbrBuffer; 2261 PIO_STACK_LOCATION IoStackLocation; 2262 VolumeOffset.QuadPart = Offset.QuadPart = 0; 2263 PAGED_CODE(); 2264 2265 /* Normalize the buffer size */ 2266 BufferSize = max(512, SectorSize); 2267 2268 /* Check for EZ Drive */ 2269 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 2270 if (MbrBuffer) 2271 { 2272 /* EZ Drive found, bias the offset */ 2273 IsEzDrive = TRUE; 2274 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 2275 Offset.QuadPart = 512; 2276 } 2277 2278 /* Allocate our partition buffer */ 2279 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 2280 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 2281 2282 /* Initialize the event we'll use and loop partitions */ 2283 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2284 do 2285 { 2286 /* Reset the event since we reuse it */ 2287 KeClearEvent(&Event); 2288 2289 /* Build the read IRP */ 2290 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 2291 DeviceObject, 2292 Buffer, 2293 BufferSize, 2294 &Offset, 2295 &Event, 2296 &IoStatusBlock); 2297 if (!Irp) 2298 { 2299 /* Fail */ 2300 Status = STATUS_INSUFFICIENT_RESOURCES; 2301 break; 2302 } 2303 2304 /* Make sure to disable volume verification */ 2305 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2306 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2307 2308 /* Call the driver */ 2309 Status = IoCallDriver(DeviceObject, Irp); 2310 if (Status == STATUS_PENDING) 2311 { 2312 /* Wait for completion */ 2313 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2314 Status = IoStatusBlock.Status; 2315 } 2316 2317 /* Check for failure */ 2318 if (!NT_SUCCESS(Status)) break; 2319 2320 /* If we biased for EZ-Drive, unbias now */ 2321 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2322 2323 /* Make sure this is a valid MBR */ 2324 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 2325 { 2326 /* It's not, fail */ 2327 Status = STATUS_BAD_MASTER_BOOT_RECORD; 2328 break; 2329 } 2330 2331 /* Get the partition descriptors and loop them */ 2332 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 2333 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 2334 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 2335 { 2336 /* Check if it's unused or a container partition */ 2337 if ((PartitionDescriptor->PartitionType == 2338 PARTITION_ENTRY_UNUSED) || 2339 (IsContainerPartition(PartitionDescriptor->PartitionType))) 2340 { 2341 /* Go to the next one */ 2342 continue; 2343 } 2344 2345 /* It's a valid partition, so increase the partition count */ 2346 if (++i == PartitionNumber) 2347 { 2348 /* We found a match, set the type */ 2349 PartitionDescriptor->PartitionType = (UCHAR)PartitionType; 2350 2351 /* Reset the reusable event */ 2352 KeClearEvent(&Event); 2353 2354 /* Build the write IRP */ 2355 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 2356 DeviceObject, 2357 Buffer, 2358 BufferSize, 2359 &Offset, 2360 &Event, 2361 &IoStatusBlock); 2362 if (!Irp) 2363 { 2364 /* Fail */ 2365 Status = STATUS_INSUFFICIENT_RESOURCES; 2366 break; 2367 } 2368 2369 /* Disable volume verification */ 2370 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2371 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2372 2373 /* Call the driver */ 2374 Status = IoCallDriver(DeviceObject, Irp); 2375 if (Status == STATUS_PENDING) 2376 { 2377 /* Wait for completion */ 2378 KeWaitForSingleObject(&Event, 2379 Executive, 2380 KernelMode, 2381 FALSE, 2382 NULL); 2383 Status = IoStatusBlock.Status; 2384 } 2385 2386 /* We're done, break out of the loop */ 2387 break; 2388 } 2389 } 2390 2391 /* If we looped all the partitions, break out */ 2392 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break; 2393 2394 /* Nothing found yet, get the partition array again */ 2395 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 2396 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 2397 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 2398 { 2399 /* Check if this was a container partition (we skipped these) */ 2400 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 2401 { 2402 /* Update the partition offset */ 2403 Offset.QuadPart = VolumeOffset.QuadPart + 2404 GET_STARTING_SECTOR(PartitionDescriptor) * 2405 SectorSize; 2406 2407 /* If this was the primary partition, update the volume too */ 2408 if (IsPrimary) VolumeOffset = Offset; 2409 break; 2410 } 2411 } 2412 2413 /* Check if we already searched all the partitions */ 2414 if (Entry > NUM_PARTITION_TABLE_ENTRIES) 2415 { 2416 /* Then we failed to find a good MBR */ 2417 Status = STATUS_BAD_MASTER_BOOT_RECORD; 2418 break; 2419 } 2420 2421 /* Loop the next partitions, which are not primary anymore */ 2422 IsPrimary = FALSE; 2423 } while (i < PartitionNumber); 2424 2425 /* Everything done, cleanup */ 2426 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 2427 return Status; 2428 } 2429 2430 NTSTATUS 2431 FASTCALL 2432 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 2433 IN ULONG SectorSize, 2434 IN ULONG SectorsPerTrack, 2435 IN ULONG NumberOfHeads, 2436 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 2437 { 2438 KEVENT Event; 2439 IO_STATUS_BLOCK IoStatusBlock; 2440 PIRP Irp; 2441 NTSTATUS Status = STATUS_SUCCESS; 2442 ULONG BufferSize; 2443 PUSHORT Buffer; 2444 PPTE Entry; 2445 PPARTITION_TABLE PartitionTable; 2446 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset; 2447 LARGE_INTEGER StartOffset, PartitionLength; 2448 ULONG i, j; 2449 CCHAR k; 2450 BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr; 2451 ULONG ConventionalCylinders; 2452 LONGLONG DiskSize; 2453 PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer; 2454 PVOID MbrBuffer; 2455 UCHAR PartitionType; 2456 PIO_STACK_LOCATION IoStackLocation; 2457 PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry; 2458 PPARTITION_INFORMATION TableEntry; 2459 ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0; 2460 PAGED_CODE(); 2461 2462 /* Normalize the buffer size */ 2463 BufferSize = max(512, SectorSize); 2464 2465 /* Get the partial drive geometry */ 2466 xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize); 2467 2468 /* Check for EZ Drive */ 2469 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 2470 if (MbrBuffer) 2471 { 2472 /* EZ Drive found, bias the offset */ 2473 IsEzDrive = TRUE; 2474 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 2475 Offset.QuadPart = 512; 2476 } 2477 2478 /* Get the number of bits to shift to multiply by the sector size */ 2479 for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break; 2480 2481 /* Check if there's only one partition */ 2482 if (PartitionBuffer->PartitionCount == 1) 2483 { 2484 /* Check if it has no starting offset or hidden sectors */ 2485 if (!(PartitionInfo->StartingOffset.QuadPart) && 2486 !(PartitionInfo->HiddenSectors)) 2487 { 2488 /* Then it's a super floppy */ 2489 IsSuperFloppy = TRUE; 2490 2491 /* Which also means it must be non-bootable FAT-16 */ 2492 if ((PartitionInfo->PartitionNumber) || 2493 (PartitionInfo->PartitionType != PARTITION_FAT_16) || 2494 (PartitionInfo->BootIndicator)) 2495 { 2496 /* It's not, so we fail */ 2497 return STATUS_INVALID_PARAMETER; 2498 } 2499 2500 /* Check if it needs a rewrite, and disable EZ drive for sure */ 2501 if (PartitionInfo->RewritePartition) DoRewrite = TRUE; 2502 IsEzDrive = FALSE; 2503 } 2504 } 2505 2506 /* Count the number of partition tables */ 2507 DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4; 2508 2509 /* Allocate our partition buffer */ 2510 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 2511 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 2512 2513 /* Loop the entries */ 2514 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET]; 2515 for (i = 0; i < DiskLayout->TableCount; i++) 2516 { 2517 /* Set if this is the MBR partition */ 2518 IsMbr= (BOOLEAN)!i; 2519 2520 /* Initialize th event */ 2521 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2522 2523 /* Build the read IRP */ 2524 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 2525 DeviceObject, 2526 Buffer, 2527 BufferSize, 2528 &Offset, 2529 &Event, 2530 &IoStatusBlock); 2531 if (!Irp) 2532 { 2533 /* Fail */ 2534 Status = STATUS_INSUFFICIENT_RESOURCES; 2535 break; 2536 } 2537 2538 /* Make sure to disable volume verification */ 2539 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2540 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2541 2542 /* Call the driver */ 2543 Status = IoCallDriver(DeviceObject, Irp); 2544 if (Status == STATUS_PENDING) 2545 { 2546 /* Wait for completion */ 2547 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2548 Status = IoStatusBlock.Status; 2549 } 2550 2551 /* Check for failure */ 2552 if (!NT_SUCCESS(Status)) break; 2553 2554 /* If we biased for EZ-Drive, unbias now */ 2555 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2556 2557 /* Check if this is a normal disk */ 2558 if (!IsSuperFloppy) 2559 { 2560 /* Set the boot record signature */ 2561 Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE; 2562 2563 /* By default, don't require a rewrite */ 2564 DoRewrite = FALSE; 2565 2566 /* Check if we don't have an offset */ 2567 if (!Offset.QuadPart) 2568 { 2569 /* Check if the signature doesn't match */ 2570 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] != 2571 PartitionBuffer->Signature) 2572 { 2573 /* Then write the signature and now we need a rewrite */ 2574 ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] = 2575 PartitionBuffer->Signature; 2576 DoRewrite = TRUE; 2577 } 2578 } 2579 2580 /* Loop the partition table entries */ 2581 PartitionTable = &DiskLayout->PartitionTable[i]; 2582 for (j = 0; j < 4; j++) 2583 { 2584 /* Get the current entry and type */ 2585 TableEntry = &PartitionTable->PartitionEntry[j]; 2586 PartitionType = TableEntry->PartitionType; 2587 2588 /* Check if the entry needs a rewrite */ 2589 if (TableEntry->RewritePartition) 2590 { 2591 /* Then we need one too */ 2592 DoRewrite = TRUE; 2593 2594 /* Save the type and if it's a bootable partition */ 2595 Entry[j].PartitionType = TableEntry->PartitionType; 2596 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0; 2597 2598 /* Make sure it's used */ 2599 if (PartitionType != PARTITION_ENTRY_UNUSED) 2600 { 2601 /* Make sure it's not a container (unless primary) */ 2602 if ((IsMbr) || !(IsContainerPartition(PartitionType))) 2603 { 2604 /* Use the partition offset */ 2605 StartOffset.QuadPart = Offset.QuadPart; 2606 } 2607 else 2608 { 2609 /* Use the extended logical partition offset */ 2610 StartOffset.QuadPart = ExtendedOffset.QuadPart; 2611 } 2612 2613 /* Set the sector offset */ 2614 SectorOffset.QuadPart = TableEntry-> 2615 StartingOffset.QuadPart - 2616 StartOffset.QuadPart; 2617 2618 /* Now calculate the starting sector */ 2619 StartOffset.QuadPart = SectorOffset.QuadPart >> k; 2620 Entry[j].StartingSector = StartOffset.LowPart; 2621 2622 /* As well as the length */ 2623 PartitionLength.QuadPart = TableEntry->PartitionLength. 2624 QuadPart >> k; 2625 Entry[j].PartitionLength = PartitionLength.LowPart; 2626 2627 /* Calculate the CHS values */ 2628 HalpCalculateChsValues(&TableEntry->StartingOffset, 2629 &TableEntry->PartitionLength, 2630 k, 2631 SectorsPerTrack, 2632 NumberOfHeads, 2633 ConventionalCylinders, 2634 (PPARTITION_DESCRIPTOR) 2635 &Entry[j]); 2636 } 2637 else 2638 { 2639 /* Otherwise set up an empty entry */ 2640 Entry[j].StartingSector = 0; 2641 Entry[j].PartitionLength = 0; 2642 Entry[j].StartingTrack = 0; 2643 Entry[j].EndingTrack = 0; 2644 Entry[j].StartingCylinder = 0; 2645 Entry[j].EndingCylinder = 0; 2646 } 2647 } 2648 2649 /* Check if this is a container partition */ 2650 if (IsContainerPartition(PartitionType)) 2651 { 2652 /* Then update the offset to use */ 2653 NextOffset = TableEntry->StartingOffset; 2654 } 2655 } 2656 } 2657 2658 /* Check if we need to write back the buffer */ 2659 if (DoRewrite) 2660 { 2661 /* We don't need to do this again */ 2662 DoRewrite = FALSE; 2663 2664 /* Initialize the event */ 2665 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2666 2667 /* If we unbiased for EZ-Drive, rebias now */ 2668 if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512; 2669 2670 /* Build the write IRP */ 2671 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 2672 DeviceObject, 2673 Buffer, 2674 BufferSize, 2675 &Offset, 2676 &Event, 2677 &IoStatusBlock); 2678 if (!Irp) 2679 { 2680 /* Fail */ 2681 Status = STATUS_INSUFFICIENT_RESOURCES; 2682 break; 2683 } 2684 2685 /* Make sure to disable volume verification */ 2686 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2687 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2688 2689 /* Call the driver */ 2690 Status = IoCallDriver(DeviceObject, Irp); 2691 if (Status == STATUS_PENDING) 2692 { 2693 /* Wait for completion */ 2694 KeWaitForSingleObject(&Event, 2695 Executive, 2696 KernelMode, 2697 FALSE, 2698 NULL); 2699 Status = IoStatusBlock.Status; 2700 } 2701 2702 /* Check for failure */ 2703 if (!NT_SUCCESS(Status)) break; 2704 2705 /* If we biased for EZ-Drive, unbias now */ 2706 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2707 } 2708 2709 /* Update the partition offset and set the extended offset if needed */ 2710 Offset = NextOffset; 2711 if (IsMbr) ExtendedOffset = NextOffset; 2712 } 2713 2714 /* If we had a buffer, free it, then return status */ 2715 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 2716 return Status; 2717 } 2718 2719 /* PUBLIC FUNCTIONS **********************************************************/ 2720 2721 /* 2722 * @implemented 2723 */ 2724 VOID 2725 FASTCALL 2726 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject, 2727 IN ULONG SectorSize, 2728 IN ULONG MbrTypeIdentifier, 2729 OUT PVOID *MbrBuffer) 2730 { 2731 HALDISPATCH->HalExamineMBR(DeviceObject, 2732 SectorSize, 2733 MbrTypeIdentifier, 2734 MbrBuffer); 2735 } 2736 2737 /* 2738 * @implemented 2739 */ 2740 NTSTATUS 2741 FASTCALL 2742 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, 2743 IN ULONG SectorSize, 2744 IN BOOLEAN ReturnRecognizedPartitions, 2745 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer) 2746 { 2747 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject, 2748 SectorSize, 2749 ReturnRecognizedPartitions, 2750 PartitionBuffer); 2751 } 2752 2753 /* 2754 * @implemented 2755 */ 2756 NTSTATUS 2757 FASTCALL 2758 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 2759 IN ULONG SectorSize, 2760 IN ULONG PartitionNumber, 2761 IN ULONG PartitionType) 2762 { 2763 return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject, 2764 SectorSize, 2765 PartitionNumber, 2766 PartitionType); 2767 } 2768 2769 /* 2770 * @implemented 2771 */ 2772 NTSTATUS 2773 FASTCALL 2774 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 2775 IN ULONG SectorSize, 2776 IN ULONG SectorsPerTrack, 2777 IN ULONG NumberOfHeads, 2778 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 2779 { 2780 return HALDISPATCH->HalIoWritePartitionTable(DeviceObject, 2781 SectorSize, 2782 SectorsPerTrack, 2783 NumberOfHeads, 2784 PartitionBuffer); 2785 } 2786 2787 /* 2788 * @implemented 2789 */ 2790 VOID 2791 FASTCALL 2792 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 2793 IN PSTRING NtDeviceName, 2794 OUT PUCHAR NtSystemPath, 2795 OUT PSTRING NtSystemPathString) 2796 { 2797 HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock, 2798 NtDeviceName, 2799 NtSystemPath, 2800 NtSystemPathString); 2801 } 2802 2803 /* EOF */ 2804