1 /* 2 * PROJECT: ReactOS DiskPart 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/diskpart/partlist.c 5 * PURPOSE: Manages all the partitions of the OS in an interactive way. 6 * PROGRAMMERS: Eric Kohl 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "diskpart.h" 12 #include <ntddscsi.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 #define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\ 18 {\ 19 PLIST_ENTRY current;\ 20 \ 21 current = (ListHead)->Flink;\ 22 while (current != (ListHead))\ 23 {\ 24 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\ 25 (NewEntry)->SortField)\ 26 {\ 27 break;\ 28 }\ 29 current = current->Flink;\ 30 }\ 31 \ 32 InsertTailList(current, &((NewEntry)->ListEntryField));\ 33 } 34 35 /* We have to define it there, because it is not in the MS DDK */ 36 #define PARTITION_LINUX 0x83 37 38 #define PARTITION_TBL_SIZE 4 39 40 #include <pshpack1.h> 41 42 typedef struct _PARTITION 43 { 44 unsigned char BootFlags; /* bootable? 0=no, 128=yes */ 45 unsigned char StartingHead; /* beginning head number */ 46 unsigned char StartingSector; /* beginning sector number */ 47 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */ 48 unsigned char PartitionType; /* Operating System type indicator code */ 49 unsigned char EndingHead; /* ending head number */ 50 unsigned char EndingSector; /* ending sector number */ 51 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */ 52 unsigned int StartingBlock; /* first sector relative to start of disk */ 53 unsigned int SectorCount; /* number of sectors in partition */ 54 } PARTITION, *PPARTITION; 55 56 typedef struct _PARTITION_SECTOR 57 { 58 UCHAR BootCode[440]; /* 0x000 */ 59 ULONG Signature; /* 0x1B8 */ 60 UCHAR Reserved[2]; /* 0x1BC */ 61 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */ 62 USHORT Magic; /* 0x1FE */ 63 } PARTITION_SECTOR, *PPARTITION_SECTOR; 64 65 #include <poppack.h> 66 67 68 /* GLOBALS ********************************************************************/ 69 70 LIST_ENTRY DiskListHead; 71 LIST_ENTRY BiosDiskListHead; 72 73 PDISKENTRY CurrentDisk = NULL; 74 PPARTENTRY CurrentPartition = NULL; 75 76 77 /* FUNCTIONS ******************************************************************/ 78 79 ULONGLONG 80 AlignDown( 81 IN ULONGLONG Value, 82 IN ULONG Alignment) 83 { 84 ULONGLONG Temp; 85 86 Temp = Value / Alignment; 87 88 return Temp * Alignment; 89 } 90 91 static 92 VOID 93 GetDriverName( 94 PDISKENTRY DiskEntry) 95 { 96 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 97 WCHAR KeyName[32]; 98 NTSTATUS Status; 99 100 RtlInitUnicodeString(&DiskEntry->DriverName, 101 NULL); 102 103 swprintf(KeyName, 104 L"\\Scsi\\Scsi Port %lu", 105 DiskEntry->Port); 106 107 RtlZeroMemory(&QueryTable, 108 sizeof(QueryTable)); 109 110 QueryTable[0].Name = L"Driver"; 111 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 112 QueryTable[0].EntryContext = &DiskEntry->DriverName; 113 114 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP, 115 KeyName, 116 QueryTable, 117 NULL, 118 NULL); 119 if (!NT_SUCCESS(Status)) 120 { 121 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 122 } 123 } 124 125 static 126 NTSTATUS 127 NTAPI 128 DiskIdentifierQueryRoutine( 129 PWSTR ValueName, 130 ULONG ValueType, 131 PVOID ValueData, 132 ULONG ValueLength, 133 PVOID Context, 134 PVOID EntryContext) 135 { 136 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 137 UNICODE_STRING NameU; 138 139 if (ValueType == REG_SZ && 140 ValueLength == 20 * sizeof(WCHAR)) 141 { 142 NameU.Buffer = (PWCHAR)ValueData; 143 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR); 144 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum); 145 146 NameU.Buffer = (PWCHAR)ValueData + 9; 147 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature); 148 149 return STATUS_SUCCESS; 150 } 151 152 return STATUS_UNSUCCESSFUL; 153 } 154 155 static 156 NTSTATUS 157 NTAPI 158 DiskConfigurationDataQueryRoutine( 159 PWSTR ValueName, 160 ULONG ValueType, 161 PVOID ValueData, 162 ULONG ValueLength, 163 PVOID Context, 164 PVOID EntryContext) 165 { 166 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 167 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 168 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; 169 ULONG i; 170 171 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 172 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 173 return STATUS_UNSUCCESSFUL; 174 175 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 176 177 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 178 #if 0 179 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 180 FullResourceDescriptor->PartialResourceList.Revision != 1) 181 return STATUS_UNSUCCESSFUL; 182 #endif 183 184 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 185 { 186 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 187 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)) 188 continue; 189 190 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1]; 191 BiosDiskEntry->DiskGeometry = *DiskGeometry; 192 193 return STATUS_SUCCESS; 194 } 195 196 return STATUS_UNSUCCESSFUL; 197 } 198 199 static 200 NTSTATUS 201 NTAPI 202 SystemConfigurationDataQueryRoutine( 203 PWSTR ValueName, 204 ULONG ValueType, 205 PVOID ValueData, 206 ULONG ValueLength, 207 PVOID Context, 208 PVOID EntryContext) 209 { 210 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 211 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context; 212 ULONG i; 213 214 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 215 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR)) 216 return STATUS_UNSUCCESSFUL; 217 218 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 219 220 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 221 #if 0 222 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 223 FullResourceDescriptor->PartialResourceList.Revision != 1) 224 return STATUS_UNSUCCESSFUL; 225 #endif 226 227 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 228 { 229 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 230 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0) 231 continue; 232 233 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0, 234 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 235 if (*Int13Drives == NULL) 236 return STATUS_NO_MEMORY; 237 238 memcpy(*Int13Drives, 239 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1], 240 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 241 return STATUS_SUCCESS; 242 } 243 244 return STATUS_UNSUCCESSFUL; 245 } 246 247 248 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter" 249 250 static 251 VOID 252 EnumerateBiosDiskEntries(VOID) 253 { 254 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 255 WCHAR Name[120]; 256 ULONG AdapterCount; 257 ULONG DiskCount; 258 NTSTATUS Status; 259 PCM_INT13_DRIVE_PARAMETER Int13Drives; 260 PBIOSDISKENTRY BiosDiskEntry; 261 262 memset(QueryTable, 0, sizeof(QueryTable)); 263 264 QueryTable[1].Name = L"Configuration Data"; 265 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine; 266 Int13Drives = NULL; 267 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 268 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System", 269 &QueryTable[1], 270 (PVOID)&Int13Drives, 271 NULL); 272 if (!NT_SUCCESS(Status)) 273 { 274 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status); 275 return; 276 } 277 278 AdapterCount = 0; 279 while (1) 280 { 281 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount); 282 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 283 Name, 284 &QueryTable[2], 285 NULL, 286 NULL); 287 if (!NT_SUCCESS(Status)) 288 { 289 break; 290 } 291 292 swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount); 293 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 294 Name, 295 &QueryTable[2], 296 NULL, 297 NULL); 298 if (NT_SUCCESS(Status)) 299 { 300 while (1) 301 { 302 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount); 303 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 304 Name, 305 &QueryTable[2], 306 NULL, 307 NULL); 308 if (!NT_SUCCESS(Status)) 309 { 310 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 311 return; 312 } 313 314 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount); 315 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 316 Name, 317 &QueryTable[2], 318 NULL, 319 NULL); 320 if (NT_SUCCESS(Status)) 321 { 322 QueryTable[0].Name = L"Identifier"; 323 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine; 324 QueryTable[1].Name = L"Configuration Data"; 325 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine; 326 327 DiskCount = 0; 328 while (1) 329 { 330 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY)); 331 if (BiosDiskEntry == NULL) 332 { 333 break; 334 } 335 336 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount); 337 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 338 Name, 339 QueryTable, 340 (PVOID)BiosDiskEntry, 341 NULL); 342 if (!NT_SUCCESS(Status)) 343 { 344 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 345 break; 346 } 347 348 BiosDiskEntry->DiskNumber = DiskCount; 349 BiosDiskEntry->Recognized = FALSE; 350 351 if (DiskCount < Int13Drives[0].NumberDrives) 352 { 353 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount]; 354 } 355 else 356 { 357 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount); 358 } 359 360 InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry); 361 362 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber); 363 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature); 364 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum); 365 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector); 366 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders); 367 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads); 368 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect); 369 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders); 370 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack); 371 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads); 372 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives); 373 374 DiskCount++; 375 } 376 } 377 378 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 379 return; 380 } 381 } 382 383 AdapterCount++; 384 } 385 386 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 387 } 388 389 390 static 391 VOID 392 AddPartitionToDisk( 393 ULONG DiskNumber, 394 PDISKENTRY DiskEntry, 395 ULONG PartitionIndex, 396 BOOLEAN LogicalPartition) 397 { 398 PPARTITION_INFORMATION PartitionInfo; 399 PPARTENTRY PartEntry; 400 401 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 402 if (PartitionInfo->PartitionType == 0 || 403 (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->PartitionType))) 404 return; 405 406 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 407 HEAP_ZERO_MEMORY, 408 sizeof(PARTENTRY)); 409 if (PartEntry == NULL) 410 { 411 return; 412 } 413 414 PartEntry->DiskEntry = DiskEntry; 415 416 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 417 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 418 419 PartEntry->BootIndicator = PartitionInfo->BootIndicator; 420 PartEntry->PartitionType = PartitionInfo->PartitionType; 421 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors; 422 423 PartEntry->LogicalPartition = LogicalPartition; 424 PartEntry->IsPartitioned = TRUE; 425 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 426 PartEntry->PartitionIndex = PartitionIndex; 427 428 if (IsContainerPartition(PartEntry->PartitionType)) 429 { 430 PartEntry->FormatState = Unformatted; 431 432 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL) 433 DiskEntry->ExtendedPartition = PartEntry; 434 } 435 else if ((PartEntry->PartitionType == PARTITION_FAT_12) || 436 (PartEntry->PartitionType == PARTITION_FAT_16) || 437 (PartEntry->PartitionType == PARTITION_HUGE) || 438 (PartEntry->PartitionType == PARTITION_XINT13) || 439 (PartEntry->PartitionType == PARTITION_FAT32) || 440 (PartEntry->PartitionType == PARTITION_FAT32_XINT13)) 441 { 442 #if 0 443 if (CheckFatFormat()) 444 { 445 PartEntry->FormatState = Preformatted; 446 } 447 else 448 { 449 PartEntry->FormatState = Unformatted; 450 } 451 #endif 452 PartEntry->FormatState = Preformatted; 453 } 454 else if (PartEntry->PartitionType == PARTITION_LINUX) 455 { 456 #if 0 457 if (CheckExt2Format()) 458 { 459 PartEntry->FormatState = Preformatted; 460 } 461 else 462 { 463 PartEntry->FormatState = Unformatted; 464 } 465 #endif 466 PartEntry->FormatState = Preformatted; 467 } 468 else if (PartEntry->PartitionType == PARTITION_IFS) 469 { 470 #if 0 471 if (CheckNtfsFormat()) 472 { 473 PartEntry->FormatState = Preformatted; 474 } 475 else if (CheckHpfsFormat()) 476 { 477 PartEntry->FormatState = Preformatted; 478 } 479 else 480 { 481 PartEntry->FormatState = Unformatted; 482 } 483 #endif 484 PartEntry->FormatState = Preformatted; 485 } 486 else 487 { 488 PartEntry->FormatState = UnknownFormat; 489 } 490 491 if (LogicalPartition) 492 InsertTailList(&DiskEntry->LogicalPartListHead, 493 &PartEntry->ListEntry); 494 else 495 InsertTailList(&DiskEntry->PrimaryPartListHead, 496 &PartEntry->ListEntry); 497 } 498 499 500 static 501 VOID 502 ScanForUnpartitionedDiskSpace( 503 PDISKENTRY DiskEntry) 504 { 505 ULONGLONG LastStartSector; 506 ULONGLONG LastSectorCount; 507 ULONGLONG LastUnusedSectorCount; 508 PPARTENTRY PartEntry; 509 PPARTENTRY NewPartEntry; 510 PLIST_ENTRY Entry; 511 512 DPRINT("ScanForUnpartitionedDiskSpace()\n"); 513 514 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 515 { 516 DPRINT1("No primary partition!\n"); 517 518 /* Create a partition table that represents the empty disk */ 519 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 520 HEAP_ZERO_MEMORY, 521 sizeof(PARTENTRY)); 522 if (NewPartEntry == NULL) 523 return; 524 525 NewPartEntry->DiskEntry = DiskEntry; 526 527 NewPartEntry->IsPartitioned = FALSE; 528 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment; 529 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - 530 NewPartEntry->StartSector.QuadPart; 531 532 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 533 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 534 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 535 536 NewPartEntry->FormatState = Unformatted; 537 538 InsertTailList(&DiskEntry->PrimaryPartListHead, 539 &NewPartEntry->ListEntry); 540 541 return; 542 } 543 544 /* Start partition at head 1, cylinder 0 */ 545 LastStartSector = DiskEntry->SectorAlignment; 546 LastSectorCount = 0ULL; 547 LastUnusedSectorCount = 0ULL; 548 549 Entry = DiskEntry->PrimaryPartListHead.Flink; 550 while (Entry != &DiskEntry->PrimaryPartListHead) 551 { 552 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 553 554 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 555 PartEntry->SectorCount.QuadPart != 0ULL) 556 { 557 LastUnusedSectorCount = 558 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 559 560 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 561 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 562 { 563 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 564 565 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 566 HEAP_ZERO_MEMORY, 567 sizeof(PARTENTRY)); 568 if (NewPartEntry == NULL) 569 return; 570 571 NewPartEntry->DiskEntry = DiskEntry; 572 573 NewPartEntry->IsPartitioned = FALSE; 574 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 575 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 576 NewPartEntry->StartSector.QuadPart; 577 578 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 579 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 580 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 581 582 NewPartEntry->FormatState = Unformatted; 583 584 /* Insert the table into the list */ 585 InsertTailList(&PartEntry->ListEntry, 586 &NewPartEntry->ListEntry); 587 } 588 589 LastStartSector = PartEntry->StartSector.QuadPart; 590 LastSectorCount = PartEntry->SectorCount.QuadPart; 591 } 592 593 Entry = Entry->Flink; 594 } 595 596 /* Check for trailing unpartitioned disk space */ 597 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart) 598 { 599 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 600 601 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 602 { 603 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 604 605 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 606 HEAP_ZERO_MEMORY, 607 sizeof(PARTENTRY)); 608 if (NewPartEntry == NULL) 609 return; 610 611 NewPartEntry->DiskEntry = DiskEntry; 612 613 NewPartEntry->IsPartitioned = FALSE; 614 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 615 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 616 NewPartEntry->StartSector.QuadPart; 617 618 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 619 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 620 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 621 622 NewPartEntry->FormatState = Unformatted; 623 624 /* Append the table to the list */ 625 InsertTailList(&DiskEntry->PrimaryPartListHead, 626 &NewPartEntry->ListEntry); 627 } 628 } 629 630 if (DiskEntry->ExtendedPartition != NULL) 631 { 632 if (IsListEmpty(&DiskEntry->LogicalPartListHead)) 633 { 634 DPRINT1("No logical partition!\n"); 635 636 /* Create a partition table entry that represents the empty extended partition */ 637 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 638 HEAP_ZERO_MEMORY, 639 sizeof(PARTENTRY)); 640 if (NewPartEntry == NULL) 641 return; 642 643 NewPartEntry->DiskEntry = DiskEntry; 644 NewPartEntry->LogicalPartition = TRUE; 645 646 NewPartEntry->IsPartitioned = FALSE; 647 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 648 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 649 650 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 651 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 652 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 653 654 NewPartEntry->FormatState = Unformatted; 655 656 InsertTailList(&DiskEntry->LogicalPartListHead, 657 &NewPartEntry->ListEntry); 658 659 return; 660 } 661 662 /* Start partition at head 1, cylinder 0 */ 663 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 664 LastSectorCount = 0ULL; 665 LastUnusedSectorCount = 0ULL; 666 667 Entry = DiskEntry->LogicalPartListHead.Flink; 668 while (Entry != &DiskEntry->LogicalPartListHead) 669 { 670 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 671 672 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 673 PartEntry->SectorCount.QuadPart != 0ULL) 674 { 675 LastUnusedSectorCount = 676 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount); 677 678 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) && 679 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 680 { 681 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 682 683 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 684 HEAP_ZERO_MEMORY, 685 sizeof(PARTENTRY)); 686 if (NewPartEntry == NULL) 687 return; 688 689 NewPartEntry->DiskEntry = DiskEntry; 690 NewPartEntry->LogicalPartition = TRUE; 691 692 NewPartEntry->IsPartitioned = FALSE; 693 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 694 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 695 NewPartEntry->StartSector.QuadPart; 696 697 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 698 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 699 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 700 701 NewPartEntry->FormatState = Unformatted; 702 703 /* Insert the table into the list */ 704 InsertTailList(&PartEntry->ListEntry, 705 &NewPartEntry->ListEntry); 706 } 707 708 LastStartSector = PartEntry->StartSector.QuadPart; 709 LastSectorCount = PartEntry->SectorCount.QuadPart; 710 } 711 712 Entry = Entry->Flink; 713 } 714 715 /* Check for trailing unpartitioned disk space */ 716 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart) 717 { 718 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), 719 DiskEntry->SectorAlignment); 720 721 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 722 { 723 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 724 725 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 726 HEAP_ZERO_MEMORY, 727 sizeof(PARTENTRY)); 728 if (NewPartEntry == NULL) 729 return; 730 731 NewPartEntry->DiskEntry = DiskEntry; 732 NewPartEntry->LogicalPartition = TRUE; 733 734 NewPartEntry->IsPartitioned = FALSE; 735 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 736 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 737 NewPartEntry->StartSector.QuadPart; 738 739 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 740 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 741 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 742 743 NewPartEntry->FormatState = Unformatted; 744 745 /* Append the table to the list */ 746 InsertTailList(&DiskEntry->LogicalPartListHead, 747 &NewPartEntry->ListEntry); 748 } 749 } 750 } 751 752 DPRINT("ScanForUnpartitionedDiskSpace() done\n"); 753 } 754 755 756 static 757 VOID 758 AddDiskToList( 759 HANDLE FileHandle, 760 ULONG DiskNumber) 761 { 762 DISK_GEOMETRY DiskGeometry; 763 SCSI_ADDRESS ScsiAddress; 764 PDISKENTRY DiskEntry; 765 IO_STATUS_BLOCK Iosb; 766 NTSTATUS Status; 767 PPARTITION_SECTOR Mbr; 768 PULONG Buffer; 769 LARGE_INTEGER FileOffset; 770 WCHAR Identifier[20]; 771 ULONG Checksum; 772 ULONG Signature; 773 ULONG i; 774 PLIST_ENTRY ListEntry; 775 PBIOSDISKENTRY BiosDiskEntry; 776 ULONG LayoutBufferSize; 777 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 778 779 Status = NtDeviceIoControlFile(FileHandle, 780 NULL, 781 NULL, 782 NULL, 783 &Iosb, 784 IOCTL_DISK_GET_DRIVE_GEOMETRY, 785 NULL, 786 0, 787 &DiskGeometry, 788 sizeof(DISK_GEOMETRY)); 789 if (!NT_SUCCESS(Status)) 790 { 791 return; 792 } 793 794 if (DiskGeometry.MediaType != FixedMedia && 795 DiskGeometry.MediaType != RemovableMedia) 796 { 797 return; 798 } 799 800 Status = NtDeviceIoControlFile(FileHandle, 801 NULL, 802 NULL, 803 NULL, 804 &Iosb, 805 IOCTL_SCSI_GET_ADDRESS, 806 NULL, 807 0, 808 &ScsiAddress, 809 sizeof(SCSI_ADDRESS)); 810 if (!NT_SUCCESS(Status)) 811 { 812 return; 813 } 814 815 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(), 816 0, 817 DiskGeometry.BytesPerSector); 818 if (Mbr == NULL) 819 { 820 return; 821 } 822 823 FileOffset.QuadPart = 0; 824 Status = NtReadFile(FileHandle, 825 NULL, 826 NULL, 827 NULL, 828 &Iosb, 829 (PVOID)Mbr, 830 DiskGeometry.BytesPerSector, 831 &FileOffset, 832 NULL); 833 if (!NT_SUCCESS(Status)) 834 { 835 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 836 DPRINT1("NtReadFile failed, status=%x\n", Status); 837 return; 838 } 839 Signature = Mbr->Signature; 840 841 /* Calculate the MBR checksum */ 842 Checksum = 0; 843 Buffer = (PULONG)Mbr; 844 for (i = 0; i < 128; i++) 845 { 846 Checksum += Buffer[i]; 847 } 848 Checksum = ~Checksum + 1; 849 850 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature); 851 DPRINT("Identifier: %S\n", Identifier); 852 853 DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(), 854 HEAP_ZERO_MEMORY, 855 sizeof(DISKENTRY)); 856 if (DiskEntry == NULL) 857 { 858 return; 859 } 860 861 // DiskEntry->Checksum = Checksum; 862 // DiskEntry->Signature = Signature; 863 DiskEntry->BiosFound = FALSE; 864 865 /* Check if this disk has a valid MBR */ 866 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0) 867 DiskEntry->NoMbr = TRUE; 868 else 869 DiskEntry->NoMbr = FALSE; 870 871 /* Free Mbr sector buffer */ 872 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 873 874 ListEntry = BiosDiskListHead.Flink; 875 while (ListEntry != &BiosDiskListHead) 876 { 877 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 878 /* FIXME: 879 * Compare the size from bios and the reported size from driver. 880 * If we have more than one disk with a zero or with the same signatur 881 * we must create new signatures and reboot. After the reboot, 882 * it is possible to identify the disks. 883 */ 884 if (BiosDiskEntry->Signature == Signature && 885 BiosDiskEntry->Checksum == Checksum && 886 !BiosDiskEntry->Recognized) 887 { 888 if (!DiskEntry->BiosFound) 889 { 890 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber; 891 DiskEntry->BiosFound = TRUE; 892 BiosDiskEntry->Recognized = TRUE; 893 } 894 else 895 { 896 } 897 } 898 ListEntry = ListEntry->Flink; 899 } 900 901 if (!DiskEntry->BiosFound) 902 { 903 #if 0 904 RtlFreeHeap(ProcessHeap, 0, DiskEntry); 905 return; 906 #else 907 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber); 908 #endif 909 } 910 911 InitializeListHead(&DiskEntry->PrimaryPartListHead); 912 InitializeListHead(&DiskEntry->LogicalPartListHead); 913 914 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart; 915 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder; 916 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack; 917 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector; 918 919 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders); 920 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder); 921 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack); 922 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector); 923 924 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 925 (ULONGLONG)DiskGeometry.TracksPerCylinder * 926 (ULONGLONG)DiskGeometry.SectorsPerTrack; 927 928 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack; 929 DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder; 930 931 DPRINT1("SectorCount: %I64u\n", DiskEntry->SectorCount); 932 DPRINT1("SectorAlignment: %lu\n", DiskEntry->SectorAlignment); 933 DPRINT1("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment); 934 935 DiskEntry->DiskNumber = DiskNumber; 936 DiskEntry->Port = ScsiAddress.PortNumber; 937 DiskEntry->Bus = ScsiAddress.PathId; 938 DiskEntry->Id = ScsiAddress.TargetId; 939 940 GetDriverName(DiskEntry); 941 942 InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber); 943 944 /* Allocate a layout buffer with 4 partition entries first */ 945 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 946 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 947 DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 948 HEAP_ZERO_MEMORY, 949 LayoutBufferSize); 950 if (DiskEntry->LayoutBuffer == NULL) 951 { 952 DPRINT1("Failed to allocate the disk layout buffer!\n"); 953 return; 954 } 955 956 for (;;) 957 { 958 DPRINT1("Buffer size: %lu\n", LayoutBufferSize); 959 Status = NtDeviceIoControlFile(FileHandle, 960 NULL, 961 NULL, 962 NULL, 963 &Iosb, 964 IOCTL_DISK_GET_DRIVE_LAYOUT, 965 NULL, 966 0, 967 DiskEntry->LayoutBuffer, 968 LayoutBufferSize); 969 if (NT_SUCCESS(Status)) 970 break; 971 972 if (Status != STATUS_BUFFER_TOO_SMALL) 973 { 974 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status); 975 return; 976 } 977 978 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION); 979 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 980 HEAP_ZERO_MEMORY, 981 DiskEntry->LayoutBuffer, 982 LayoutBufferSize); 983 if (NewLayoutBuffer == NULL) 984 { 985 DPRINT1("Failed to reallocate the disk layout buffer!\n"); 986 return; 987 } 988 989 DiskEntry->LayoutBuffer = NewLayoutBuffer; 990 } 991 992 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount); 993 994 #ifdef DUMP_PARTITION_TABLE 995 DumpPartitionTable(DiskEntry); 996 #endif 997 998 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 && 999 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 && 1000 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0) 1001 { 1002 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0) 1003 { 1004 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack); 1005 } 1006 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0) 1007 { 1008 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1009 } 1010 else 1011 { 1012 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart); 1013 } 1014 } 1015 else 1016 { 1017 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1018 } 1019 1020 1021 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1022 { 1023 DiskEntry->NewDisk = TRUE; 1024 DiskEntry->LayoutBuffer->PartitionCount = 4; 1025 1026 for (i = 0; i < 4; i++) 1027 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1028 } 1029 else 1030 { 1031 for (i = 0; i < 4; i++) 1032 { 1033 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE); 1034 } 1035 1036 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4) 1037 { 1038 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE); 1039 } 1040 } 1041 1042 ScanForUnpartitionedDiskSpace(DiskEntry); 1043 } 1044 1045 1046 NTSTATUS 1047 CreatePartitionList(VOID) 1048 { 1049 OBJECT_ATTRIBUTES ObjectAttributes; 1050 SYSTEM_DEVICE_INFORMATION Sdi; 1051 IO_STATUS_BLOCK Iosb; 1052 ULONG ReturnSize; 1053 NTSTATUS Status; 1054 ULONG DiskNumber; 1055 WCHAR Buffer[MAX_PATH]; 1056 UNICODE_STRING Name; 1057 HANDLE FileHandle; 1058 1059 CurrentDisk = NULL; 1060 CurrentPartition = NULL; 1061 1062 // BootDisk = NULL; 1063 // BootPartition = NULL; 1064 1065 // TempDisk = NULL; 1066 // TempPartition = NULL; 1067 // FormatState = Start; 1068 1069 InitializeListHead(&DiskListHead); 1070 InitializeListHead(&BiosDiskListHead); 1071 1072 EnumerateBiosDiskEntries(); 1073 1074 Status = NtQuerySystemInformation(SystemDeviceInformation, 1075 &Sdi, 1076 sizeof(SYSTEM_DEVICE_INFORMATION), 1077 &ReturnSize); 1078 if (!NT_SUCCESS(Status)) 1079 { 1080 return Status; 1081 } 1082 1083 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) 1084 { 1085 swprintf(Buffer, 1086 L"\\Device\\Harddisk%d\\Partition0", 1087 DiskNumber); 1088 RtlInitUnicodeString(&Name, 1089 Buffer); 1090 1091 InitializeObjectAttributes(&ObjectAttributes, 1092 &Name, 1093 0, 1094 NULL, 1095 NULL); 1096 1097 Status = NtOpenFile(&FileHandle, 1098 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 1099 &ObjectAttributes, 1100 &Iosb, 1101 FILE_SHARE_READ, 1102 FILE_SYNCHRONOUS_IO_NONALERT); 1103 if (NT_SUCCESS(Status)) 1104 { 1105 AddDiskToList(FileHandle, DiskNumber); 1106 1107 NtClose(FileHandle); 1108 } 1109 } 1110 1111 // UpdateDiskSignatures(List); 1112 1113 // AssignDriveLetters(List); 1114 1115 return STATUS_SUCCESS; 1116 } 1117 1118 1119 VOID 1120 DestroyPartitionList(VOID) 1121 { 1122 PDISKENTRY DiskEntry; 1123 PBIOSDISKENTRY BiosDiskEntry; 1124 PPARTENTRY PartEntry; 1125 PLIST_ENTRY Entry; 1126 1127 CurrentDisk = NULL; 1128 CurrentPartition = NULL; 1129 1130 /* Release disk and partition info */ 1131 while (!IsListEmpty(&DiskListHead)) 1132 { 1133 Entry = RemoveHeadList(&DiskListHead); 1134 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1135 1136 /* Release driver name */ 1137 RtlFreeUnicodeString(&DiskEntry->DriverName); 1138 1139 /* Release primary partition list */ 1140 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1141 { 1142 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead); 1143 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1144 1145 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1146 } 1147 1148 /* Release logical partition list */ 1149 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 1150 { 1151 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 1152 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1153 1154 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1155 } 1156 1157 /* Release layout buffer */ 1158 if (DiskEntry->LayoutBuffer != NULL) 1159 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer); 1160 1161 1162 /* Release disk entry */ 1163 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry); 1164 } 1165 1166 /* Release the bios disk info */ 1167 while (!IsListEmpty(&BiosDiskListHead)) 1168 { 1169 Entry = RemoveHeadList(&BiosDiskListHead); 1170 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry); 1171 1172 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 1173 } 1174 } 1175 1176 /* EOF */ 1177