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 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 #include <internal/hal.h> 17 18 /* DEPRECATED FUNCTIONS ******************************************************/ 19 20 #if 1 21 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:"; 22 23 #define AUTO_DRIVE MAXULONG 24 25 #define PARTITION_MAGIC 0xaa55 26 27 #define EFI_PMBR_OSTYPE_EFI 0xEE 28 29 #include <pshpack1.h> 30 31 typedef struct _REG_DISK_MOUNT_INFO 32 { 33 ULONG Signature; 34 LARGE_INTEGER StartingOffset; 35 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO; 36 37 #include <poppack.h> 38 39 typedef enum _DISK_MANAGER 40 { 41 NoDiskManager, 42 OntrackDiskManager, 43 EZ_Drive 44 } DISK_MANAGER; 45 46 static BOOLEAN 47 HalpAssignDrive(IN PUNICODE_STRING PartitionName, 48 IN ULONG DriveNumber, 49 IN UCHAR DriveType, 50 IN ULONG Signature, 51 IN LARGE_INTEGER StartingOffset, 52 IN HANDLE hKey, 53 IN PUNICODE_STRING BootDevice, 54 OUT PUCHAR NtSystemPath) 55 { 56 WCHAR DriveNameBuffer[16]; 57 UNICODE_STRING DriveName; 58 ULONG i; 59 NTSTATUS Status; 60 REG_DISK_MOUNT_INFO DiskMountInfo; 61 62 DPRINT("HalpAssignDrive()\n"); 63 64 if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26)) 65 { 66 /* Force assignment */ 67 KeAcquireGuardedMutex(&ObpDeviceMapLock); 68 if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0) 69 { 70 DbgPrint("Drive letter already used!\n"); 71 KeReleaseGuardedMutex(&ObpDeviceMapLock); 72 return FALSE; 73 } 74 KeReleaseGuardedMutex(&ObpDeviceMapLock); 75 } 76 else 77 { 78 /* Automatic assignment */ 79 DriveNumber = AUTO_DRIVE; 80 KeAcquireGuardedMutex(&ObpDeviceMapLock); 81 for (i = 2; i < 26; i++) 82 { 83 if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0) 84 { 85 DriveNumber = i; 86 break; 87 } 88 } 89 KeReleaseGuardedMutex(&ObpDeviceMapLock); 90 91 if (DriveNumber == AUTO_DRIVE) 92 { 93 DbgPrint("No drive letter available!\n"); 94 return FALSE; 95 } 96 } 97 98 DPRINT("DriveNumber %lu\n", DriveNumber); 99 100 /* Build drive name */ 101 swprintf(DriveNameBuffer, 102 L"\\??\\%C:", 103 'A' + DriveNumber); 104 RtlInitUnicodeString(&DriveName, 105 DriveNameBuffer); 106 107 DPRINT(" %wZ ==> %wZ\n", 108 &DriveName, 109 PartitionName); 110 111 /* Create symbolic link */ 112 Status = IoCreateSymbolicLink(&DriveName, 113 PartitionName); 114 115 if (hKey && 116 DriveType == DOSDEVICE_DRIVE_FIXED && 117 Signature) 118 { 119 DiskMountInfo.Signature = Signature; 120 DiskMountInfo.StartingOffset = StartingOffset; 121 swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber); 122 RtlInitUnicodeString(&DriveName, DriveNameBuffer); 123 124 Status = ZwSetValueKey(hKey, 125 &DriveName, 126 0, 127 REG_BINARY, 128 &DiskMountInfo, 129 sizeof(DiskMountInfo)); 130 if (!NT_SUCCESS(Status)) 131 { 132 DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status); 133 } 134 } 135 136 /* Check if this is a boot partition */ 137 if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0) 138 { 139 /* Set NtSystemPath to that partition's disk letter */ 140 *NtSystemPath = (UCHAR)('A' + DriveNumber); 141 } 142 143 return TRUE; 144 } 145 146 ULONG 147 xHalpGetRDiskCount(VOID) 148 { 149 NTSTATUS Status; 150 UNICODE_STRING ArcName; 151 PWCHAR ArcNameBuffer; 152 OBJECT_ATTRIBUTES ObjectAttributes; 153 HANDLE DirectoryHandle; 154 POBJECT_DIRECTORY_INFORMATION DirectoryInfo; 155 ULONG Skip; 156 ULONG ResultLength; 157 ULONG CurrentRDisk; 158 ULONG RDiskCount; 159 BOOLEAN First = TRUE; 160 ULONG Count; 161 162 DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM); 163 if (DirectoryInfo == NULL) 164 { 165 return 0; 166 } 167 168 RtlInitUnicodeString(&ArcName, L"\\ArcName"); 169 InitializeObjectAttributes(&ObjectAttributes, 170 &ArcName, 171 0, 172 NULL, 173 NULL); 174 175 Status = ZwOpenDirectoryObject (&DirectoryHandle, 176 DIRECTORY_ALL_ACCESS, 177 &ObjectAttributes); 178 if (!NT_SUCCESS(Status)) 179 { 180 DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status); 181 ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM); 182 return 0; 183 } 184 185 RDiskCount = 0; 186 Skip = 0; 187 while (NT_SUCCESS(Status)) 188 { 189 Status = ZwQueryDirectoryObject (DirectoryHandle, 190 DirectoryInfo, 191 2 * PAGE_SIZE, 192 FALSE, 193 First, 194 &Skip, 195 &ResultLength); 196 First = FALSE; 197 if (NT_SUCCESS(Status)) 198 { 199 Count = 0; 200 while (DirectoryInfo[Count].Name.Buffer) 201 { 202 DPRINT("Count %x\n", Count); 203 DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0; 204 ArcNameBuffer = DirectoryInfo[Count].Name.Buffer; 205 if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) && 206 !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR))) 207 { 208 DPRINT("%S\n", ArcNameBuffer); 209 ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR); 210 CurrentRDisk = 0; 211 while (iswdigit(*ArcNameBuffer)) 212 { 213 CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0'; 214 ArcNameBuffer++; 215 } 216 if (!_wcsicmp(ArcNameBuffer, L")") && 217 CurrentRDisk >= RDiskCount) 218 { 219 RDiskCount = CurrentRDisk + 1; 220 } 221 } 222 Count++; 223 } 224 } 225 } 226 227 ZwClose(DirectoryHandle); 228 229 ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM); 230 return RDiskCount; 231 } 232 233 NTSTATUS 234 xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber) 235 { 236 WCHAR NameBuffer[80]; 237 UNICODE_STRING ArcName; 238 UNICODE_STRING LinkName; 239 OBJECT_ATTRIBUTES ObjectAttributes; 240 HANDLE LinkHandle; 241 NTSTATUS Status; 242 243 swprintf(NameBuffer, 244 L"\\ArcName\\multi(0)disk(0)rdisk(%lu)", 245 RDisk); 246 247 RtlInitUnicodeString(&ArcName, NameBuffer); 248 InitializeObjectAttributes(&ObjectAttributes, 249 &ArcName, 250 0, 251 NULL, 252 NULL); 253 Status = ZwOpenSymbolicLinkObject(&LinkHandle, 254 SYMBOLIC_LINK_ALL_ACCESS, 255 &ObjectAttributes); 256 if (!NT_SUCCESS(Status)) 257 { 258 DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status); 259 return Status; 260 } 261 262 LinkName.Buffer = NameBuffer; 263 LinkName.Length = 0; 264 LinkName.MaximumLength = sizeof(NameBuffer); 265 Status = ZwQuerySymbolicLinkObject(LinkHandle, 266 &LinkName, 267 NULL); 268 ZwClose(LinkHandle); 269 if (!NT_SUCCESS(Status)) 270 { 271 DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status); 272 return Status; 273 } 274 if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) || 275 LinkName.Length >= sizeof(NameBuffer)) 276 { 277 return STATUS_UNSUCCESSFUL; 278 } 279 280 NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0; 281 if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR))) 282 { 283 return STATUS_UNSUCCESSFUL; 284 } 285 LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR); 286 287 if (!iswdigit(*LinkName.Buffer)) 288 { 289 return STATUS_UNSUCCESSFUL; 290 } 291 *DiskNumber = 0; 292 while (iswdigit(*LinkName.Buffer)) 293 { 294 *DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0'; 295 LinkName.Buffer++; 296 } 297 if (_wcsicmp(LinkName.Buffer, L"\\Partition0")) 298 { 299 return STATUS_UNSUCCESSFUL; 300 } 301 return STATUS_SUCCESS; 302 } 303 304 NTSTATUS 305 FASTCALL 306 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName, 307 OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo) 308 { 309 IO_STATUS_BLOCK StatusBlock; 310 DISK_GEOMETRY DiskGeometry; 311 PDEVICE_OBJECT DeviceObject = NULL; 312 PFILE_OBJECT FileObject; 313 KEVENT Event; 314 PIRP Irp; 315 NTSTATUS Status; 316 317 DPRINT("xHalpQueryDriveLayout %wZ %p\n", 318 DeviceName, 319 LayoutInfo); 320 321 /* Get the drives sector size */ 322 Status = IoGetDeviceObjectPointer(DeviceName, 323 FILE_READ_ATTRIBUTES, 324 &FileObject, 325 &DeviceObject); 326 if (!NT_SUCCESS(Status)) 327 { 328 DPRINT("Status %x\n", Status); 329 return(Status); 330 } 331 332 KeInitializeEvent(&Event, 333 NotificationEvent, 334 FALSE); 335 336 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 337 DeviceObject, 338 NULL, 339 0, 340 &DiskGeometry, 341 sizeof(DISK_GEOMETRY), 342 FALSE, 343 &Event, 344 &StatusBlock); 345 if (Irp == NULL) 346 { 347 ObDereferenceObject(FileObject); 348 return(STATUS_INSUFFICIENT_RESOURCES); 349 } 350 351 Status = IoCallDriver(DeviceObject, 352 Irp); 353 if (Status == STATUS_PENDING) 354 { 355 KeWaitForSingleObject(&Event, 356 Executive, 357 KernelMode, 358 FALSE, 359 NULL); 360 Status = StatusBlock.Status; 361 } 362 if (!NT_SUCCESS(Status)) 363 { 364 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) 365 { 366 DiskGeometry.BytesPerSector = 512; 367 } 368 else 369 { 370 ObDereferenceObject(FileObject); 371 return(Status); 372 } 373 } 374 375 DPRINT("DiskGeometry.BytesPerSector: %lu\n", 376 DiskGeometry.BytesPerSector); 377 378 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) 379 { 380 PDRIVE_LAYOUT_INFORMATION Buffer; 381 382 /* Allocate a partition list for a single entry. */ 383 Buffer = ExAllocatePoolWithTag(NonPagedPool, 384 sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM); 385 if (Buffer != NULL) 386 { 387 RtlZeroMemory(Buffer, 388 sizeof(DRIVE_LAYOUT_INFORMATION)); 389 Buffer->PartitionCount = 1; 390 *LayoutInfo = Buffer; 391 392 Status = STATUS_SUCCESS; 393 } 394 else 395 { 396 Status = STATUS_UNSUCCESSFUL; 397 } 398 } 399 else 400 { 401 /* Read the partition table */ 402 Status = IoReadPartitionTable(DeviceObject, 403 DiskGeometry.BytesPerSector, 404 TRUE, 405 LayoutInfo); 406 } 407 408 ObDereferenceObject(FileObject); 409 410 return(Status); 411 } 412 413 VOID 414 FASTCALL 415 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 416 IN PSTRING NtDeviceName, 417 OUT PUCHAR NtSystemPath, 418 OUT PSTRING NtSystemPathString) 419 { 420 PDRIVE_LAYOUT_INFORMATION *LayoutArray; 421 PCONFIGURATION_INFORMATION ConfigInfo; 422 OBJECT_ATTRIBUTES ObjectAttributes; 423 IO_STATUS_BLOCK StatusBlock; 424 UNICODE_STRING UnicodeString1; 425 UNICODE_STRING UnicodeString2; 426 HANDLE FileHandle; 427 PWSTR Buffer1; 428 PWSTR Buffer2; 429 ULONG i, j, k; 430 ULONG DiskNumber; 431 ULONG RDisk; 432 NTSTATUS Status; 433 HANDLE hKey; 434 ULONG Length; 435 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation; 436 PREG_DISK_MOUNT_INFO DiskMountInfo; 437 ULONG RDiskCount; 438 UNICODE_STRING BootDevice; 439 440 Status = RtlAnsiStringToUnicodeString(&BootDevice, 441 NtDeviceName, 442 TRUE); 443 444 DPRINT("xHalIoAssignDriveLetters()\n"); 445 446 ConfigInfo = IoGetConfigurationInformation(); 447 448 RDiskCount = xHalpGetRDiskCount(); 449 450 DPRINT("RDiskCount %lu\n", RDiskCount); 451 452 Buffer1 = ExAllocatePoolWithTag(PagedPool, 453 64 * sizeof(WCHAR), 454 TAG_FILE_SYSTEM); 455 if (!Buffer1) return; 456 457 Buffer2 = ExAllocatePoolWithTag(PagedPool, 458 32 * sizeof(WCHAR), 459 TAG_FILE_SYSTEM); 460 if (!Buffer2) 461 { 462 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); 463 return; 464 } 465 466 PartialInformation = ExAllocatePoolWithTag(PagedPool, 467 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO), 468 TAG_FILE_SYSTEM); 469 if (!PartialInformation) 470 { 471 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); 472 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); 473 return; 474 } 475 476 DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data; 477 478 /* Create or open the 'MountedDevices' key */ 479 RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices"); 480 InitializeObjectAttributes(&ObjectAttributes, 481 &UnicodeString1, 482 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 483 NULL, 484 NULL); 485 Status = ZwCreateKey(&hKey, 486 KEY_ALL_ACCESS, 487 &ObjectAttributes, 488 0, 489 NULL, 490 REG_OPTION_NON_VOLATILE, 491 NULL); 492 if (!NT_SUCCESS(Status)) 493 { 494 hKey = NULL; 495 DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status); 496 } 497 498 /* Create PhysicalDrive links */ 499 DPRINT("Physical disk drives: %lu\n", ConfigInfo->DiskCount); 500 for (i = 0; i < ConfigInfo->DiskCount; i++) 501 { 502 swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i); 503 RtlInitUnicodeString(&UnicodeString1, Buffer1); 504 505 InitializeObjectAttributes(&ObjectAttributes, 506 &UnicodeString1, 507 0, 508 NULL, 509 NULL); 510 511 Status = ZwOpenFile(&FileHandle, 512 FILE_READ_DATA | SYNCHRONIZE, 513 &ObjectAttributes, 514 &StatusBlock, 515 FILE_SHARE_READ, 516 FILE_SYNCHRONOUS_IO_NONALERT); 517 if (NT_SUCCESS(Status)) 518 { 519 ZwClose(FileHandle); 520 521 swprintf(Buffer2, L"\\??\\PhysicalDrive%lu", i); 522 RtlInitUnicodeString(&UnicodeString2, Buffer2); 523 524 DPRINT("Creating link: %S ==> %S\n", 525 Buffer2, 526 Buffer1); 527 528 IoCreateSymbolicLink(&UnicodeString2, 529 &UnicodeString1); 530 } 531 } 532 533 /* Initialize layout array */ 534 if (ConfigInfo->DiskCount == 0) 535 goto end_assign_disks; 536 LayoutArray = ExAllocatePoolWithTag(NonPagedPool, 537 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM); 538 if (!LayoutArray) 539 { 540 ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM); 541 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); 542 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); 543 if (hKey) ObCloseHandle(hKey, KernelMode); 544 return; 545 } 546 547 RtlZeroMemory(LayoutArray, 548 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION)); 549 for (i = 0; i < ConfigInfo->DiskCount; i++) 550 { 551 swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i); 552 RtlInitUnicodeString(&UnicodeString1, Buffer1); 553 554 Status = xHalQueryDriveLayout(&UnicodeString1, &LayoutArray[i]); 555 if (!NT_SUCCESS(Status)) 556 { 557 DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n", 558 Status); 559 LayoutArray[i] = NULL; 560 continue; 561 } 562 /* We don't use the RewritePartition value while mounting the disks. 563 * We use this value for marking pre-assigned (registry) partitions. 564 */ 565 for (j = 0; j < LayoutArray[i]->PartitionCount; j++) 566 { 567 LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE; 568 } 569 } 570 571 #ifndef NDEBUG 572 /* Dump layout array */ 573 for (i = 0; i < ConfigInfo->DiskCount; i++) 574 { 575 DPRINT("Harddisk %d:\n", 576 i); 577 578 if (LayoutArray[i] == NULL) 579 continue; 580 581 DPRINT("Logical partitions: %d\n", 582 LayoutArray[i]->PartitionCount); 583 584 for (j = 0; j < LayoutArray[i]->PartitionCount; j++) 585 { 586 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n", 587 j, 588 LayoutArray[i]->PartitionEntry[j].PartitionNumber, 589 LayoutArray[i]->PartitionEntry[j].BootIndicator, 590 LayoutArray[i]->PartitionEntry[j].PartitionType, 591 LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart, 592 LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart); 593 } 594 } 595 #endif 596 597 /* Assign pre-assigned (registry) partitions */ 598 if (hKey) 599 { 600 for (k = 2; k < 26; k++) 601 { 602 swprintf(Buffer1, DiskMountString, L'A' + k); 603 RtlInitUnicodeString(&UnicodeString1, Buffer1); 604 Status = ZwQueryValueKey(hKey, 605 &UnicodeString1, 606 KeyValuePartialInformation, 607 PartialInformation, 608 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO), 609 &Length); 610 if (NT_SUCCESS(Status) && 611 PartialInformation->Type == REG_BINARY && 612 PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO)) 613 { 614 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature, 615 DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart); 616 { 617 BOOLEAN Found = FALSE; 618 for (i = 0; i < ConfigInfo->DiskCount; i++) 619 { 620 DPRINT("%x\n", LayoutArray[i]->Signature); 621 if (LayoutArray[i] && 622 LayoutArray[i]->Signature && 623 LayoutArray[i]->Signature == DiskMountInfo->Signature) 624 { 625 for (j = 0; j < LayoutArray[i]->PartitionCount; j++) 626 { 627 if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart) 628 { 629 if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) && 630 LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE) 631 { 632 swprintf(Buffer2, 633 L"\\Device\\Harddisk%lu\\Partition%lu", 634 i, 635 LayoutArray[i]->PartitionEntry[j].PartitionNumber); 636 RtlInitUnicodeString(&UnicodeString2, Buffer2); 637 638 /* Assign drive */ 639 DPRINT(" %wZ\n", &UnicodeString2); 640 Found = HalpAssignDrive(&UnicodeString2, 641 k, 642 DOSDEVICE_DRIVE_FIXED, 643 DiskMountInfo->Signature, 644 DiskMountInfo->StartingOffset, 645 NULL, 646 &BootDevice, 647 NtSystemPath); 648 /* Mark the partition as assigned */ 649 LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE; 650 } 651 break; 652 } 653 } 654 } 655 } 656 if (Found == FALSE) 657 { 658 /* We didn't find a partition for this entry, remove them. */ 659 Status = ZwDeleteValueKey(hKey, &UnicodeString1); 660 } 661 } 662 } 663 } 664 } 665 666 /* Assign bootable partition on first harddisk */ 667 DPRINT("Assigning bootable primary partition on first harddisk:\n"); 668 if (RDiskCount > 0) 669 { 670 Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber); 671 if (NT_SUCCESS(Status) && 672 DiskNumber < ConfigInfo->DiskCount && 673 LayoutArray[DiskNumber]) 674 { 675 /* Search for bootable partition */ 676 for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++) 677 { 678 if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator != FALSE) && 679 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) 680 { 681 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE) 682 { 683 swprintf(Buffer2, 684 L"\\Device\\Harddisk%lu\\Partition%lu", 685 DiskNumber, 686 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); 687 RtlInitUnicodeString(&UnicodeString2, Buffer2); 688 689 /* Assign drive */ 690 DPRINT(" %wZ\n", &UnicodeString2); 691 HalpAssignDrive(&UnicodeString2, 692 AUTO_DRIVE, 693 DOSDEVICE_DRIVE_FIXED, 694 LayoutArray[DiskNumber]->Signature, 695 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, 696 hKey, 697 &BootDevice, 698 NtSystemPath); 699 /* Mark the partition as assigned */ 700 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; 701 } 702 break; 703 } 704 } 705 } 706 } 707 708 /* Assign remaining primary partitions */ 709 DPRINT("Assigning remaining primary partitions:\n"); 710 for (RDisk = 0; RDisk < RDiskCount; RDisk++) 711 { 712 Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber); 713 if (NT_SUCCESS(Status) && 714 DiskNumber < ConfigInfo->DiskCount && 715 LayoutArray[DiskNumber]) 716 { 717 /* Search for primary partitions */ 718 for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++) 719 { 720 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && 721 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) 722 { 723 swprintf(Buffer2, 724 L"\\Device\\Harddisk%lu\\Partition%lu", 725 DiskNumber, 726 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); 727 RtlInitUnicodeString(&UnicodeString2, Buffer2); 728 729 /* Assign drive */ 730 DPRINT(" %wZ\n", 731 &UnicodeString2); 732 HalpAssignDrive(&UnicodeString2, 733 AUTO_DRIVE, 734 DOSDEVICE_DRIVE_FIXED, 735 LayoutArray[DiskNumber]->Signature, 736 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, 737 hKey, 738 &BootDevice, 739 NtSystemPath); 740 /* Mark the partition as assigned */ 741 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; 742 } 743 } 744 } 745 } 746 747 /* Assign extended (logical) partitions */ 748 DPRINT("Assigning extended (logical) partitions:\n"); 749 for (RDisk = 0; RDisk < RDiskCount; RDisk++) 750 { 751 Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber); 752 if (NT_SUCCESS(Status) && 753 DiskNumber < ConfigInfo->DiskCount && 754 LayoutArray[DiskNumber]) 755 { 756 /* Search for extended partitions */ 757 for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++) 758 { 759 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) && 760 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && 761 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0) 762 { 763 swprintf(Buffer2, 764 L"\\Device\\Harddisk%lu\\Partition%lu", 765 DiskNumber, 766 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); 767 RtlInitUnicodeString(&UnicodeString2, Buffer2); 768 769 /* Assign drive */ 770 DPRINT(" %wZ\n", 771 &UnicodeString2); 772 HalpAssignDrive(&UnicodeString2, 773 AUTO_DRIVE, 774 DOSDEVICE_DRIVE_FIXED, 775 LayoutArray[DiskNumber]->Signature, 776 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, 777 hKey, 778 &BootDevice, 779 NtSystemPath); 780 /* Mark the partition as assigned */ 781 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; 782 } 783 } 784 } 785 } 786 787 /* Assign remaining primary partitions without an arc-name */ 788 DPRINT("Assigning remaining primary partitions:\n"); 789 for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++) 790 { 791 if (LayoutArray[DiskNumber]) 792 { 793 /* Search for primary partitions */ 794 for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++) 795 { 796 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && 797 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) 798 { 799 swprintf(Buffer2, 800 L"\\Device\\Harddisk%lu\\Partition%lu", 801 DiskNumber, 802 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); 803 RtlInitUnicodeString(&UnicodeString2, Buffer2); 804 805 /* Assign drive */ 806 DPRINT(" %wZ\n", 807 &UnicodeString2); 808 HalpAssignDrive(&UnicodeString2, 809 AUTO_DRIVE, 810 DOSDEVICE_DRIVE_FIXED, 811 LayoutArray[DiskNumber]->Signature, 812 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, 813 hKey, 814 &BootDevice, 815 NtSystemPath); 816 /* Mark the partition as assigned */ 817 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; 818 } 819 } 820 } 821 } 822 823 /* Assign extended (logical) partitions without an arc-name */ 824 DPRINT("Assigning extended (logical) partitions:\n"); 825 for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++) 826 { 827 if (LayoutArray[DiskNumber]) 828 { 829 /* Search for extended partitions */ 830 for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++) 831 { 832 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) && 833 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && 834 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0) 835 { 836 swprintf(Buffer2, 837 L"\\Device\\Harddisk%lu\\Partition%lu", 838 DiskNumber, 839 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); 840 RtlInitUnicodeString(&UnicodeString2, Buffer2); 841 842 /* Assign drive */ 843 DPRINT(" %wZ\n", 844 &UnicodeString2); 845 HalpAssignDrive(&UnicodeString2, 846 AUTO_DRIVE, 847 DOSDEVICE_DRIVE_FIXED, 848 LayoutArray[DiskNumber]->Signature, 849 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, 850 hKey, 851 &BootDevice, 852 NtSystemPath); 853 /* Mark the partition as assigned */ 854 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; 855 } 856 } 857 } 858 } 859 860 /* Assign removable disk drives */ 861 DPRINT("Assigning removable disk drives:\n"); 862 for (i = 0; i < ConfigInfo->DiskCount; i++) 863 { 864 if (LayoutArray[i]) 865 { 866 /* Search for virtual partitions */ 867 if (LayoutArray[i]->PartitionCount == 1 && 868 LayoutArray[i]->PartitionEntry[0].PartitionType == 0) 869 { 870 swprintf(Buffer2, L"\\Device\\Harddisk%lu\\Partition1", i); 871 RtlInitUnicodeString(&UnicodeString2, Buffer2); 872 873 /* Assign drive */ 874 DPRINT(" %wZ\n", 875 &UnicodeString2); 876 HalpAssignDrive(&UnicodeString2, 877 AUTO_DRIVE, 878 DOSDEVICE_DRIVE_REMOVABLE, 879 0, 880 RtlConvertLongToLargeInteger(0), 881 hKey, 882 &BootDevice, 883 NtSystemPath); 884 } 885 } 886 } 887 888 /* Free layout array */ 889 for (i = 0; i < ConfigInfo->DiskCount; i++) 890 { 891 if (LayoutArray[i] != NULL) 892 ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM); 893 } 894 ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM); 895 end_assign_disks: 896 897 /* Assign floppy drives */ 898 DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount); 899 for (i = 0; i < ConfigInfo->FloppyCount; i++) 900 { 901 swprintf(Buffer1, L"\\Device\\Floppy%lu", i); 902 RtlInitUnicodeString(&UnicodeString1, Buffer1); 903 904 /* Assign drive letters A: or B: or first free drive letter */ 905 DPRINT(" %wZ\n", 906 &UnicodeString1); 907 HalpAssignDrive(&UnicodeString1, 908 (i < 2) ? i : AUTO_DRIVE, 909 DOSDEVICE_DRIVE_REMOVABLE, 910 0, 911 RtlConvertLongToLargeInteger(0), 912 hKey, 913 &BootDevice, 914 NtSystemPath); 915 } 916 917 /* Assign cdrom drives */ 918 DPRINT("CD-Rom drives: %lu\n", ConfigInfo->CdRomCount); 919 for (i = 0; i < ConfigInfo->CdRomCount; i++) 920 { 921 swprintf(Buffer1, L"\\Device\\CdRom%lu", i); 922 RtlInitUnicodeString(&UnicodeString1, Buffer1); 923 924 /* Assign first free drive letter */ 925 DPRINT(" %wZ\n", &UnicodeString1); 926 HalpAssignDrive(&UnicodeString1, 927 AUTO_DRIVE, 928 DOSDEVICE_DRIVE_CDROM, 929 0, 930 RtlConvertLongToLargeInteger(0), 931 hKey, 932 &BootDevice, 933 NtSystemPath); 934 } 935 936 /* Anything else to do? */ 937 938 ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM); 939 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); 940 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); 941 if (hKey) ObCloseHandle(hKey, KernelMode); 942 } 943 944 #endif 945 946 /* PRIVATE FUNCTIONS *********************************************************/ 947 948 NTSTATUS 949 NTAPI 950 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject, 951 IN PDISK_GEOMETRY Geometry, 952 OUT PULONGLONG RealSectorCount) 953 { 954 PIRP Irp; 955 IO_STATUS_BLOCK IoStatusBlock; 956 PKEVENT Event; 957 NTSTATUS Status; 958 PARTITION_INFORMATION PartitionInfo; 959 PAGED_CODE(); 960 961 /* Allocate a non-paged event */ 962 Event = ExAllocatePoolWithTag(NonPagedPool, 963 sizeof(KEVENT), 964 TAG_FILE_SYSTEM); 965 if (!Event) return STATUS_INSUFFICIENT_RESOURCES; 966 967 /* Initialize it */ 968 KeInitializeEvent(Event, NotificationEvent, FALSE); 969 970 /* Build the IRP */ 971 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 972 DeviceObject, 973 NULL, 974 0UL, 975 Geometry, 976 sizeof(DISK_GEOMETRY), 977 FALSE, 978 Event, 979 &IoStatusBlock); 980 if (!Irp) 981 { 982 /* Fail, free the event */ 983 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 984 return STATUS_INSUFFICIENT_RESOURCES; 985 } 986 987 /* Call the driver and check if it's pending */ 988 Status = IoCallDriver(DeviceObject, Irp); 989 if (Status == STATUS_PENDING) 990 { 991 /* Wait on the driver */ 992 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 993 Status = IoStatusBlock.Status; 994 } 995 996 /* Check if the driver returned success */ 997 if(NT_SUCCESS(Status)) 998 { 999 /* Build another IRP */ 1000 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO, 1001 DeviceObject, 1002 NULL, 1003 0UL, 1004 &PartitionInfo, 1005 sizeof(PARTITION_INFORMATION), 1006 FALSE, 1007 Event, 1008 &IoStatusBlock); 1009 if (!Irp) 1010 { 1011 /* Fail, free the event */ 1012 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1013 return STATUS_INSUFFICIENT_RESOURCES; 1014 } 1015 1016 /* Reset event */ 1017 KeClearEvent(Event); 1018 1019 /* Call the driver and check if it's pending */ 1020 Status = IoCallDriver(DeviceObject, Irp); 1021 if (Status == STATUS_PENDING) 1022 { 1023 /* Wait on the driver */ 1024 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 1025 Status = IoStatusBlock.Status; 1026 } 1027 1028 /* Check if the driver returned success */ 1029 if(NT_SUCCESS(Status)) 1030 { 1031 /* Get the number of sectors */ 1032 *RealSectorCount = (PartitionInfo.PartitionLength.QuadPart / 1033 Geometry->BytesPerSector); 1034 } 1035 } 1036 1037 /* Free the event and return the Status */ 1038 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1039 return Status; 1040 } 1041 1042 BOOLEAN 1043 NTAPI 1044 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry, 1045 IN ULONGLONG MaxOffset, 1046 IN ULONGLONG MaxSector) 1047 { 1048 ULONGLONG EndingSector; 1049 PAGED_CODE(); 1050 1051 /* Unused partitions are considered valid */ 1052 if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE; 1053 1054 /* Get the last sector of the partition */ 1055 EndingSector = GET_STARTING_SECTOR(Entry) + GET_PARTITION_LENGTH(Entry); 1056 1057 /* Check if it's more then the maximum sector */ 1058 if (EndingSector > MaxSector) 1059 { 1060 /* Invalid partition */ 1061 DPRINT1("FSTUB: entry is invalid\n"); 1062 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry)); 1063 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry)); 1064 DPRINT1("FSTUB: end %#I64x\n", EndingSector); 1065 DPRINT1("FSTUB: max %#I64x\n", MaxSector); 1066 return FALSE; 1067 } 1068 else if(GET_STARTING_SECTOR(Entry) > MaxOffset) 1069 { 1070 /* Invalid partition */ 1071 DPRINT1("FSTUB: entry is invalid\n"); 1072 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry)); 1073 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry)); 1074 DPRINT1("FSTUB: end %#I64x\n", EndingSector); 1075 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset); 1076 return FALSE; 1077 } 1078 1079 /* It's fine, return success */ 1080 return TRUE; 1081 } 1082 1083 VOID 1084 NTAPI 1085 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset, 1086 IN PLARGE_INTEGER PartitionLength, 1087 IN CCHAR ShiftCount, 1088 IN ULONG SectorsPerTrack, 1089 IN ULONG NumberOfTracks, 1090 IN ULONG ConventionalCylinders, 1091 OUT PPARTITION_DESCRIPTOR PartitionDescriptor) 1092 { 1093 LARGE_INTEGER FirstSector, SectorCount; 1094 ULONG LastSector, Remainder, SectorsPerCylinder; 1095 ULONG StartingCylinder, EndingCylinder; 1096 ULONG StartingTrack, EndingTrack; 1097 ULONG StartingSector, EndingSector; 1098 PAGED_CODE(); 1099 1100 /* Calculate the number of sectors for each cylinder */ 1101 SectorsPerCylinder = SectorsPerTrack * NumberOfTracks; 1102 1103 /* Calculate the first sector, and the sector count */ 1104 FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount; 1105 SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount; 1106 1107 /* Now calculate the last sector */ 1108 LastSector = FirstSector.LowPart + SectorCount.LowPart - 1; 1109 1110 /* Calculate the first and last cylinders */ 1111 StartingCylinder = FirstSector.LowPart / SectorsPerCylinder; 1112 EndingCylinder = LastSector / SectorsPerCylinder; 1113 1114 /* Set the default number of cylinders */ 1115 if (!ConventionalCylinders) ConventionalCylinders = 1024; 1116 1117 /* Normalize the values */ 1118 if (StartingCylinder >= ConventionalCylinders) 1119 { 1120 /* Set the maximum to 1023 */ 1121 StartingCylinder = ConventionalCylinders - 1; 1122 } 1123 if (EndingCylinder >= ConventionalCylinders) 1124 { 1125 /* Set the maximum to 1023 */ 1126 EndingCylinder = ConventionalCylinders - 1; 1127 } 1128 1129 /* Calculate the starting head and sector that still remain */ 1130 Remainder = FirstSector.LowPart % SectorsPerCylinder; 1131 StartingTrack = Remainder / SectorsPerTrack; 1132 StartingSector = Remainder % SectorsPerTrack; 1133 1134 /* Calculate the ending head and sector that still remain */ 1135 Remainder = LastSector % SectorsPerCylinder; 1136 EndingTrack = Remainder / SectorsPerTrack; 1137 EndingSector = Remainder % SectorsPerTrack; 1138 1139 /* Set cylinder data for the MSB */ 1140 PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder; 1141 PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder; 1142 1143 /* Set the track data */ 1144 PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack; 1145 PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack; 1146 1147 /* Update cylinder data for the LSB */ 1148 StartingCylinder = ((StartingSector + 1) & 0x3F) | 1149 ((StartingCylinder >> 2) & 0xC0); 1150 EndingCylinder = ((EndingSector + 1) & 0x3F) | 1151 ((EndingCylinder >> 2) & 0xC0); 1152 1153 /* Set the cylinder data for the LSB */ 1154 PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder; 1155 PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder; 1156 } 1157 1158 VOID 1159 FASTCALL 1160 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject, 1161 IN PULONG ConventionalCylinders, 1162 IN PLONGLONG DiskSize) 1163 { 1164 PDISK_GEOMETRY DiskGeometry = NULL; 1165 PIO_STATUS_BLOCK IoStatusBlock = NULL; 1166 PKEVENT Event = NULL; 1167 PIRP Irp; 1168 NTSTATUS Status; 1169 1170 /* Set defaults */ 1171 *ConventionalCylinders = 0; 1172 *DiskSize = 0; 1173 1174 /* Allocate the structure in nonpaged pool */ 1175 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool, 1176 sizeof(DISK_GEOMETRY), 1177 TAG_FILE_SYSTEM); 1178 if (!DiskGeometry) goto Cleanup; 1179 1180 /* Allocate the status block in nonpaged pool */ 1181 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool, 1182 sizeof(IO_STATUS_BLOCK), 1183 TAG_FILE_SYSTEM); 1184 if (!IoStatusBlock) goto Cleanup; 1185 1186 /* Allocate the event in nonpaged pool too */ 1187 Event = ExAllocatePoolWithTag(NonPagedPool, 1188 sizeof(KEVENT), 1189 TAG_FILE_SYSTEM); 1190 if (!Event) goto Cleanup; 1191 1192 /* Initialize the event */ 1193 KeInitializeEvent(Event, NotificationEvent, FALSE); 1194 1195 /* Build the IRP */ 1196 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 1197 DeviceObject, 1198 NULL, 1199 0, 1200 DiskGeometry, 1201 sizeof(DISK_GEOMETRY), 1202 FALSE, 1203 Event, 1204 IoStatusBlock); 1205 if (!Irp) goto Cleanup; 1206 1207 /* Now call the driver */ 1208 Status = IoCallDriver(DeviceObject, Irp); 1209 if (Status == STATUS_PENDING) 1210 { 1211 /* Wait for it to complete */ 1212 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 1213 Status = IoStatusBlock->Status; 1214 } 1215 1216 /* Check driver status */ 1217 if (NT_SUCCESS(Status)) 1218 { 1219 /* Return the cylinder count */ 1220 *ConventionalCylinders = DiskGeometry->Cylinders.LowPart; 1221 1222 /* Make sure it's not larger then 1024 */ 1223 if (DiskGeometry->Cylinders.LowPart >= 1024) 1224 { 1225 /* Otherwise, normalize the value */ 1226 *ConventionalCylinders = 1024; 1227 } 1228 1229 /* Calculate the disk size */ 1230 *DiskSize = DiskGeometry->Cylinders.QuadPart * 1231 DiskGeometry->TracksPerCylinder * 1232 DiskGeometry->SectorsPerTrack * 1233 DiskGeometry->BytesPerSector; 1234 } 1235 1236 Cleanup: 1237 /* Free all the pointers */ 1238 if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM); 1239 if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM); 1240 if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM); 1241 return; 1242 } 1243 1244 VOID 1245 FASTCALL 1246 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject, 1247 IN ULONG SectorSize, 1248 IN ULONG MbrTypeIdentifier, 1249 OUT PVOID *MbrBuffer) 1250 { 1251 LARGE_INTEGER Offset; 1252 PUCHAR Buffer; 1253 ULONG BufferSize; 1254 KEVENT Event; 1255 IO_STATUS_BLOCK IoStatusBlock; 1256 PIRP Irp; 1257 PPARTITION_DESCRIPTOR PartitionDescriptor; 1258 NTSTATUS Status; 1259 PIO_STACK_LOCATION IoStackLocation; 1260 Offset.QuadPart = 0; 1261 1262 /* Assume failure */ 1263 *MbrBuffer = NULL; 1264 1265 /* Normalize the buffer size */ 1266 BufferSize = max(SectorSize, 512); 1267 1268 /* Allocate the buffer */ 1269 Buffer = ExAllocatePoolWithTag(NonPagedPool, 1270 PAGE_SIZE > BufferSize ? 1271 PAGE_SIZE : BufferSize, 1272 TAG_FILE_SYSTEM); 1273 if (!Buffer) return; 1274 1275 /* Initialize the Event */ 1276 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1277 1278 /* Build the IRP */ 1279 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1280 DeviceObject, 1281 Buffer, 1282 BufferSize, 1283 &Offset, 1284 &Event, 1285 &IoStatusBlock); 1286 if (!Irp) 1287 { 1288 /* Failed */ 1289 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1290 return; 1291 } 1292 1293 /* Make sure to override volume verification */ 1294 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1295 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1296 1297 /* Call the driver */ 1298 Status = IoCallDriver(DeviceObject, Irp); 1299 if (Status == STATUS_PENDING) 1300 { 1301 /* Wait for completion */ 1302 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1303 Status = IoStatusBlock.Status; 1304 } 1305 1306 /* Check driver Status */ 1307 if (NT_SUCCESS(Status)) 1308 { 1309 /* Validate the MBR Signature */ 1310 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1311 { 1312 /* Failed */ 1313 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1314 return; 1315 } 1316 1317 /* Get the partition entry */ 1318 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1319 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1320 1321 /* Make sure it's what the caller wanted */ 1322 if (PartitionDescriptor->PartitionType != MbrTypeIdentifier) 1323 { 1324 /* It's not, free our buffer */ 1325 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1326 } 1327 else 1328 { 1329 /* Check if this is a secondary entry */ 1330 if (PartitionDescriptor->PartitionType == 0x54) 1331 { 1332 /* Return our buffer, but at sector 63 */ 1333 *(PULONG)Buffer = 63; 1334 *MbrBuffer = Buffer; 1335 } 1336 else if (PartitionDescriptor->PartitionType == 0x55) 1337 { 1338 /* EZ Drive, return the buffer directly */ 1339 *MbrBuffer = Buffer; 1340 } 1341 else 1342 { 1343 /* Otherwise crash on debug builds */ 1344 ASSERT(PartitionDescriptor->PartitionType == 0x55); 1345 } 1346 } 1347 } 1348 } 1349 1350 VOID 1351 NTAPI 1352 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor, 1353 IN ULONGLONG MaxOffset) 1354 { 1355 ULONG PartitionMaxOffset, PartitionLength; 1356 PAGED_CODE(); 1357 1358 /* Compute partition length (according to MBR entry) */ 1359 PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor); 1360 /* In case the partition length goes beyond disk size... */ 1361 if (PartitionMaxOffset > MaxOffset) 1362 { 1363 /* Resize partition to its maximum real length */ 1364 PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor)); 1365 SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength); 1366 } 1367 } 1368 1369 NTSTATUS 1370 FASTCALL 1371 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, 1372 IN ULONG SectorSize, 1373 IN BOOLEAN ReturnRecognizedPartitions, 1374 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer) 1375 { 1376 KEVENT Event; 1377 IO_STATUS_BLOCK IoStatusBlock; 1378 PIRP Irp; 1379 PPARTITION_DESCRIPTOR PartitionDescriptor; 1380 CCHAR Entry; 1381 NTSTATUS Status; 1382 PPARTITION_INFORMATION PartitionInfo; 1383 PUCHAR Buffer = NULL; 1384 ULONG BufferSize = 2048, InputSize; 1385 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL; 1386 LONG j = -1, i = -1, k; 1387 DISK_GEOMETRY DiskGeometry; 1388 LONGLONG EndSector, MaxSector, StartOffset; 1389 ULONGLONG MaxOffset; 1390 LARGE_INTEGER Offset, VolumeOffset; 1391 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE; 1392 BOOLEAN IsValid, IsEmpty = TRUE; 1393 PVOID MbrBuffer; 1394 PIO_STACK_LOCATION IoStackLocation; 1395 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer; 1396 UCHAR PartitionType; 1397 LARGE_INTEGER HiddenSectors64; 1398 VolumeOffset.QuadPart = Offset.QuadPart = 0; 1399 PAGED_CODE(); 1400 1401 /* Allocate the buffer */ 1402 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 1403 BufferSize, 1404 TAG_FILE_SYSTEM); 1405 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES; 1406 1407 /* Normalize the buffer size */ 1408 InputSize = max(512, SectorSize); 1409 1410 /* Check for EZ Drive */ 1411 HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer); 1412 if (MbrBuffer) 1413 { 1414 /* EZ Drive found, bias the offset */ 1415 IsEzDrive = TRUE; 1416 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 1417 Offset.QuadPart = 512; 1418 } 1419 1420 /* Get drive geometry */ 1421 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset); 1422 if (!NT_SUCCESS(Status)) 1423 { 1424 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1425 *PartitionBuffer = NULL; 1426 return Status; 1427 } 1428 1429 /* Get the end and maximum sector */ 1430 EndSector = MaxOffset; 1431 MaxSector = MaxOffset << 1; 1432 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n", 1433 MaxOffset, MaxSector); 1434 1435 /* Allocate our buffer */ 1436 Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM); 1437 if (!Buffer) 1438 { 1439 /* Fail, free the input buffer */ 1440 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1441 *PartitionBuffer = NULL; 1442 return STATUS_INSUFFICIENT_RESOURCES; 1443 } 1444 1445 /* Start partition loop */ 1446 do 1447 { 1448 /* Assume the partition is valid */ 1449 IsValid = TRUE; 1450 1451 /* Initialize the event */ 1452 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1453 1454 /* Clear the buffer and build the IRP */ 1455 RtlZeroMemory(Buffer, InputSize); 1456 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1457 DeviceObject, 1458 Buffer, 1459 InputSize, 1460 &Offset, 1461 &Event, 1462 &IoStatusBlock); 1463 if (!Irp) 1464 { 1465 /* Failed */ 1466 Status = STATUS_INSUFFICIENT_RESOURCES; 1467 break; 1468 } 1469 1470 /* Make sure to disable volume verification */ 1471 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1472 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1473 1474 /* Call the driver */ 1475 Status = IoCallDriver(DeviceObject, Irp); 1476 if (Status == STATUS_PENDING) 1477 { 1478 /* Wait for completion */ 1479 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1480 Status = IoStatusBlock.Status; 1481 } 1482 1483 /* Normalize status code and check for failure */ 1484 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS; 1485 if (!NT_SUCCESS(Status)) break; 1486 1487 /* If we biased for EZ-Drive, unbias now */ 1488 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 1489 1490 /* Make sure this is a valid MBR */ 1491 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1492 { 1493 /* It's not, fail */ 1494 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in " 1495 "partition table %d\n", j + 1); 1496 break; 1497 } 1498 1499 /* At this point we have a valid MBR */ 1500 MbrFound = TRUE; 1501 1502 /* Check if we weren't given an offset */ 1503 if (!Offset.QuadPart) 1504 { 1505 /* Then read the signature off the disk */ 1506 (*PartitionBuffer)->Signature = ((PULONG)Buffer) 1507 [PARTITION_TABLE_OFFSET / 2 - 1]; 1508 } 1509 1510 /* Get the partition descriptor array */ 1511 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1512 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1513 1514 /* Start looping partitions */ 1515 j++; 1516 DPRINT("FSTUB: Partition Table %d:\n", j); 1517 for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++) 1518 { 1519 /* Get the partition type */ 1520 PartitionType = PartitionDescriptor->PartitionType; 1521 1522 /* Print debug messages */ 1523 DPRINT("Partition Entry %d,%d: type %#x %s\n", 1524 j, 1525 Entry, 1526 PartitionType, 1527 (PartitionDescriptor->ActiveFlag) ? "Active" : ""); 1528 DPRINT("\tOffset %#08lx for %#08lx Sectors\n", 1529 GET_STARTING_SECTOR(PartitionDescriptor), 1530 GET_PARTITION_LENGTH(PartitionDescriptor)); 1531 1532 /* Check whether we're facing a protective MBR */ 1533 if (PartitionType == EFI_PMBR_OSTYPE_EFI) 1534 { 1535 /* Partition length might be bigger than disk size */ 1536 FstubFixupEfiPartition(PartitionDescriptor, 1537 MaxOffset); 1538 } 1539 1540 /* Make sure that the partition is valid, unless it's the first */ 1541 if (!(HalpIsValidPartitionEntry(PartitionDescriptor, 1542 MaxOffset, 1543 MaxSector)) && !(j)) 1544 { 1545 /* It's invalid, so fail */ 1546 IsValid = FALSE; 1547 break; 1548 } 1549 1550 /* Check if it's a container */ 1551 if (IsContainerPartition(PartitionType)) 1552 { 1553 /* Increase the count of containers */ 1554 if (++k != 1) 1555 { 1556 /* More then one table is invalid */ 1557 DPRINT1("FSTUB: Multiple container partitions found in " 1558 "partition table %d\n - table is invalid\n", 1559 j); 1560 IsValid = FALSE; 1561 break; 1562 } 1563 } 1564 1565 /* Check if the partition is supposedly empty */ 1566 if (IsEmpty) 1567 { 1568 /* But check if it actually has a start and/or length */ 1569 if ((GET_STARTING_SECTOR(PartitionDescriptor)) || 1570 (GET_PARTITION_LENGTH(PartitionDescriptor))) 1571 { 1572 /* So then it's not really empty */ 1573 IsEmpty = FALSE; 1574 } 1575 } 1576 1577 /* Check if the caller wanted only recognized partitions */ 1578 if (ReturnRecognizedPartitions) 1579 { 1580 /* Then check if this one is unused, or a container */ 1581 if ((PartitionType == PARTITION_ENTRY_UNUSED) || 1582 IsContainerPartition(PartitionType)) 1583 { 1584 /* Skip it, since the caller doesn't want it */ 1585 continue; 1586 } 1587 } 1588 1589 /* Increase the structure count and check if they can fit */ 1590 if ((sizeof(DRIVE_LAYOUT_INFORMATION) + 1591 (++i * sizeof(PARTITION_INFORMATION))) > 1592 BufferSize) 1593 { 1594 /* Allocate a new buffer that's twice as big */ 1595 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool, 1596 BufferSize << 1, 1597 TAG_FILE_SYSTEM); 1598 if (!DriveLayoutInfo) 1599 { 1600 /* Out of memory, unto this extra structure */ 1601 --i; 1602 Status = STATUS_INSUFFICIENT_RESOURCES; 1603 break; 1604 } 1605 1606 /* Copy the contents of the old buffer */ 1607 RtlMoveMemory(DriveLayoutInfo, 1608 *PartitionBuffer, 1609 BufferSize); 1610 1611 /* Free the old buffer and set this one as the new one */ 1612 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1613 *PartitionBuffer = DriveLayoutInfo; 1614 1615 /* Double the size */ 1616 BufferSize <<= 1; 1617 } 1618 1619 /* Now get the current structure being filled and initialize it */ 1620 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i]; 1621 PartitionInfo->PartitionType = PartitionType; 1622 PartitionInfo->RewritePartition = FALSE; 1623 1624 /* Check if we're dealing with a partition that's in use */ 1625 if (PartitionType != PARTITION_ENTRY_UNUSED) 1626 { 1627 /* Check if it's bootable */ 1628 PartitionInfo->BootIndicator = PartitionDescriptor-> 1629 ActiveFlag & 0x80 ? 1630 TRUE : FALSE; 1631 1632 /* Check if its' a container */ 1633 if (IsContainerPartition(PartitionType)) 1634 { 1635 /* Then don't recognize it and use the volume offset */ 1636 PartitionInfo->RecognizedPartition = FALSE; 1637 StartOffset = VolumeOffset.QuadPart; 1638 } 1639 else 1640 { 1641 /* Then recognize it and use the partition offset */ 1642 PartitionInfo->RecognizedPartition = TRUE; 1643 StartOffset = Offset.QuadPart; 1644 } 1645 1646 /* Get the starting offset */ 1647 PartitionInfo->StartingOffset.QuadPart = 1648 StartOffset + 1649 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor), 1650 SectorSize); 1651 1652 /* Calculate the number of hidden sectors */ 1653 HiddenSectors64.QuadPart = (PartitionInfo-> 1654 StartingOffset.QuadPart - 1655 StartOffset) / 1656 SectorSize; 1657 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart; 1658 1659 /* Get the partition length */ 1660 PartitionInfo->PartitionLength.QuadPart = 1661 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor), 1662 SectorSize); 1663 1664 /* Get the partition number */ 1665 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0; 1666 } 1667 else 1668 { 1669 /* Otherwise, clear all the relevant fields */ 1670 PartitionInfo->BootIndicator = FALSE; 1671 PartitionInfo->RecognizedPartition = FALSE; 1672 PartitionInfo->StartingOffset.QuadPart = 0; 1673 PartitionInfo->PartitionLength.QuadPart = 0; 1674 PartitionInfo->HiddenSectors = 0; 1675 1676 PartitionInfo->PartitionNumber = 0; 1677 } 1678 } 1679 1680 /* Finish debug log, and check for failure */ 1681 DPRINT("\n"); 1682 if (!NT_SUCCESS(Status)) break; 1683 1684 /* Also check if we hit an invalid entry here */ 1685 if (!IsValid) 1686 { 1687 /* We did, so break out of the loop minus one entry */ 1688 j--; 1689 break; 1690 } 1691 1692 /* Reset the offset */ 1693 Offset.QuadPart = 0; 1694 1695 /* Go back to the descriptor array and loop it */ 1696 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1697 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1698 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1699 { 1700 /* Check if this is a container partition, since we skipped them */ 1701 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 1702 { 1703 /* Get its offset */ 1704 Offset.QuadPart = VolumeOffset.QuadPart + 1705 UInt32x32To64( 1706 GET_STARTING_SECTOR(PartitionDescriptor), 1707 SectorSize); 1708 1709 /* If this is a primary partition, this is the volume offset */ 1710 if (IsPrimary) VolumeOffset = Offset; 1711 1712 /* Also update the maximum sector */ 1713 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor); 1714 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector); 1715 break; 1716 } 1717 } 1718 1719 /* Loop the next partitions, which are not primary anymore */ 1720 IsPrimary = FALSE; 1721 } while (Offset.HighPart | Offset.LowPart); 1722 1723 /* Check if this is a removable device that's probably a super-floppy */ 1724 if ((DiskGeometry.MediaType == RemovableMedia) && 1725 !(j) && 1726 (MbrFound) && 1727 (IsEmpty)) 1728 { 1729 /* Read the jump bytes to detect super-floppy */ 1730 if ((BootSectorInfo->JumpByte[0] == 0xeb) || 1731 (BootSectorInfo->JumpByte[0] == 0xe9)) 1732 { 1733 /* Super floppes don't have typical MBRs, so skip them */ 1734 DPRINT1("FSTUB: Jump byte %#x found along with empty partition " 1735 "table - disk is a super floppy and has no valid MBR\n", 1736 BootSectorInfo->JumpByte); 1737 j = -1; 1738 } 1739 } 1740 1741 /* Check if we're still at partition -1 */ 1742 if (j == -1) 1743 { 1744 /* The likely cause is the super floppy detection above */ 1745 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia)) 1746 { 1747 /* Print out debugging information */ 1748 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a " 1749 "super-floppy\n", 1750 DeviceObject); 1751 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x " 1752 "bytes large\n", 1753 EndSector, EndSector * DiskGeometry.BytesPerSector); 1754 1755 /* We should at least have some sectors */ 1756 if (EndSector > 0) 1757 { 1758 /* Get the entry we'll use */ 1759 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0]; 1760 1761 /* Fill it out with data for a super-floppy */ 1762 PartitionInfo->RewritePartition = FALSE; 1763 PartitionInfo->RecognizedPartition = TRUE; 1764 PartitionInfo->PartitionType = PARTITION_FAT_16; 1765 PartitionInfo->BootIndicator = FALSE; 1766 PartitionInfo->HiddenSectors = 0; 1767 PartitionInfo->StartingOffset.QuadPart = 0; 1768 PartitionInfo->PartitionLength.QuadPart = (EndSector * 1769 DiskGeometry. 1770 BytesPerSector); 1771 1772 /* FIXME: REACTOS HACK */ 1773 PartitionInfo->PartitionNumber = 0; 1774 1775 /* Set the signature and set the count back to 0 */ 1776 (*PartitionBuffer)->Signature = 1; 1777 i = 0; 1778 } 1779 } 1780 else 1781 { 1782 /* Otherwise, this isn't a super floppy, so set an invalid count */ 1783 i = -1; 1784 } 1785 } 1786 1787 /* Set the partition count */ 1788 (*PartitionBuffer)->PartitionCount = ++i; 1789 1790 /* If we have no count, delete the signature */ 1791 if (!i) (*PartitionBuffer)->Signature = 0; 1792 1793 /* Free the buffer and check for success */ 1794 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1795 if (!NT_SUCCESS(Status)) 1796 { 1797 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1798 *PartitionBuffer = NULL; 1799 } 1800 1801 /* Return status */ 1802 return Status; 1803 } 1804 1805 NTSTATUS 1806 FASTCALL 1807 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 1808 IN ULONG SectorSize, 1809 IN ULONG PartitionNumber, 1810 IN ULONG PartitionType) 1811 { 1812 PIRP Irp; 1813 KEVENT Event; 1814 IO_STATUS_BLOCK IoStatusBlock; 1815 NTSTATUS Status; 1816 LARGE_INTEGER Offset, VolumeOffset; 1817 PUCHAR Buffer = NULL; 1818 ULONG BufferSize; 1819 ULONG i = 0; 1820 ULONG Entry; 1821 PPARTITION_DESCRIPTOR PartitionDescriptor; 1822 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE; 1823 PVOID MbrBuffer; 1824 PIO_STACK_LOCATION IoStackLocation; 1825 VolumeOffset.QuadPart = Offset.QuadPart = 0; 1826 PAGED_CODE(); 1827 1828 /* Normalize the buffer size */ 1829 BufferSize = max(512, SectorSize); 1830 1831 /* Check for EZ Drive */ 1832 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 1833 if (MbrBuffer) 1834 { 1835 /* EZ Drive found, bias the offset */ 1836 IsEzDrive = TRUE; 1837 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 1838 Offset.QuadPart = 512; 1839 } 1840 1841 /* Allocate our partition buffer */ 1842 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 1843 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 1844 1845 /* Initialize the event we'll use and loop partitions */ 1846 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1847 do 1848 { 1849 /* Reset the event since we reuse it */ 1850 KeClearEvent(&Event); 1851 1852 /* Build the read IRP */ 1853 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1854 DeviceObject, 1855 Buffer, 1856 BufferSize, 1857 &Offset, 1858 &Event, 1859 &IoStatusBlock); 1860 if (!Irp) 1861 { 1862 /* Fail */ 1863 Status = STATUS_INSUFFICIENT_RESOURCES; 1864 break; 1865 } 1866 1867 /* Make sure to disable volume verification */ 1868 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1869 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1870 1871 /* Call the driver */ 1872 Status = IoCallDriver(DeviceObject, Irp); 1873 if (Status == STATUS_PENDING) 1874 { 1875 /* Wait for completion */ 1876 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1877 Status = IoStatusBlock.Status; 1878 } 1879 1880 /* Check for failure */ 1881 if (!NT_SUCCESS(Status)) break; 1882 1883 /* If we biased for EZ-Drive, unbias now */ 1884 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 1885 1886 /* Make sure this is a valid MBR */ 1887 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1888 { 1889 /* It's not, fail */ 1890 Status = STATUS_BAD_MASTER_BOOT_RECORD; 1891 break; 1892 } 1893 1894 /* Get the partition descriptors and loop them */ 1895 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1896 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1897 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1898 { 1899 /* Check if it's unused or a container partition */ 1900 if ((PartitionDescriptor->PartitionType == 1901 PARTITION_ENTRY_UNUSED) || 1902 (IsContainerPartition(PartitionDescriptor->PartitionType))) 1903 { 1904 /* Go to the next one */ 1905 continue; 1906 } 1907 1908 /* It's a valid partition, so increase the partition count */ 1909 if (++i == PartitionNumber) 1910 { 1911 /* We found a match, set the type */ 1912 PartitionDescriptor->PartitionType = (UCHAR)PartitionType; 1913 1914 /* Reset the reusable event */ 1915 KeClearEvent(&Event); 1916 1917 /* Build the write IRP */ 1918 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 1919 DeviceObject, 1920 Buffer, 1921 BufferSize, 1922 &Offset, 1923 &Event, 1924 &IoStatusBlock); 1925 if (!Irp) 1926 { 1927 /* Fail */ 1928 Status = STATUS_INSUFFICIENT_RESOURCES; 1929 break; 1930 } 1931 1932 /* Disable volume verification */ 1933 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1934 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1935 1936 /* Call the driver */ 1937 Status = IoCallDriver(DeviceObject, Irp); 1938 if (Status == STATUS_PENDING) 1939 { 1940 /* Wait for completion */ 1941 KeWaitForSingleObject(&Event, 1942 Executive, 1943 KernelMode, 1944 FALSE, 1945 NULL); 1946 Status = IoStatusBlock.Status; 1947 } 1948 1949 /* We're done, break out of the loop */ 1950 break; 1951 } 1952 } 1953 1954 /* If we looped all the partitions, break out */ 1955 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break; 1956 1957 /* Nothing found yet, get the partition array again */ 1958 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1959 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1960 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1961 { 1962 /* Check if this was a container partition (we skipped these) */ 1963 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 1964 { 1965 /* Update the partition offset */ 1966 Offset.QuadPart = VolumeOffset.QuadPart + 1967 GET_STARTING_SECTOR(PartitionDescriptor) * 1968 SectorSize; 1969 1970 /* If this was the primary partition, update the volume too */ 1971 if (IsPrimary) VolumeOffset = Offset; 1972 break; 1973 } 1974 } 1975 1976 /* Check if we already searched all the partitions */ 1977 if (Entry > NUM_PARTITION_TABLE_ENTRIES) 1978 { 1979 /* Then we failed to find a good MBR */ 1980 Status = STATUS_BAD_MASTER_BOOT_RECORD; 1981 break; 1982 } 1983 1984 /* Loop the next partitions, which are not primary anymore */ 1985 IsPrimary = FALSE; 1986 } while (i < PartitionNumber); 1987 1988 /* Everything done, cleanup */ 1989 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1990 return Status; 1991 } 1992 1993 NTSTATUS 1994 FASTCALL 1995 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 1996 IN ULONG SectorSize, 1997 IN ULONG SectorsPerTrack, 1998 IN ULONG NumberOfHeads, 1999 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 2000 { 2001 KEVENT Event; 2002 IO_STATUS_BLOCK IoStatusBlock; 2003 PIRP Irp; 2004 NTSTATUS Status = STATUS_SUCCESS; 2005 ULONG BufferSize; 2006 PUSHORT Buffer; 2007 PPTE Entry; 2008 PPARTITION_TABLE PartitionTable; 2009 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset; 2010 LARGE_INTEGER StartOffset, PartitionLength; 2011 ULONG i, j; 2012 CCHAR k; 2013 BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr; 2014 ULONG ConventionalCylinders; 2015 LONGLONG DiskSize; 2016 PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer; 2017 PVOID MbrBuffer; 2018 UCHAR PartitionType; 2019 PIO_STACK_LOCATION IoStackLocation; 2020 PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry; 2021 PPARTITION_INFORMATION TableEntry; 2022 ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0; 2023 PAGED_CODE(); 2024 2025 /* Normalize the buffer size */ 2026 BufferSize = max(512, SectorSize); 2027 2028 /* Get the partial drive geometry */ 2029 xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize); 2030 2031 /* Check for EZ Drive */ 2032 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 2033 if (MbrBuffer) 2034 { 2035 /* EZ Drive found, bias the offset */ 2036 IsEzDrive = TRUE; 2037 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 2038 Offset.QuadPart = 512; 2039 } 2040 2041 /* Get the number of bits to shift to multiply by the sector size */ 2042 for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break; 2043 2044 /* Check if there's only one partition */ 2045 if (PartitionBuffer->PartitionCount == 1) 2046 { 2047 /* Check if it has no starting offset or hidden sectors */ 2048 if (!(PartitionInfo->StartingOffset.QuadPart) && 2049 !(PartitionInfo->HiddenSectors)) 2050 { 2051 /* Then it's a super floppy */ 2052 IsSuperFloppy = TRUE; 2053 2054 /* Which also means it must be non-bootable FAT-16 */ 2055 if ((PartitionInfo->PartitionNumber) || 2056 (PartitionInfo->PartitionType != PARTITION_FAT_16) || 2057 (PartitionInfo->BootIndicator)) 2058 { 2059 /* It's not, so we fail */ 2060 return STATUS_INVALID_PARAMETER; 2061 } 2062 2063 /* Check if it needs a rewrite, and disable EZ drive for sure */ 2064 if (PartitionInfo->RewritePartition) DoRewrite = TRUE; 2065 IsEzDrive = FALSE; 2066 } 2067 } 2068 2069 /* Count the number of partition tables */ 2070 DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4; 2071 2072 /* Allocate our partition buffer */ 2073 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 2074 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 2075 2076 /* Loop the entries */ 2077 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET]; 2078 for (i = 0; i < DiskLayout->TableCount; i++) 2079 { 2080 /* Set if this is the MBR partition */ 2081 IsMbr= (BOOLEAN)!i; 2082 2083 /* Initialize th event */ 2084 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2085 2086 /* Build the read IRP */ 2087 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 2088 DeviceObject, 2089 Buffer, 2090 BufferSize, 2091 &Offset, 2092 &Event, 2093 &IoStatusBlock); 2094 if (!Irp) 2095 { 2096 /* Fail */ 2097 Status = STATUS_INSUFFICIENT_RESOURCES; 2098 break; 2099 } 2100 2101 /* Make sure to disable volume verification */ 2102 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2103 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2104 2105 /* Call the driver */ 2106 Status = IoCallDriver(DeviceObject, Irp); 2107 if (Status == STATUS_PENDING) 2108 { 2109 /* Wait for completion */ 2110 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2111 Status = IoStatusBlock.Status; 2112 } 2113 2114 /* Check for failure */ 2115 if (!NT_SUCCESS(Status)) break; 2116 2117 /* If we biased for EZ-Drive, unbias now */ 2118 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2119 2120 /* Check if this is a normal disk */ 2121 if (!IsSuperFloppy) 2122 { 2123 /* Set the boot record signature */ 2124 Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE; 2125 2126 /* By default, don't require a rewrite */ 2127 DoRewrite = FALSE; 2128 2129 /* Check if we don't have an offset */ 2130 if (!Offset.QuadPart) 2131 { 2132 /* Check if the signature doesn't match */ 2133 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] != 2134 PartitionBuffer->Signature) 2135 { 2136 /* Then write the signature and now w need a rewrite */ 2137 ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] = 2138 PartitionBuffer->Signature; 2139 DoRewrite = TRUE; 2140 } 2141 } 2142 2143 /* Loop the partition table entries */ 2144 PartitionTable = &DiskLayout->PartitionTable[i]; 2145 for (j = 0; j < 4; j++) 2146 { 2147 /* Get the current entry and type */ 2148 TableEntry = &PartitionTable->PartitionEntry[j]; 2149 PartitionType = TableEntry->PartitionType; 2150 2151 /* Check if the entry needs a rewrite */ 2152 if (TableEntry->RewritePartition) 2153 { 2154 /* Then we need one too */ 2155 DoRewrite = TRUE; 2156 2157 /* Save the type and if it's a bootable partition */ 2158 Entry[j].PartitionType = TableEntry->PartitionType; 2159 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0; 2160 2161 /* Make sure it's used */ 2162 if (PartitionType != PARTITION_ENTRY_UNUSED) 2163 { 2164 /* Make sure it's not a container (unless primary) */ 2165 if ((IsMbr) || !(IsContainerPartition(PartitionType))) 2166 { 2167 /* Use the partition offset */ 2168 StartOffset.QuadPart = Offset.QuadPart; 2169 } 2170 else 2171 { 2172 /* Use the extended logical partition offset */ 2173 StartOffset.QuadPart = ExtendedOffset.QuadPart; 2174 } 2175 2176 /* Set the sector offset */ 2177 SectorOffset.QuadPart = TableEntry-> 2178 StartingOffset.QuadPart - 2179 StartOffset.QuadPart; 2180 2181 /* Now calculate the starting sector */ 2182 StartOffset.QuadPart = SectorOffset.QuadPart >> k; 2183 Entry[j].StartingSector = StartOffset.LowPart; 2184 2185 /* As well as the length */ 2186 PartitionLength.QuadPart = TableEntry->PartitionLength. 2187 QuadPart >> k; 2188 Entry[j].PartitionLength = PartitionLength.LowPart; 2189 2190 /* Calculate the CHS values */ 2191 HalpCalculateChsValues(&TableEntry->StartingOffset, 2192 &TableEntry->PartitionLength, 2193 k, 2194 SectorsPerTrack, 2195 NumberOfHeads, 2196 ConventionalCylinders, 2197 (PPARTITION_DESCRIPTOR) 2198 &Entry[j]); 2199 } 2200 else 2201 { 2202 /* Otherwise set up an empty entry */ 2203 Entry[j].StartingSector = 0; 2204 Entry[j].PartitionLength = 0; 2205 Entry[j].StartingTrack = 0; 2206 Entry[j].EndingTrack = 0; 2207 Entry[j].StartingCylinder = 0; 2208 Entry[j].EndingCylinder = 0; 2209 } 2210 } 2211 2212 /* Check if this is a container partition */ 2213 if (IsContainerPartition(PartitionType)) 2214 { 2215 /* Then update the offset to use */ 2216 NextOffset = TableEntry->StartingOffset; 2217 } 2218 } 2219 } 2220 2221 /* Check if we need to write back the buffer */ 2222 if (DoRewrite) 2223 { 2224 /* We don't need to do this again */ 2225 DoRewrite = FALSE; 2226 2227 /* Initialize the event */ 2228 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2229 2230 /* If we unbiased for EZ-Drive, rebias now */ 2231 if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512; 2232 2233 /* Build the write IRP */ 2234 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 2235 DeviceObject, 2236 Buffer, 2237 BufferSize, 2238 &Offset, 2239 &Event, 2240 &IoStatusBlock); 2241 if (!Irp) 2242 { 2243 /* Fail */ 2244 Status = STATUS_INSUFFICIENT_RESOURCES; 2245 break; 2246 } 2247 2248 /* Make sure to disable volume verification */ 2249 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2250 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2251 2252 /* Call the driver */ 2253 Status = IoCallDriver(DeviceObject, Irp); 2254 if (Status == STATUS_PENDING) 2255 { 2256 /* Wait for completion */ 2257 KeWaitForSingleObject(&Event, 2258 Executive, 2259 KernelMode, 2260 FALSE, 2261 NULL); 2262 Status = IoStatusBlock.Status; 2263 } 2264 2265 /* Check for failure */ 2266 if (!NT_SUCCESS(Status)) break; 2267 2268 /* If we biased for EZ-Drive, unbias now */ 2269 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2270 } 2271 2272 /* Update the partition offset and set the extended offset if needed */ 2273 Offset = NextOffset; 2274 if (IsMbr) ExtendedOffset = NextOffset; 2275 } 2276 2277 /* If we had a buffer, free it, then return status */ 2278 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 2279 return Status; 2280 } 2281 2282 /* PUBLIC FUNCTIONS **********************************************************/ 2283 2284 /* 2285 * @implemented 2286 */ 2287 VOID 2288 FASTCALL 2289 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject, 2290 IN ULONG SectorSize, 2291 IN ULONG MbrTypeIdentifier, 2292 OUT PVOID *MbrBuffer) 2293 { 2294 HALDISPATCH->HalExamineMBR(DeviceObject, 2295 SectorSize, 2296 MbrTypeIdentifier, 2297 MbrBuffer); 2298 } 2299 2300 /* 2301 * @implemented 2302 */ 2303 NTSTATUS 2304 FASTCALL 2305 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, 2306 IN ULONG SectorSize, 2307 IN BOOLEAN ReturnRecognizedPartitions, 2308 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer) 2309 { 2310 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject, 2311 SectorSize, 2312 ReturnRecognizedPartitions, 2313 PartitionBuffer); 2314 } 2315 2316 /* 2317 * @implemented 2318 */ 2319 NTSTATUS 2320 FASTCALL 2321 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 2322 IN ULONG SectorSize, 2323 IN ULONG PartitionNumber, 2324 IN ULONG PartitionType) 2325 { 2326 return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject, 2327 SectorSize, 2328 PartitionNumber, 2329 PartitionType); 2330 } 2331 2332 /* 2333 * @implemented 2334 */ 2335 NTSTATUS 2336 FASTCALL 2337 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 2338 IN ULONG SectorSize, 2339 IN ULONG SectorsPerTrack, 2340 IN ULONG NumberOfHeads, 2341 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 2342 { 2343 return HALDISPATCH->HalIoWritePartitionTable(DeviceObject, 2344 SectorSize, 2345 SectorsPerTrack, 2346 NumberOfHeads, 2347 PartitionBuffer); 2348 } 2349 2350 /* 2351 * @implemented 2352 */ 2353 VOID 2354 FASTCALL 2355 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 2356 IN PSTRING NtDeviceName, 2357 OUT PUCHAR NtSystemPath, 2358 OUT PSTRING NtSystemPathString) 2359 { 2360 HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock, 2361 NtDeviceName, 2362 NtSystemPath, 2363 NtSystemPathString); 2364 } 2365 2366 /* EOF */ 2367