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 UCHAR PartitionType; 1396 LARGE_INTEGER HiddenSectors64; 1397 VolumeOffset.QuadPart = Offset.QuadPart = 0; 1398 PAGED_CODE(); 1399 1400 /* Allocate the buffer */ 1401 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 1402 BufferSize, 1403 TAG_FILE_SYSTEM); 1404 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES; 1405 1406 /* Normalize the buffer size */ 1407 InputSize = max(512, SectorSize); 1408 1409 /* Check for EZ Drive */ 1410 HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer); 1411 if (MbrBuffer) 1412 { 1413 /* EZ Drive found, bias the offset */ 1414 IsEzDrive = TRUE; 1415 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 1416 Offset.QuadPart = 512; 1417 } 1418 1419 /* Get drive geometry */ 1420 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset); 1421 if (!NT_SUCCESS(Status)) 1422 { 1423 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1424 *PartitionBuffer = NULL; 1425 return Status; 1426 } 1427 1428 /* Get the end and maximum sector */ 1429 EndSector = MaxOffset; 1430 MaxSector = MaxOffset << 1; 1431 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n", 1432 MaxOffset, MaxSector); 1433 1434 /* Allocate our buffer */ 1435 Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM); 1436 if (!Buffer) 1437 { 1438 /* Fail, free the input buffer */ 1439 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1440 *PartitionBuffer = NULL; 1441 return STATUS_INSUFFICIENT_RESOURCES; 1442 } 1443 1444 /* Start partition loop */ 1445 do 1446 { 1447 /* Assume the partition is valid */ 1448 IsValid = TRUE; 1449 1450 /* Initialize the event */ 1451 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1452 1453 /* Clear the buffer and build the IRP */ 1454 RtlZeroMemory(Buffer, InputSize); 1455 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1456 DeviceObject, 1457 Buffer, 1458 InputSize, 1459 &Offset, 1460 &Event, 1461 &IoStatusBlock); 1462 if (!Irp) 1463 { 1464 /* Failed */ 1465 Status = STATUS_INSUFFICIENT_RESOURCES; 1466 break; 1467 } 1468 1469 /* Make sure to disable volume verification */ 1470 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1471 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1472 1473 /* Call the driver */ 1474 Status = IoCallDriver(DeviceObject, Irp); 1475 if (Status == STATUS_PENDING) 1476 { 1477 /* Wait for completion */ 1478 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1479 Status = IoStatusBlock.Status; 1480 } 1481 1482 /* Normalize status code and check for failure */ 1483 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS; 1484 if (!NT_SUCCESS(Status)) break; 1485 1486 /* If we biased for EZ-Drive, unbias now */ 1487 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 1488 1489 /* Make sure this is a valid MBR */ 1490 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1491 { 1492 /* It's not, fail */ 1493 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in " 1494 "partition table %d\n", j + 1); 1495 break; 1496 } 1497 1498 /* At this point we have a valid MBR */ 1499 MbrFound = TRUE; 1500 1501 /* Check if we weren't given an offset */ 1502 if (!Offset.QuadPart) 1503 { 1504 /* Then read the signature off the disk */ 1505 (*PartitionBuffer)->Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1]; 1506 } 1507 1508 /* Get the partition descriptor array */ 1509 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1510 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1511 1512 /* Start looping partitions */ 1513 j++; 1514 DPRINT("FSTUB: Partition Table %d:\n", j); 1515 for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++) 1516 { 1517 /* Get the partition type */ 1518 PartitionType = PartitionDescriptor->PartitionType; 1519 1520 /* Print debug messages */ 1521 DPRINT("Partition Entry %d,%d: type %#x %s\n", 1522 j, 1523 Entry, 1524 PartitionType, 1525 (PartitionDescriptor->ActiveFlag) ? "Active" : ""); 1526 DPRINT("\tOffset %#08lx for %#08lx Sectors\n", 1527 GET_STARTING_SECTOR(PartitionDescriptor), 1528 GET_PARTITION_LENGTH(PartitionDescriptor)); 1529 1530 /* Check whether we're facing a protective MBR */ 1531 if (PartitionType == EFI_PMBR_OSTYPE_EFI) 1532 { 1533 /* Partition length might be bigger than disk size */ 1534 FstubFixupEfiPartition(PartitionDescriptor, 1535 MaxOffset); 1536 } 1537 1538 /* Make sure that the partition is valid, unless it's the first */ 1539 if (!(HalpIsValidPartitionEntry(PartitionDescriptor, 1540 MaxOffset, 1541 MaxSector)) && (j == 0)) 1542 { 1543 /* It's invalid, so fail */ 1544 IsValid = FALSE; 1545 break; 1546 } 1547 1548 /* Check if it's a container */ 1549 if (IsContainerPartition(PartitionType)) 1550 { 1551 /* Increase the count of containers */ 1552 if (++k != 1) 1553 { 1554 /* More then one table is invalid */ 1555 DPRINT1("FSTUB: Multiple container partitions found in " 1556 "partition table %d\n - table is invalid\n", 1557 j); 1558 IsValid = FALSE; 1559 break; 1560 } 1561 } 1562 1563 /* Check if the partition is supposedly empty */ 1564 if (IsEmpty) 1565 { 1566 /* But check if it actually has a start and/or length */ 1567 if ((GET_STARTING_SECTOR(PartitionDescriptor)) || 1568 (GET_PARTITION_LENGTH(PartitionDescriptor))) 1569 { 1570 /* So then it's not really empty */ 1571 IsEmpty = FALSE; 1572 } 1573 } 1574 1575 /* Check if the caller wanted only recognized partitions */ 1576 if (ReturnRecognizedPartitions) 1577 { 1578 /* Then check if this one is unused, or a container */ 1579 if ((PartitionType == PARTITION_ENTRY_UNUSED) || 1580 IsContainerPartition(PartitionType)) 1581 { 1582 /* Skip it, since the caller doesn't want it */ 1583 continue; 1584 } 1585 } 1586 1587 /* Increase the structure count and check if they can fit */ 1588 if ((sizeof(DRIVE_LAYOUT_INFORMATION) + 1589 (++i * sizeof(PARTITION_INFORMATION))) > 1590 BufferSize) 1591 { 1592 /* Allocate a new buffer that's twice as big */ 1593 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool, 1594 BufferSize << 1, 1595 TAG_FILE_SYSTEM); 1596 if (!DriveLayoutInfo) 1597 { 1598 /* Out of memory, unto this extra structure */ 1599 --i; 1600 Status = STATUS_INSUFFICIENT_RESOURCES; 1601 break; 1602 } 1603 1604 /* Copy the contents of the old buffer */ 1605 RtlMoveMemory(DriveLayoutInfo, 1606 *PartitionBuffer, 1607 BufferSize); 1608 1609 /* Free the old buffer and set this one as the new one */ 1610 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1611 *PartitionBuffer = DriveLayoutInfo; 1612 1613 /* Double the size */ 1614 BufferSize <<= 1; 1615 } 1616 1617 /* Now get the current structure being filled and initialize it */ 1618 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i]; 1619 PartitionInfo->PartitionType = PartitionType; 1620 PartitionInfo->RewritePartition = FALSE; 1621 1622 /* Check if we're dealing with a partition that's in use */ 1623 if (PartitionType != PARTITION_ENTRY_UNUSED) 1624 { 1625 /* Check if it's bootable */ 1626 PartitionInfo->BootIndicator = PartitionDescriptor-> 1627 ActiveFlag & 0x80 ? 1628 TRUE : FALSE; 1629 1630 /* Check if its' a container */ 1631 if (IsContainerPartition(PartitionType)) 1632 { 1633 /* Then don't recognize it and use the volume offset */ 1634 PartitionInfo->RecognizedPartition = FALSE; 1635 StartOffset = VolumeOffset.QuadPart; 1636 } 1637 else 1638 { 1639 /* Then recognize it and use the partition offset */ 1640 PartitionInfo->RecognizedPartition = TRUE; 1641 StartOffset = Offset.QuadPart; 1642 } 1643 1644 /* Get the starting offset */ 1645 PartitionInfo->StartingOffset.QuadPart = 1646 StartOffset + 1647 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor), 1648 SectorSize); 1649 1650 /* Calculate the number of hidden sectors */ 1651 HiddenSectors64.QuadPart = (PartitionInfo-> 1652 StartingOffset.QuadPart - 1653 StartOffset) / 1654 SectorSize; 1655 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart; 1656 1657 /* Get the partition length */ 1658 PartitionInfo->PartitionLength.QuadPart = 1659 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor), 1660 SectorSize); 1661 1662 /* Get the partition number */ 1663 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0; 1664 } 1665 else 1666 { 1667 /* Otherwise, clear all the relevant fields */ 1668 PartitionInfo->BootIndicator = FALSE; 1669 PartitionInfo->RecognizedPartition = FALSE; 1670 PartitionInfo->StartingOffset.QuadPart = 0; 1671 PartitionInfo->PartitionLength.QuadPart = 0; 1672 PartitionInfo->HiddenSectors = 0; 1673 1674 PartitionInfo->PartitionNumber = 0; 1675 } 1676 } 1677 1678 /* Finish debug log, and check for failure */ 1679 DPRINT("\n"); 1680 if (!NT_SUCCESS(Status)) break; 1681 1682 /* Also check if we hit an invalid entry here */ 1683 if (!IsValid) 1684 { 1685 /* We did, so break out of the loop minus one entry */ 1686 j--; 1687 break; 1688 } 1689 1690 /* Reset the offset */ 1691 Offset.QuadPart = 0; 1692 1693 /* Go back to the descriptor array and loop it */ 1694 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1695 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1696 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1697 { 1698 /* Check if this is a container partition, since we skipped them */ 1699 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 1700 { 1701 /* Get its offset */ 1702 Offset.QuadPart = VolumeOffset.QuadPart + 1703 UInt32x32To64( 1704 GET_STARTING_SECTOR(PartitionDescriptor), 1705 SectorSize); 1706 1707 /* If this is a primary partition, this is the volume offset */ 1708 if (IsPrimary) VolumeOffset = Offset; 1709 1710 /* Also update the maximum sector */ 1711 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor); 1712 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector); 1713 break; 1714 } 1715 } 1716 1717 /* Loop the next partitions, which are not primary anymore */ 1718 IsPrimary = FALSE; 1719 } while (Offset.HighPart | Offset.LowPart); 1720 1721 /* Check if this is a removable device that's probably a super-floppy */ 1722 if ((DiskGeometry.MediaType == RemovableMedia) && 1723 (j == 0) && (MbrFound) && (IsEmpty)) 1724 { 1725 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer; 1726 1727 /* Read the jump bytes to detect super-floppy */ 1728 if ((BootSectorInfo->JumpByte[0] == 0xeb) || 1729 (BootSectorInfo->JumpByte[0] == 0xe9)) 1730 { 1731 /* Super floppes don't have typical MBRs, so skip them */ 1732 DPRINT1("FSTUB: Jump byte %#x found along with empty partition " 1733 "table - disk is a super floppy and has no valid MBR\n", 1734 BootSectorInfo->JumpByte); 1735 j = -1; 1736 } 1737 } 1738 1739 /* Check if we're still at partition -1 */ 1740 if (j == -1) 1741 { 1742 /* The likely cause is the super floppy detection above */ 1743 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia)) 1744 { 1745 /* Print out debugging information */ 1746 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a " 1747 "super-floppy\n", 1748 DeviceObject); 1749 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x " 1750 "bytes large\n", 1751 EndSector, EndSector * DiskGeometry.BytesPerSector); 1752 1753 /* We should at least have some sectors */ 1754 if (EndSector > 0) 1755 { 1756 /* Get the entry we'll use */ 1757 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0]; 1758 1759 /* Fill it out with data for a super-floppy */ 1760 PartitionInfo->RewritePartition = FALSE; 1761 PartitionInfo->RecognizedPartition = TRUE; 1762 PartitionInfo->PartitionType = PARTITION_FAT_16; 1763 PartitionInfo->BootIndicator = FALSE; 1764 PartitionInfo->HiddenSectors = 0; 1765 PartitionInfo->StartingOffset.QuadPart = 0; 1766 PartitionInfo->PartitionLength.QuadPart = (EndSector * 1767 DiskGeometry. 1768 BytesPerSector); 1769 1770 /* FIXME: REACTOS HACK */ 1771 PartitionInfo->PartitionNumber = 0; 1772 1773 /* Set the signature and set the count back to 0 */ 1774 (*PartitionBuffer)->Signature = 1; 1775 i = 0; 1776 } 1777 } 1778 else 1779 { 1780 /* Otherwise, this isn't a super floppy, so set an invalid count */ 1781 i = -1; 1782 } 1783 } 1784 1785 /* Set the partition count */ 1786 (*PartitionBuffer)->PartitionCount = ++i; 1787 1788 /* If we have no count, delete the signature */ 1789 if (!i) (*PartitionBuffer)->Signature = 0; 1790 1791 /* Free the buffer and check for success */ 1792 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1793 if (!NT_SUCCESS(Status)) 1794 { 1795 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM); 1796 *PartitionBuffer = NULL; 1797 } 1798 1799 /* Return status */ 1800 return Status; 1801 } 1802 1803 NTSTATUS 1804 FASTCALL 1805 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 1806 IN ULONG SectorSize, 1807 IN ULONG PartitionNumber, 1808 IN ULONG PartitionType) 1809 { 1810 PIRP Irp; 1811 KEVENT Event; 1812 IO_STATUS_BLOCK IoStatusBlock; 1813 NTSTATUS Status; 1814 LARGE_INTEGER Offset, VolumeOffset; 1815 PUCHAR Buffer = NULL; 1816 ULONG BufferSize; 1817 ULONG i = 0; 1818 ULONG Entry; 1819 PPARTITION_DESCRIPTOR PartitionDescriptor; 1820 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE; 1821 PVOID MbrBuffer; 1822 PIO_STACK_LOCATION IoStackLocation; 1823 VolumeOffset.QuadPart = Offset.QuadPart = 0; 1824 PAGED_CODE(); 1825 1826 /* Normalize the buffer size */ 1827 BufferSize = max(512, SectorSize); 1828 1829 /* Check for EZ Drive */ 1830 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 1831 if (MbrBuffer) 1832 { 1833 /* EZ Drive found, bias the offset */ 1834 IsEzDrive = TRUE; 1835 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 1836 Offset.QuadPart = 512; 1837 } 1838 1839 /* Allocate our partition buffer */ 1840 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 1841 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 1842 1843 /* Initialize the event we'll use and loop partitions */ 1844 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1845 do 1846 { 1847 /* Reset the event since we reuse it */ 1848 KeClearEvent(&Event); 1849 1850 /* Build the read IRP */ 1851 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 1852 DeviceObject, 1853 Buffer, 1854 BufferSize, 1855 &Offset, 1856 &Event, 1857 &IoStatusBlock); 1858 if (!Irp) 1859 { 1860 /* Fail */ 1861 Status = STATUS_INSUFFICIENT_RESOURCES; 1862 break; 1863 } 1864 1865 /* Make sure to disable volume verification */ 1866 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1867 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1868 1869 /* Call the driver */ 1870 Status = IoCallDriver(DeviceObject, Irp); 1871 if (Status == STATUS_PENDING) 1872 { 1873 /* Wait for completion */ 1874 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1875 Status = IoStatusBlock.Status; 1876 } 1877 1878 /* Check for failure */ 1879 if (!NT_SUCCESS(Status)) break; 1880 1881 /* If we biased for EZ-Drive, unbias now */ 1882 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 1883 1884 /* Make sure this is a valid MBR */ 1885 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 1886 { 1887 /* It's not, fail */ 1888 Status = STATUS_BAD_MASTER_BOOT_RECORD; 1889 break; 1890 } 1891 1892 /* Get the partition descriptors and loop them */ 1893 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1894 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1895 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1896 { 1897 /* Check if it's unused or a container partition */ 1898 if ((PartitionDescriptor->PartitionType == 1899 PARTITION_ENTRY_UNUSED) || 1900 (IsContainerPartition(PartitionDescriptor->PartitionType))) 1901 { 1902 /* Go to the next one */ 1903 continue; 1904 } 1905 1906 /* It's a valid partition, so increase the partition count */ 1907 if (++i == PartitionNumber) 1908 { 1909 /* We found a match, set the type */ 1910 PartitionDescriptor->PartitionType = (UCHAR)PartitionType; 1911 1912 /* Reset the reusable event */ 1913 KeClearEvent(&Event); 1914 1915 /* Build the write IRP */ 1916 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 1917 DeviceObject, 1918 Buffer, 1919 BufferSize, 1920 &Offset, 1921 &Event, 1922 &IoStatusBlock); 1923 if (!Irp) 1924 { 1925 /* Fail */ 1926 Status = STATUS_INSUFFICIENT_RESOURCES; 1927 break; 1928 } 1929 1930 /* Disable volume verification */ 1931 IoStackLocation = IoGetNextIrpStackLocation(Irp); 1932 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1933 1934 /* Call the driver */ 1935 Status = IoCallDriver(DeviceObject, Irp); 1936 if (Status == STATUS_PENDING) 1937 { 1938 /* Wait for completion */ 1939 KeWaitForSingleObject(&Event, 1940 Executive, 1941 KernelMode, 1942 FALSE, 1943 NULL); 1944 Status = IoStatusBlock.Status; 1945 } 1946 1947 /* We're done, break out of the loop */ 1948 break; 1949 } 1950 } 1951 1952 /* If we looped all the partitions, break out */ 1953 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break; 1954 1955 /* Nothing found yet, get the partition array again */ 1956 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 1957 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]); 1958 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++) 1959 { 1960 /* Check if this was a container partition (we skipped these) */ 1961 if (IsContainerPartition(PartitionDescriptor->PartitionType)) 1962 { 1963 /* Update the partition offset */ 1964 Offset.QuadPart = VolumeOffset.QuadPart + 1965 GET_STARTING_SECTOR(PartitionDescriptor) * 1966 SectorSize; 1967 1968 /* If this was the primary partition, update the volume too */ 1969 if (IsPrimary) VolumeOffset = Offset; 1970 break; 1971 } 1972 } 1973 1974 /* Check if we already searched all the partitions */ 1975 if (Entry > NUM_PARTITION_TABLE_ENTRIES) 1976 { 1977 /* Then we failed to find a good MBR */ 1978 Status = STATUS_BAD_MASTER_BOOT_RECORD; 1979 break; 1980 } 1981 1982 /* Loop the next partitions, which are not primary anymore */ 1983 IsPrimary = FALSE; 1984 } while (i < PartitionNumber); 1985 1986 /* Everything done, cleanup */ 1987 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 1988 return Status; 1989 } 1990 1991 NTSTATUS 1992 FASTCALL 1993 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 1994 IN ULONG SectorSize, 1995 IN ULONG SectorsPerTrack, 1996 IN ULONG NumberOfHeads, 1997 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 1998 { 1999 KEVENT Event; 2000 IO_STATUS_BLOCK IoStatusBlock; 2001 PIRP Irp; 2002 NTSTATUS Status = STATUS_SUCCESS; 2003 ULONG BufferSize; 2004 PUSHORT Buffer; 2005 PPTE Entry; 2006 PPARTITION_TABLE PartitionTable; 2007 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset; 2008 LARGE_INTEGER StartOffset, PartitionLength; 2009 ULONG i, j; 2010 CCHAR k; 2011 BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr; 2012 ULONG ConventionalCylinders; 2013 LONGLONG DiskSize; 2014 PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer; 2015 PVOID MbrBuffer; 2016 UCHAR PartitionType; 2017 PIO_STACK_LOCATION IoStackLocation; 2018 PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry; 2019 PPARTITION_INFORMATION TableEntry; 2020 ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0; 2021 PAGED_CODE(); 2022 2023 /* Normalize the buffer size */ 2024 BufferSize = max(512, SectorSize); 2025 2026 /* Get the partial drive geometry */ 2027 xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize); 2028 2029 /* Check for EZ Drive */ 2030 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer); 2031 if (MbrBuffer) 2032 { 2033 /* EZ Drive found, bias the offset */ 2034 IsEzDrive = TRUE; 2035 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM); 2036 Offset.QuadPart = 512; 2037 } 2038 2039 /* Get the number of bits to shift to multiply by the sector size */ 2040 for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break; 2041 2042 /* Check if there's only one partition */ 2043 if (PartitionBuffer->PartitionCount == 1) 2044 { 2045 /* Check if it has no starting offset or hidden sectors */ 2046 if (!(PartitionInfo->StartingOffset.QuadPart) && 2047 !(PartitionInfo->HiddenSectors)) 2048 { 2049 /* Then it's a super floppy */ 2050 IsSuperFloppy = TRUE; 2051 2052 /* Which also means it must be non-bootable FAT-16 */ 2053 if ((PartitionInfo->PartitionNumber) || 2054 (PartitionInfo->PartitionType != PARTITION_FAT_16) || 2055 (PartitionInfo->BootIndicator)) 2056 { 2057 /* It's not, so we fail */ 2058 return STATUS_INVALID_PARAMETER; 2059 } 2060 2061 /* Check if it needs a rewrite, and disable EZ drive for sure */ 2062 if (PartitionInfo->RewritePartition) DoRewrite = TRUE; 2063 IsEzDrive = FALSE; 2064 } 2065 } 2066 2067 /* Count the number of partition tables */ 2068 DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4; 2069 2070 /* Allocate our partition buffer */ 2071 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM); 2072 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 2073 2074 /* Loop the entries */ 2075 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET]; 2076 for (i = 0; i < DiskLayout->TableCount; i++) 2077 { 2078 /* Set if this is the MBR partition */ 2079 IsMbr= (BOOLEAN)!i; 2080 2081 /* Initialize th event */ 2082 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2083 2084 /* Build the read IRP */ 2085 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 2086 DeviceObject, 2087 Buffer, 2088 BufferSize, 2089 &Offset, 2090 &Event, 2091 &IoStatusBlock); 2092 if (!Irp) 2093 { 2094 /* Fail */ 2095 Status = STATUS_INSUFFICIENT_RESOURCES; 2096 break; 2097 } 2098 2099 /* Make sure to disable volume verification */ 2100 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2101 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2102 2103 /* Call the driver */ 2104 Status = IoCallDriver(DeviceObject, Irp); 2105 if (Status == STATUS_PENDING) 2106 { 2107 /* Wait for completion */ 2108 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2109 Status = IoStatusBlock.Status; 2110 } 2111 2112 /* Check for failure */ 2113 if (!NT_SUCCESS(Status)) break; 2114 2115 /* If we biased for EZ-Drive, unbias now */ 2116 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2117 2118 /* Check if this is a normal disk */ 2119 if (!IsSuperFloppy) 2120 { 2121 /* Set the boot record signature */ 2122 Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE; 2123 2124 /* By default, don't require a rewrite */ 2125 DoRewrite = FALSE; 2126 2127 /* Check if we don't have an offset */ 2128 if (!Offset.QuadPart) 2129 { 2130 /* Check if the signature doesn't match */ 2131 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] != 2132 PartitionBuffer->Signature) 2133 { 2134 /* Then write the signature and now we need a rewrite */ 2135 ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] = 2136 PartitionBuffer->Signature; 2137 DoRewrite = TRUE; 2138 } 2139 } 2140 2141 /* Loop the partition table entries */ 2142 PartitionTable = &DiskLayout->PartitionTable[i]; 2143 for (j = 0; j < 4; j++) 2144 { 2145 /* Get the current entry and type */ 2146 TableEntry = &PartitionTable->PartitionEntry[j]; 2147 PartitionType = TableEntry->PartitionType; 2148 2149 /* Check if the entry needs a rewrite */ 2150 if (TableEntry->RewritePartition) 2151 { 2152 /* Then we need one too */ 2153 DoRewrite = TRUE; 2154 2155 /* Save the type and if it's a bootable partition */ 2156 Entry[j].PartitionType = TableEntry->PartitionType; 2157 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0; 2158 2159 /* Make sure it's used */ 2160 if (PartitionType != PARTITION_ENTRY_UNUSED) 2161 { 2162 /* Make sure it's not a container (unless primary) */ 2163 if ((IsMbr) || !(IsContainerPartition(PartitionType))) 2164 { 2165 /* Use the partition offset */ 2166 StartOffset.QuadPart = Offset.QuadPart; 2167 } 2168 else 2169 { 2170 /* Use the extended logical partition offset */ 2171 StartOffset.QuadPart = ExtendedOffset.QuadPart; 2172 } 2173 2174 /* Set the sector offset */ 2175 SectorOffset.QuadPart = TableEntry-> 2176 StartingOffset.QuadPart - 2177 StartOffset.QuadPart; 2178 2179 /* Now calculate the starting sector */ 2180 StartOffset.QuadPart = SectorOffset.QuadPart >> k; 2181 Entry[j].StartingSector = StartOffset.LowPart; 2182 2183 /* As well as the length */ 2184 PartitionLength.QuadPart = TableEntry->PartitionLength. 2185 QuadPart >> k; 2186 Entry[j].PartitionLength = PartitionLength.LowPart; 2187 2188 /* Calculate the CHS values */ 2189 HalpCalculateChsValues(&TableEntry->StartingOffset, 2190 &TableEntry->PartitionLength, 2191 k, 2192 SectorsPerTrack, 2193 NumberOfHeads, 2194 ConventionalCylinders, 2195 (PPARTITION_DESCRIPTOR) 2196 &Entry[j]); 2197 } 2198 else 2199 { 2200 /* Otherwise set up an empty entry */ 2201 Entry[j].StartingSector = 0; 2202 Entry[j].PartitionLength = 0; 2203 Entry[j].StartingTrack = 0; 2204 Entry[j].EndingTrack = 0; 2205 Entry[j].StartingCylinder = 0; 2206 Entry[j].EndingCylinder = 0; 2207 } 2208 } 2209 2210 /* Check if this is a container partition */ 2211 if (IsContainerPartition(PartitionType)) 2212 { 2213 /* Then update the offset to use */ 2214 NextOffset = TableEntry->StartingOffset; 2215 } 2216 } 2217 } 2218 2219 /* Check if we need to write back the buffer */ 2220 if (DoRewrite) 2221 { 2222 /* We don't need to do this again */ 2223 DoRewrite = FALSE; 2224 2225 /* Initialize the event */ 2226 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2227 2228 /* If we unbiased for EZ-Drive, rebias now */ 2229 if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512; 2230 2231 /* Build the write IRP */ 2232 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 2233 DeviceObject, 2234 Buffer, 2235 BufferSize, 2236 &Offset, 2237 &Event, 2238 &IoStatusBlock); 2239 if (!Irp) 2240 { 2241 /* Fail */ 2242 Status = STATUS_INSUFFICIENT_RESOURCES; 2243 break; 2244 } 2245 2246 /* Make sure to disable volume verification */ 2247 IoStackLocation = IoGetNextIrpStackLocation(Irp); 2248 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2249 2250 /* Call the driver */ 2251 Status = IoCallDriver(DeviceObject, Irp); 2252 if (Status == STATUS_PENDING) 2253 { 2254 /* Wait for completion */ 2255 KeWaitForSingleObject(&Event, 2256 Executive, 2257 KernelMode, 2258 FALSE, 2259 NULL); 2260 Status = IoStatusBlock.Status; 2261 } 2262 2263 /* Check for failure */ 2264 if (!NT_SUCCESS(Status)) break; 2265 2266 /* If we biased for EZ-Drive, unbias now */ 2267 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0; 2268 } 2269 2270 /* Update the partition offset and set the extended offset if needed */ 2271 Offset = NextOffset; 2272 if (IsMbr) ExtendedOffset = NextOffset; 2273 } 2274 2275 /* If we had a buffer, free it, then return status */ 2276 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM); 2277 return Status; 2278 } 2279 2280 /* PUBLIC FUNCTIONS **********************************************************/ 2281 2282 /* 2283 * @implemented 2284 */ 2285 VOID 2286 FASTCALL 2287 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject, 2288 IN ULONG SectorSize, 2289 IN ULONG MbrTypeIdentifier, 2290 OUT PVOID *MbrBuffer) 2291 { 2292 HALDISPATCH->HalExamineMBR(DeviceObject, 2293 SectorSize, 2294 MbrTypeIdentifier, 2295 MbrBuffer); 2296 } 2297 2298 /* 2299 * @implemented 2300 */ 2301 NTSTATUS 2302 FASTCALL 2303 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, 2304 IN ULONG SectorSize, 2305 IN BOOLEAN ReturnRecognizedPartitions, 2306 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer) 2307 { 2308 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject, 2309 SectorSize, 2310 ReturnRecognizedPartitions, 2311 PartitionBuffer); 2312 } 2313 2314 /* 2315 * @implemented 2316 */ 2317 NTSTATUS 2318 FASTCALL 2319 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, 2320 IN ULONG SectorSize, 2321 IN ULONG PartitionNumber, 2322 IN ULONG PartitionType) 2323 { 2324 return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject, 2325 SectorSize, 2326 PartitionNumber, 2327 PartitionType); 2328 } 2329 2330 /* 2331 * @implemented 2332 */ 2333 NTSTATUS 2334 FASTCALL 2335 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, 2336 IN ULONG SectorSize, 2337 IN ULONG SectorsPerTrack, 2338 IN ULONG NumberOfHeads, 2339 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) 2340 { 2341 return HALDISPATCH->HalIoWritePartitionTable(DeviceObject, 2342 SectorSize, 2343 SectorsPerTrack, 2344 NumberOfHeads, 2345 PartitionBuffer); 2346 } 2347 2348 /* 2349 * @implemented 2350 */ 2351 VOID 2352 FASTCALL 2353 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 2354 IN PSTRING NtDeviceName, 2355 OUT PUCHAR NtSystemPath, 2356 OUT PSTRING NtSystemPathString) 2357 { 2358 HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock, 2359 NtDeviceName, 2360 NtSystemPath, 2361 NtSystemPathString); 2362 } 2363 2364 /* EOF */ 2365