1 /* 2 * PROJECT: ReactOS Setup Library 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Partition list functions 5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net) 6 * Copyright 2018-2019 Hermes Belusca-Maito 7 */ 8 9 #include "precomp.h" 10 #include <ntddscsi.h> 11 12 #include "partlist.h" 13 #include "fsrec.h" 14 #include "registry.h" 15 16 #define NDEBUG 17 #include <debug.h> 18 19 //#define DUMP_PARTITION_TABLE 20 21 #include <pshpack1.h> 22 23 typedef struct _REG_DISK_MOUNT_INFO 24 { 25 ULONG Signature; 26 LARGE_INTEGER StartingOffset; 27 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO; 28 29 #include <poppack.h> 30 31 32 /* FUNCTIONS ****************************************************************/ 33 34 #ifdef DUMP_PARTITION_TABLE 35 static 36 VOID 37 DumpPartitionTable( 38 PDISKENTRY DiskEntry) 39 { 40 PPARTITION_INFORMATION PartitionInfo; 41 ULONG i; 42 43 DbgPrint("\n"); 44 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n"); 45 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n"); 46 47 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++) 48 { 49 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i]; 50 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n", 51 i, 52 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector, 53 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector, 54 PartitionInfo->HiddenSectors, 55 PartitionInfo->PartitionNumber, 56 PartitionInfo->PartitionType, 57 PartitionInfo->BootIndicator ? '*': ' ', 58 PartitionInfo->RewritePartition ? 'Y': 'N'); 59 } 60 61 DbgPrint("\n"); 62 } 63 #endif 64 65 66 ULONGLONG 67 AlignDown( 68 IN ULONGLONG Value, 69 IN ULONG Alignment) 70 { 71 ULONGLONG Temp; 72 73 Temp = Value / Alignment; 74 75 return Temp * Alignment; 76 } 77 78 ULONGLONG 79 AlignUp( 80 IN ULONGLONG Value, 81 IN ULONG Alignment) 82 { 83 ULONGLONG Temp, Result; 84 85 Temp = Value / Alignment; 86 87 Result = Temp * Alignment; 88 if (Value % Alignment) 89 Result += Alignment; 90 91 return Result; 92 } 93 94 ULONGLONG 95 RoundingDivide( 96 IN ULONGLONG Dividend, 97 IN ULONGLONG Divisor) 98 { 99 return (Dividend + Divisor / 2) / Divisor; 100 } 101 102 103 static 104 VOID 105 GetDriverName( 106 IN PDISKENTRY DiskEntry) 107 { 108 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 109 WCHAR KeyName[32]; 110 NTSTATUS Status; 111 112 RtlInitUnicodeString(&DiskEntry->DriverName, NULL); 113 114 RtlStringCchPrintfW(KeyName, ARRAYSIZE(KeyName), 115 L"\\Scsi\\Scsi Port %hu", 116 DiskEntry->Port); 117 118 RtlZeroMemory(&QueryTable, sizeof(QueryTable)); 119 120 QueryTable[0].Name = L"Driver"; 121 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 122 QueryTable[0].EntryContext = &DiskEntry->DriverName; 123 124 /* This will allocate DiskEntry->DriverName if needed */ 125 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP, 126 KeyName, 127 QueryTable, 128 NULL, 129 NULL); 130 if (!NT_SUCCESS(Status)) 131 { 132 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 133 } 134 } 135 136 static 137 VOID 138 AssignDriveLetters( 139 IN PPARTLIST List) 140 { 141 PDISKENTRY DiskEntry; 142 PPARTENTRY PartEntry; 143 PLIST_ENTRY Entry1; 144 PLIST_ENTRY Entry2; 145 WCHAR Letter; 146 147 Letter = L'C'; 148 149 /* Assign drive letters to primary partitions */ 150 for (Entry1 = List->DiskListHead.Flink; 151 Entry1 != &List->DiskListHead; 152 Entry1 = Entry1->Flink) 153 { 154 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry); 155 156 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 157 Entry2 != &DiskEntry->PrimaryPartListHead; 158 Entry2 = Entry2->Flink) 159 { 160 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 161 162 PartEntry->DriveLetter = 0; 163 164 if (PartEntry->IsPartitioned && 165 !IsContainerPartition(PartEntry->PartitionType)) 166 { 167 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 168 169 if (IsRecognizedPartition(PartEntry->PartitionType) || 170 PartEntry->SectorCount.QuadPart != 0LL) 171 { 172 if (Letter <= L'Z') 173 { 174 PartEntry->DriveLetter = Letter; 175 Letter++; 176 } 177 } 178 } 179 } 180 } 181 182 /* Assign drive letters to logical drives */ 183 for (Entry1 = List->DiskListHead.Flink; 184 Entry1 != &List->DiskListHead; 185 Entry1 = Entry1->Flink) 186 { 187 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry); 188 189 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 190 Entry2 != &DiskEntry->LogicalPartListHead; 191 Entry2 = Entry2->Flink) 192 { 193 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 194 195 PartEntry->DriveLetter = 0; 196 197 if (PartEntry->IsPartitioned) 198 { 199 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 200 201 if (IsRecognizedPartition(PartEntry->PartitionType) || 202 PartEntry->SectorCount.QuadPart != 0LL) 203 { 204 if (Letter <= L'Z') 205 { 206 PartEntry->DriveLetter = Letter; 207 Letter++; 208 } 209 } 210 } 211 } 212 } 213 } 214 215 static NTSTATUS 216 NTAPI 217 DiskIdentifierQueryRoutine( 218 PWSTR ValueName, 219 ULONG ValueType, 220 PVOID ValueData, 221 ULONG ValueLength, 222 PVOID Context, 223 PVOID EntryContext) 224 { 225 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 226 UNICODE_STRING NameU; 227 228 if (ValueType == REG_SZ && 229 ValueLength == 20 * sizeof(WCHAR) && 230 ((PWCHAR)ValueData)[8] == L'-') 231 { 232 NameU.Buffer = (PWCHAR)ValueData; 233 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR); 234 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum); 235 236 NameU.Buffer = (PWCHAR)ValueData + 9; 237 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature); 238 239 return STATUS_SUCCESS; 240 } 241 242 return STATUS_UNSUCCESSFUL; 243 } 244 245 static NTSTATUS 246 NTAPI 247 DiskConfigurationDataQueryRoutine( 248 PWSTR ValueName, 249 ULONG ValueType, 250 PVOID ValueData, 251 ULONG ValueLength, 252 PVOID Context, 253 PVOID EntryContext) 254 { 255 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 256 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 257 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; 258 ULONG i; 259 260 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 261 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 262 return STATUS_UNSUCCESSFUL; 263 264 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 265 266 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 267 #if 0 268 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 269 FullResourceDescriptor->PartialResourceList.Revision != 1) 270 return STATUS_UNSUCCESSFUL; 271 #endif 272 273 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 274 { 275 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 276 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)) 277 continue; 278 279 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1]; 280 BiosDiskEntry->DiskGeometry = *DiskGeometry; 281 282 return STATUS_SUCCESS; 283 } 284 285 return STATUS_UNSUCCESSFUL; 286 } 287 288 static NTSTATUS 289 NTAPI 290 SystemConfigurationDataQueryRoutine( 291 PWSTR ValueName, 292 ULONG ValueType, 293 PVOID ValueData, 294 ULONG ValueLength, 295 PVOID Context, 296 PVOID EntryContext) 297 { 298 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 299 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context; 300 ULONG i; 301 302 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 303 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 304 return STATUS_UNSUCCESSFUL; 305 306 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 307 308 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 309 #if 0 310 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 311 FullResourceDescriptor->PartialResourceList.Revision != 1) 312 return STATUS_UNSUCCESSFUL; 313 #endif 314 315 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 316 { 317 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 318 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0) 319 continue; 320 321 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0, 322 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 323 if (*Int13Drives == NULL) 324 return STATUS_NO_MEMORY; 325 326 memcpy(*Int13Drives, 327 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1], 328 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 329 return STATUS_SUCCESS; 330 } 331 332 return STATUS_UNSUCCESSFUL; 333 } 334 335 336 static VOID 337 EnumerateBiosDiskEntries( 338 IN PPARTLIST PartList) 339 { 340 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 341 WCHAR Name[120]; 342 ULONG AdapterCount; 343 ULONG ControllerCount; 344 ULONG DiskCount; 345 NTSTATUS Status; 346 PCM_INT13_DRIVE_PARAMETER Int13Drives; 347 PBIOSDISKENTRY BiosDiskEntry; 348 349 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter" 350 351 memset(QueryTable, 0, sizeof(QueryTable)); 352 353 QueryTable[1].Name = L"Configuration Data"; 354 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine; 355 Int13Drives = NULL; 356 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 357 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System", 358 &QueryTable[1], 359 (PVOID)&Int13Drives, 360 NULL); 361 if (!NT_SUCCESS(Status)) 362 { 363 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status); 364 return; 365 } 366 367 for (AdapterCount = 0; ; ++AdapterCount) 368 { 369 RtlStringCchPrintfW(Name, ARRAYSIZE(Name), 370 L"%s\\%lu", 371 ROOT_NAME, AdapterCount); 372 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 373 Name, 374 &QueryTable[2], 375 NULL, 376 NULL); 377 if (!NT_SUCCESS(Status)) 378 { 379 break; 380 } 381 382 RtlStringCchPrintfW(Name, ARRAYSIZE(Name), 383 L"%s\\%lu\\DiskController", 384 ROOT_NAME, AdapterCount); 385 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 386 Name, 387 &QueryTable[2], 388 NULL, 389 NULL); 390 if (NT_SUCCESS(Status)) 391 { 392 for (ControllerCount = 0; ; ++ControllerCount) 393 { 394 RtlStringCchPrintfW(Name, ARRAYSIZE(Name), 395 L"%s\\%lu\\DiskController\\%lu", 396 ROOT_NAME, AdapterCount, ControllerCount); 397 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 398 Name, 399 &QueryTable[2], 400 NULL, 401 NULL); 402 if (!NT_SUCCESS(Status)) 403 { 404 RtlFreeHeap(ProcessHeap, 0, Int13Drives); 405 return; 406 } 407 408 RtlStringCchPrintfW(Name, ARRAYSIZE(Name), 409 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral", 410 ROOT_NAME, AdapterCount, ControllerCount); 411 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 412 Name, 413 &QueryTable[2], 414 NULL, 415 NULL); 416 if (NT_SUCCESS(Status)) 417 { 418 QueryTable[0].Name = L"Identifier"; 419 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine; 420 QueryTable[1].Name = L"Configuration Data"; 421 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine; 422 423 for (DiskCount = 0; ; ++DiskCount) 424 { 425 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY)); 426 if (BiosDiskEntry == NULL) 427 { 428 RtlFreeHeap(ProcessHeap, 0, Int13Drives); 429 return; 430 } 431 432 RtlStringCchPrintfW(Name, ARRAYSIZE(Name), 433 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu", 434 ROOT_NAME, AdapterCount, ControllerCount, DiskCount); 435 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 436 Name, 437 QueryTable, 438 (PVOID)BiosDiskEntry, 439 NULL); 440 if (!NT_SUCCESS(Status)) 441 { 442 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry); 443 RtlFreeHeap(ProcessHeap, 0, Int13Drives); 444 return; 445 } 446 447 BiosDiskEntry->AdapterNumber = 0; // And NOT "AdapterCount" as it needs to be hardcoded for BIOS! 448 BiosDiskEntry->ControllerNumber = ControllerCount; 449 BiosDiskEntry->DiskNumber = DiskCount; 450 BiosDiskEntry->DiskEntry = NULL; 451 452 if (DiskCount < Int13Drives[0].NumberDrives) 453 { 454 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount]; 455 } 456 else 457 { 458 DPRINT1("Didn't find Int13 drive data for disk %u\n", DiskCount); 459 } 460 461 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry); 462 463 DPRINT("--->\n"); 464 DPRINT("AdapterNumber: %lu\n", BiosDiskEntry->AdapterNumber); 465 DPRINT("ControllerNumber: %lu\n", BiosDiskEntry->ControllerNumber); 466 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber); 467 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature); 468 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum); 469 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector); 470 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders); 471 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads); 472 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect); 473 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders); 474 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack); 475 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads); 476 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives); 477 DPRINT("<---\n"); 478 } 479 } 480 } 481 } 482 } 483 484 RtlFreeHeap(ProcessHeap, 0, Int13Drives); 485 486 #undef ROOT_NAME 487 } 488 489 490 /* 491 * Detects whether a disk reports as a "super-floppy", i.e. an unpartitioned 492 * disk with a valid VBR, following the criteria used by IoReadPartitionTable() 493 * and IoWritePartitionTable(): 494 * only one single partition starting at the beginning of the disk; the reported 495 * defaults are: partition number being zero and its type being FAT16 non-bootable. 496 * Note also that accessing \Device\HarddiskN\Partition0 or Partition1 returns 497 * the same data. 498 */ 499 // static 500 BOOLEAN 501 IsSuperFloppy( 502 IN PDISKENTRY DiskEntry) 503 { 504 PPARTITION_INFORMATION PartitionInfo; 505 ULONGLONG PartitionLengthEstimate; 506 507 /* No layout buffer: we cannot say anything yet */ 508 if (DiskEntry->LayoutBuffer == NULL) 509 return FALSE; 510 511 /* We must have only one partition */ 512 if (DiskEntry->LayoutBuffer->PartitionCount != 1) 513 return FALSE; 514 515 /* Get the single partition entry */ 516 PartitionInfo = DiskEntry->LayoutBuffer->PartitionEntry; 517 518 /* The single partition must start at the beginning of the disk */ 519 if (!(PartitionInfo->StartingOffset.QuadPart == 0 && 520 PartitionInfo->HiddenSectors == 0)) 521 { 522 return FALSE; 523 } 524 525 /* The disk signature is usually set to one; warn in case it's not */ 526 if (DiskEntry->LayoutBuffer->Signature != 1) 527 { 528 DPRINT1("Super-Floppy disk %lu signature %08x != 1!\n", 529 DiskEntry->DiskNumber, DiskEntry->LayoutBuffer->Signature); 530 } 531 532 /* 533 * The partition number must be zero or one, be recognized, 534 * have FAT16 type and report as non-bootable. 535 */ 536 if ((PartitionInfo->PartitionNumber != 0 && 537 PartitionInfo->PartitionNumber != 1) || 538 PartitionInfo->RecognizedPartition != TRUE || 539 PartitionInfo->PartitionType != PARTITION_FAT_16 || 540 PartitionInfo->BootIndicator != FALSE) 541 { 542 DPRINT1("Super-Floppy disk %lu does not return default settings!\n" 543 " PartitionNumber = %lu, expected 0\n" 544 " RecognizedPartition = %s, expected TRUE\n" 545 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n" 546 " BootIndicator = %s, expected FALSE\n", 547 DiskEntry->DiskNumber, 548 PartitionInfo->PartitionNumber, 549 PartitionInfo->RecognizedPartition ? "TRUE" : "FALSE", 550 PartitionInfo->PartitionType, 551 PartitionInfo->BootIndicator ? "TRUE" : "FALSE"); 552 } 553 554 /* The partition lengths should agree */ 555 PartitionLengthEstimate = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 556 if (PartitionInfo->PartitionLength.QuadPart != PartitionLengthEstimate) 557 { 558 DPRINT1("PartitionLength = %I64u is different from PartitionLengthEstimate = %I64u\n", 559 PartitionInfo->PartitionLength.QuadPart, PartitionLengthEstimate); 560 } 561 562 return TRUE; 563 } 564 565 566 /* 567 * Inserts the disk region represented by PartEntry into either the primary 568 * or the logical partition list of the given disk. 569 * The lists are kept sorted by increasing order of start sectors. 570 * Of course no disk region should overlap at all with one another. 571 */ 572 static 573 BOOLEAN 574 InsertDiskRegion( 575 IN PDISKENTRY DiskEntry, 576 IN PPARTENTRY PartEntry, 577 IN BOOLEAN LogicalPartition) 578 { 579 PLIST_ENTRY List; 580 PLIST_ENTRY Entry; 581 PPARTENTRY PartEntry2; 582 583 /* Use the correct partition list */ 584 if (LogicalPartition) 585 List = &DiskEntry->LogicalPartListHead; 586 else 587 List = &DiskEntry->PrimaryPartListHead; 588 589 /* Find the first disk region before which we need to insert the new one */ 590 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink) 591 { 592 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 593 594 /* Ignore any unused empty region */ 595 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED && 596 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0) 597 { 598 continue; 599 } 600 601 /* If the current region ends before the one to be inserted, try again */ 602 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart) 603 continue; 604 605 /* 606 * One of the disk region boundaries crosses the desired region 607 * (it starts after the desired region, or ends before the end 608 * of the desired region): this is an impossible situation because 609 * disk regions (partitions) cannot overlap! 610 * Throw an error and bail out. 611 */ 612 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart) 613 <= 614 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1, 615 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1)) 616 { 617 DPRINT1("Disk region overlap problem, stopping there!\n" 618 "Partition to be inserted:\n" 619 " StartSector = %I64u ; EndSector = %I64u\n" 620 "Existing disk region:\n" 621 " StartSector = %I64u ; EndSector = %I64u\n", 622 PartEntry->StartSector.QuadPart, 623 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1, 624 PartEntry2->StartSector.QuadPart, 625 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1); 626 return FALSE; 627 } 628 629 /* We have found the first region before which the new one has to be inserted */ 630 break; 631 } 632 633 /* Insert the disk region */ 634 InsertTailList(Entry, &PartEntry->ListEntry); 635 return TRUE; 636 } 637 638 static 639 PPARTENTRY 640 CreateInsertBlankRegion( 641 IN PDISKENTRY DiskEntry, 642 IN OUT PLIST_ENTRY ListHead, 643 IN ULONGLONG StartSector, 644 IN ULONGLONG SectorCount, 645 IN BOOLEAN LogicalSpace) 646 { 647 PPARTENTRY NewPartEntry; 648 649 NewPartEntry = RtlAllocateHeap(ProcessHeap, 650 HEAP_ZERO_MEMORY, 651 sizeof(PARTENTRY)); 652 if (NewPartEntry == NULL) 653 return NULL; 654 655 NewPartEntry->DiskEntry = DiskEntry; 656 657 NewPartEntry->StartSector.QuadPart = StartSector; 658 NewPartEntry->SectorCount.QuadPart = SectorCount; 659 660 NewPartEntry->LogicalPartition = LogicalSpace; 661 NewPartEntry->IsPartitioned = FALSE; 662 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED; 663 NewPartEntry->FormatState = Unformatted; 664 NewPartEntry->FileSystem[0] = L'\0'; 665 666 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart); 667 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 668 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 669 670 /* Insert the new entry into the list */ 671 InsertTailList(ListHead, &NewPartEntry->ListEntry); 672 673 return NewPartEntry; 674 } 675 676 static 677 BOOLEAN 678 InitializePartitionEntry( 679 IN OUT PPARTENTRY PartEntry, 680 IN ULONGLONG SectorCount, 681 IN BOOLEAN AutoCreate) 682 { 683 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 684 685 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart); 686 687 /* Fail if we try to initialize this partition entry with more sectors than what it actually contains */ 688 if (SectorCount > PartEntry->SectorCount.QuadPart) 689 return FALSE; 690 691 /* Fail if the partition is already in use */ 692 ASSERT(!PartEntry->IsPartitioned); 693 694 if ((AutoCreate != FALSE) || 695 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - 696 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)) 697 { 698 PartEntry->AutoCreate = AutoCreate; 699 } 700 else 701 { 702 ULONGLONG StartSector; 703 ULONGLONG SectorCount2; 704 PPARTENTRY NewPartEntry; 705 706 /* Create a partition entry that represents the remaining space after the partition to be initialized */ 707 708 StartSector = AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment); 709 SectorCount2 = PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - StartSector; 710 711 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 712 PartEntry->ListEntry.Flink, 713 StartSector, 714 SectorCount2, 715 PartEntry->LogicalPartition); 716 if (NewPartEntry == NULL) 717 { 718 DPRINT1("Failed to create a new empty region for disk space!\n"); 719 return FALSE; 720 } 721 722 /* Resize down the partition entry; its StartSector remains the same */ 723 PartEntry->SectorCount.QuadPart = StartSector - PartEntry->StartSector.QuadPart; 724 } 725 726 /* Convert the partition entry to 'New (Unformatted)' */ 727 PartEntry->New = TRUE; 728 PartEntry->IsPartitioned = TRUE; 729 730 // FIXME: Use FileSystemToMBRPartitionType() only for MBR, otherwise use PARTITION_BASIC_DATA_GUID. 731 PartEntry->PartitionType = FileSystemToMBRPartitionType(L"RAW", 732 PartEntry->StartSector.QuadPart, 733 PartEntry->SectorCount.QuadPart); 734 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 735 736 PartEntry->FormatState = Unformatted; 737 PartEntry->FileSystem[0] = L'\0'; 738 // PartEntry->AutoCreate = AutoCreate; 739 PartEntry->BootIndicator = FALSE; 740 741 DPRINT1("First Sector : %I64u\n", PartEntry->StartSector.QuadPart); 742 DPRINT1("Last Sector : %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1); 743 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart); 744 745 return TRUE; 746 } 747 748 749 static 750 VOID 751 AddPartitionToDisk( 752 IN ULONG DiskNumber, 753 IN PDISKENTRY DiskEntry, 754 IN ULONG PartitionIndex, 755 IN BOOLEAN LogicalPartition) 756 { 757 NTSTATUS Status; 758 PPARTITION_INFORMATION PartitionInfo; 759 PPARTENTRY PartEntry; 760 HANDLE PartitionHandle; 761 OBJECT_ATTRIBUTES ObjectAttributes; 762 IO_STATUS_BLOCK IoStatusBlock; 763 WCHAR PathBuffer[MAX_PATH]; 764 UNICODE_STRING Name; 765 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)]; 766 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer; 767 768 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 769 770 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED || 771 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType))) 772 { 773 return; 774 } 775 776 PartEntry = RtlAllocateHeap(ProcessHeap, 777 HEAP_ZERO_MEMORY, 778 sizeof(PARTENTRY)); 779 if (PartEntry == NULL) 780 return; 781 782 PartEntry->DiskEntry = DiskEntry; 783 784 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 785 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 786 787 PartEntry->BootIndicator = PartitionInfo->BootIndicator; 788 PartEntry->PartitionType = PartitionInfo->PartitionType; 789 790 PartEntry->LogicalPartition = LogicalPartition; 791 PartEntry->IsPartitioned = TRUE; 792 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber; 793 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 794 PartEntry->PartitionIndex = PartitionIndex; 795 796 /* Specify the partition as initially unformatted */ 797 PartEntry->FormatState = Unformatted; 798 PartEntry->FileSystem[0] = L'\0'; 799 800 /* Initialize the partition volume label */ 801 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel)); 802 803 if (IsContainerPartition(PartEntry->PartitionType)) 804 { 805 PartEntry->FormatState = Unformatted; 806 807 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL) 808 DiskEntry->ExtendedPartition = PartEntry; 809 } 810 else if (IsRecognizedPartition(PartEntry->PartitionType)) 811 { 812 ASSERT(PartitionInfo->RecognizedPartition); 813 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 814 815 /* Try to open the volume so as to mount it */ 816 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 817 L"\\Device\\Harddisk%lu\\Partition%lu", 818 DiskEntry->DiskNumber, 819 PartEntry->PartitionNumber); 820 RtlInitUnicodeString(&Name, PathBuffer); 821 822 InitializeObjectAttributes(&ObjectAttributes, 823 &Name, 824 OBJ_CASE_INSENSITIVE, 825 NULL, 826 NULL); 827 828 PartitionHandle = NULL; 829 Status = NtOpenFile(&PartitionHandle, 830 FILE_READ_DATA | SYNCHRONIZE, 831 &ObjectAttributes, 832 &IoStatusBlock, 833 FILE_SHARE_READ | FILE_SHARE_WRITE, 834 FILE_SYNCHRONOUS_IO_NONALERT); 835 if (!NT_SUCCESS(Status)) 836 { 837 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status); 838 } 839 840 if (PartitionHandle) 841 { 842 ASSERT(NT_SUCCESS(Status)); 843 844 /* We don't have a FS, try to guess one */ 845 Status = InferFileSystem(NULL, PartitionHandle, 846 PartEntry->FileSystem, 847 sizeof(PartEntry->FileSystem)); 848 if (!NT_SUCCESS(Status)) 849 DPRINT1("InferFileSystem() failed, Status 0x%08lx\n", Status); 850 } 851 if (*PartEntry->FileSystem) 852 { 853 ASSERT(PartitionHandle); 854 855 /* 856 * Handle partition mounted with RawFS: it is 857 * either unformatted or has an unknown format. 858 */ 859 if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0) 860 { 861 /* 862 * True unformatted partitions on NT are created with their 863 * partition type set to either one of the following values, 864 * and are mounted with RawFS. This is done this way since we 865 * are assured to have FAT support, which is the only FS that 866 * uses these partition types. Therefore, having a partition 867 * mounted with RawFS and with these partition types means that 868 * the FAT FS was unable to mount it beforehand and thus the 869 * partition is unformatted. 870 * However, any partition mounted by RawFS that does NOT have 871 * any of these partition types must be considered as having 872 * an unknown format. 873 */ 874 if (PartEntry->PartitionType == PARTITION_FAT_12 || 875 PartEntry->PartitionType == PARTITION_FAT_16 || 876 PartEntry->PartitionType == PARTITION_HUGE || 877 PartEntry->PartitionType == PARTITION_XINT13 || 878 PartEntry->PartitionType == PARTITION_FAT32 || 879 PartEntry->PartitionType == PARTITION_FAT32_XINT13) 880 { 881 PartEntry->FormatState = Unformatted; 882 } 883 else 884 { 885 /* Close the partition before dismounting */ 886 NtClose(PartitionHandle); 887 PartitionHandle = NULL; 888 /* 889 * Dismount the partition since RawFS owns it, and set its 890 * format to unknown (may or may not be actually formatted). 891 */ 892 DismountVolume(PartEntry); 893 PartEntry->FormatState = UnknownFormat; 894 PartEntry->FileSystem[0] = L'\0'; 895 } 896 } 897 else 898 { 899 PartEntry->FormatState = Preformatted; 900 } 901 } 902 else 903 { 904 PartEntry->FormatState = UnknownFormat; 905 } 906 907 /* Retrieve the partition volume label */ 908 if (PartitionHandle) 909 { 910 Status = NtQueryVolumeInformationFile(PartitionHandle, 911 &IoStatusBlock, 912 &LabelBuffer, 913 sizeof(LabelBuffer), 914 FileFsVolumeInformation); 915 if (NT_SUCCESS(Status)) 916 { 917 /* Copy the (possibly truncated) volume label and NULL-terminate it */ 918 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel), 919 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength); 920 } 921 else 922 { 923 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status); 924 } 925 } 926 927 /* Close the partition */ 928 if (PartitionHandle) 929 NtClose(PartitionHandle); 930 } 931 else 932 { 933 /* Unknown partition, hence unknown format (may or may not be actually formatted) */ 934 PartEntry->FormatState = UnknownFormat; 935 } 936 937 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition); 938 } 939 940 static 941 VOID 942 ScanForUnpartitionedDiskSpace( 943 IN PDISKENTRY DiskEntry) 944 { 945 ULONGLONG StartSector; 946 ULONGLONG SectorCount; 947 ULONGLONG LastStartSector; 948 ULONGLONG LastSectorCount; 949 ULONGLONG LastUnusedSectorCount; 950 PPARTENTRY PartEntry; 951 PPARTENTRY NewPartEntry; 952 PLIST_ENTRY Entry; 953 954 DPRINT("ScanForUnpartitionedDiskSpace()\n"); 955 956 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 957 { 958 DPRINT1("No primary partition!\n"); 959 960 /* Create a partition entry that represents the empty disk */ 961 962 if (DiskEntry->SectorAlignment < 2048) 963 StartSector = 2048ULL; 964 else 965 StartSector = (ULONGLONG)DiskEntry->SectorAlignment; 966 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector; 967 968 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 969 &DiskEntry->PrimaryPartListHead, 970 StartSector, 971 SectorCount, 972 FALSE); 973 if (NewPartEntry == NULL) 974 DPRINT1("Failed to create a new empty region for full disk space!\n"); 975 976 return; 977 } 978 979 /* Start partition at head 1, cylinder 0 */ 980 if (DiskEntry->SectorAlignment < 2048) 981 LastStartSector = 2048ULL; 982 else 983 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment; 984 LastSectorCount = 0ULL; 985 LastUnusedSectorCount = 0ULL; 986 987 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 988 Entry != &DiskEntry->PrimaryPartListHead; 989 Entry = Entry->Flink) 990 { 991 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 992 993 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 994 PartEntry->SectorCount.QuadPart != 0ULL) 995 { 996 LastUnusedSectorCount = 997 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 998 999 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 1000 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1001 { 1002 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 1003 1004 StartSector = LastStartSector + LastSectorCount; 1005 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1006 1007 /* Insert the table into the list */ 1008 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1009 &PartEntry->ListEntry, 1010 StartSector, 1011 SectorCount, 1012 FALSE); 1013 if (NewPartEntry == NULL) 1014 { 1015 DPRINT1("Failed to create a new empty region for disk space!\n"); 1016 return; 1017 } 1018 } 1019 1020 LastStartSector = PartEntry->StartSector.QuadPart; 1021 LastSectorCount = PartEntry->SectorCount.QuadPart; 1022 } 1023 } 1024 1025 /* Check for trailing unpartitioned disk space */ 1026 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart) 1027 { 1028 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 1029 1030 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1031 { 1032 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 1033 1034 StartSector = LastStartSector + LastSectorCount; 1035 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1036 1037 /* Append the table to the list */ 1038 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1039 &DiskEntry->PrimaryPartListHead, 1040 StartSector, 1041 SectorCount, 1042 FALSE); 1043 if (NewPartEntry == NULL) 1044 { 1045 DPRINT1("Failed to create a new empty region for trailing disk space!\n"); 1046 return; 1047 } 1048 } 1049 } 1050 1051 if (DiskEntry->ExtendedPartition != NULL) 1052 { 1053 if (IsListEmpty(&DiskEntry->LogicalPartListHead)) 1054 { 1055 DPRINT1("No logical partition!\n"); 1056 1057 /* Create a partition entry that represents the empty extended partition */ 1058 1059 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 1060 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 1061 1062 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1063 &DiskEntry->LogicalPartListHead, 1064 StartSector, 1065 SectorCount, 1066 TRUE); 1067 if (NewPartEntry == NULL) 1068 { 1069 DPRINT1("Failed to create a new empty region for full extended partition space!\n"); 1070 return; 1071 } 1072 1073 return; 1074 } 1075 1076 /* Start partition at head 1, cylinder 0 */ 1077 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 1078 LastSectorCount = 0ULL; 1079 LastUnusedSectorCount = 0ULL; 1080 1081 for (Entry = DiskEntry->LogicalPartListHead.Flink; 1082 Entry != &DiskEntry->LogicalPartListHead; 1083 Entry = Entry->Flink) 1084 { 1085 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1086 1087 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 1088 PartEntry->SectorCount.QuadPart != 0ULL) 1089 { 1090 LastUnusedSectorCount = 1091 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount); 1092 1093 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) && 1094 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1095 { 1096 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 1097 1098 StartSector = LastStartSector + LastSectorCount; 1099 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1100 1101 /* Insert the table into the list */ 1102 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1103 &PartEntry->ListEntry, 1104 StartSector, 1105 SectorCount, 1106 TRUE); 1107 if (NewPartEntry == NULL) 1108 { 1109 DPRINT1("Failed to create a new empty region for extended partition space!\n"); 1110 return; 1111 } 1112 } 1113 1114 LastStartSector = PartEntry->StartSector.QuadPart; 1115 LastSectorCount = PartEntry->SectorCount.QuadPart; 1116 } 1117 } 1118 1119 /* Check for trailing unpartitioned disk space */ 1120 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart) 1121 { 1122 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + 1123 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), 1124 DiskEntry->SectorAlignment); 1125 1126 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1127 { 1128 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 1129 1130 StartSector = LastStartSector + LastSectorCount; 1131 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1132 1133 /* Append the table to the list */ 1134 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1135 &DiskEntry->LogicalPartListHead, 1136 StartSector, 1137 SectorCount, 1138 TRUE); 1139 if (NewPartEntry == NULL) 1140 { 1141 DPRINT1("Failed to create a new empty region for extended partition space!\n"); 1142 return; 1143 } 1144 } 1145 } 1146 } 1147 1148 DPRINT("ScanForUnpartitionedDiskSpace() done\n"); 1149 } 1150 1151 static 1152 VOID 1153 SetDiskSignature( 1154 IN PPARTLIST List, 1155 IN PDISKENTRY DiskEntry) 1156 { 1157 LARGE_INTEGER SystemTime; 1158 TIME_FIELDS TimeFields; 1159 PLIST_ENTRY Entry2; 1160 PDISKENTRY DiskEntry2; 1161 PUCHAR Buffer; 1162 1163 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1164 { 1165 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1166 return; 1167 } 1168 1169 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature; 1170 1171 while (TRUE) 1172 { 1173 NtQuerySystemTime(&SystemTime); 1174 RtlTimeToTimeFields(&SystemTime, &TimeFields); 1175 1176 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF); 1177 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF); 1178 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF); 1179 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF); 1180 1181 if (DiskEntry->LayoutBuffer->Signature == 0) 1182 { 1183 continue; 1184 } 1185 1186 /* Check if the signature already exist */ 1187 /* FIXME: 1188 * Check also signatures from disks, which are 1189 * not visible (bootable) by the bios. 1190 */ 1191 for (Entry2 = List->DiskListHead.Flink; 1192 Entry2 != &List->DiskListHead; 1193 Entry2 = Entry2->Flink) 1194 { 1195 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry); 1196 1197 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT) 1198 { 1199 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1200 continue; 1201 } 1202 1203 if (DiskEntry != DiskEntry2 && 1204 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature) 1205 break; 1206 } 1207 1208 if (Entry2 == &List->DiskListHead) 1209 break; 1210 } 1211 } 1212 1213 static 1214 VOID 1215 UpdateDiskSignatures( 1216 IN PPARTLIST List) 1217 { 1218 PLIST_ENTRY Entry; 1219 PDISKENTRY DiskEntry; 1220 1221 /* Update each disk */ 1222 for (Entry = List->DiskListHead.Flink; 1223 Entry != &List->DiskListHead; 1224 Entry = Entry->Flink) 1225 { 1226 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1227 1228 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1229 { 1230 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1231 continue; 1232 } 1233 1234 if (DiskEntry->LayoutBuffer && 1235 DiskEntry->LayoutBuffer->Signature == 0) 1236 { 1237 SetDiskSignature(List, DiskEntry); 1238 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE; 1239 } 1240 } 1241 } 1242 1243 static 1244 VOID 1245 UpdateHwDiskNumbers( 1246 IN PPARTLIST List) 1247 { 1248 PLIST_ENTRY ListEntry; 1249 PBIOSDISKENTRY BiosDiskEntry; 1250 PDISKENTRY DiskEntry; 1251 ULONG HwAdapterNumber = 0; 1252 ULONG HwControllerNumber = 0; 1253 ULONG RemovableDiskCount = 0; 1254 1255 /* 1256 * Enumerate the disks recognized by the BIOS and recompute the disk 1257 * numbers on the system when *ALL* removable disks are not connected. 1258 * The entries are inserted in increasing order of AdapterNumber, 1259 * ControllerNumber and DiskNumber. 1260 */ 1261 for (ListEntry = List->BiosDiskListHead.Flink; 1262 ListEntry != &List->BiosDiskListHead; 1263 ListEntry = ListEntry->Flink) 1264 { 1265 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 1266 DiskEntry = BiosDiskEntry->DiskEntry; 1267 1268 /* 1269 * If the adapter or controller numbers change, update them and reset 1270 * the number of removable disks on this adapter/controller. 1271 */ 1272 if (HwAdapterNumber != BiosDiskEntry->AdapterNumber || 1273 HwControllerNumber != BiosDiskEntry->ControllerNumber) 1274 { 1275 HwAdapterNumber = BiosDiskEntry->AdapterNumber; 1276 HwControllerNumber = BiosDiskEntry->ControllerNumber; 1277 RemovableDiskCount = 0; 1278 } 1279 1280 /* Adjust the actual hardware disk number */ 1281 if (DiskEntry) 1282 { 1283 ASSERT(DiskEntry->HwDiskNumber == BiosDiskEntry->DiskNumber); 1284 1285 if (DiskEntry->MediaType == RemovableMedia) 1286 { 1287 /* Increase the number of removable disks and set the disk number to zero */ 1288 ++RemovableDiskCount; 1289 DiskEntry->HwFixedDiskNumber = 0; 1290 } 1291 else // if (DiskEntry->MediaType == FixedMedia) 1292 { 1293 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */ 1294 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber - RemovableDiskCount; 1295 } 1296 } 1297 else 1298 { 1299 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry->DiskNumber); 1300 } 1301 } 1302 } 1303 1304 static 1305 VOID 1306 AddDiskToList( 1307 IN HANDLE FileHandle, 1308 IN ULONG DiskNumber, 1309 IN PPARTLIST List) 1310 { 1311 DISK_GEOMETRY DiskGeometry; 1312 SCSI_ADDRESS ScsiAddress; 1313 PDISKENTRY DiskEntry; 1314 IO_STATUS_BLOCK Iosb; 1315 NTSTATUS Status; 1316 PPARTITION_SECTOR Mbr; 1317 PULONG Buffer; 1318 LARGE_INTEGER FileOffset; 1319 WCHAR Identifier[20]; 1320 ULONG Checksum; 1321 ULONG Signature; 1322 ULONG i; 1323 PLIST_ENTRY ListEntry; 1324 PBIOSDISKENTRY BiosDiskEntry; 1325 ULONG LayoutBufferSize; 1326 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 1327 1328 /* Retrieve the drive geometry */ 1329 Status = NtDeviceIoControlFile(FileHandle, 1330 NULL, 1331 NULL, 1332 NULL, 1333 &Iosb, 1334 IOCTL_DISK_GET_DRIVE_GEOMETRY, 1335 NULL, 1336 0, 1337 &DiskGeometry, 1338 sizeof(DiskGeometry)); 1339 if (!NT_SUCCESS(Status)) 1340 return; 1341 1342 if (DiskGeometry.MediaType != FixedMedia && 1343 DiskGeometry.MediaType != RemovableMedia) 1344 { 1345 return; 1346 } 1347 1348 /* 1349 * FIXME: Here we suppose the disk is always SCSI. What if it is 1350 * of another type? To check this we need to retrieve the name of 1351 * the driver the disk device belongs to. 1352 */ 1353 Status = NtDeviceIoControlFile(FileHandle, 1354 NULL, 1355 NULL, 1356 NULL, 1357 &Iosb, 1358 IOCTL_SCSI_GET_ADDRESS, 1359 NULL, 1360 0, 1361 &ScsiAddress, 1362 sizeof(ScsiAddress)); 1363 if (!NT_SUCCESS(Status)) 1364 return; 1365 1366 /* 1367 * Check whether the disk is initialized, by looking at its MBR. 1368 * NOTE that this must be generalized to GPT disks as well! 1369 */ 1370 1371 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap, 1372 0, 1373 DiskGeometry.BytesPerSector); 1374 if (Mbr == NULL) 1375 return; 1376 1377 FileOffset.QuadPart = 0; 1378 Status = NtReadFile(FileHandle, 1379 NULL, 1380 NULL, 1381 NULL, 1382 &Iosb, 1383 (PVOID)Mbr, 1384 DiskGeometry.BytesPerSector, 1385 &FileOffset, 1386 NULL); 1387 if (!NT_SUCCESS(Status)) 1388 { 1389 RtlFreeHeap(ProcessHeap, 0, Mbr); 1390 DPRINT1("NtReadFile failed, status=%x\n", Status); 1391 return; 1392 } 1393 Signature = Mbr->Signature; 1394 1395 /* Calculate the MBR checksum */ 1396 Checksum = 0; 1397 Buffer = (PULONG)Mbr; 1398 for (i = 0; i < 128; i++) 1399 { 1400 Checksum += Buffer[i]; 1401 } 1402 Checksum = ~Checksum + 1; 1403 1404 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier), 1405 L"%08x-%08x-%c", 1406 Checksum, Signature, 1407 (Mbr->Magic == PARTITION_MAGIC) ? L'A' : L'X'); 1408 DPRINT("Identifier: %S\n", Identifier); 1409 1410 DiskEntry = RtlAllocateHeap(ProcessHeap, 1411 HEAP_ZERO_MEMORY, 1412 sizeof(DISKENTRY)); 1413 if (DiskEntry == NULL) 1414 { 1415 RtlFreeHeap(ProcessHeap, 0, Mbr); 1416 DPRINT1("Failed to allocate a new disk entry.\n"); 1417 return; 1418 } 1419 1420 DiskEntry->PartList = List; 1421 1422 #if 0 1423 { 1424 FILE_FS_DEVICE_INFORMATION FileFsDevice; 1425 1426 /* Query the device for its type */ 1427 Status = NtQueryVolumeInformationFile(FileHandle, 1428 &Iosb, 1429 &FileFsDevice, 1430 sizeof(FileFsDevice), 1431 FileFsDeviceInformation); 1432 if (!NT_SUCCESS(Status)) 1433 { 1434 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber, Identifier); 1435 } 1436 else 1437 { 1438 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber, FileFsDevice.DeviceType, FileFsDevice.Characteristics); 1439 } 1440 } 1441 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation). 1442 #endif 1443 DiskEntry->MediaType = DiskGeometry.MediaType; 1444 if (DiskEntry->MediaType == RemovableMedia) 1445 { 1446 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber, Identifier); 1447 } 1448 else // if (DiskEntry->MediaType == FixedMedia) 1449 { 1450 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber, Identifier); 1451 } 1452 1453 // DiskEntry->Checksum = Checksum; 1454 // DiskEntry->Signature = Signature; 1455 DiskEntry->BiosFound = FALSE; 1456 1457 /* 1458 * Check if this disk has a valid MBR: verify its signature, 1459 * and whether its two first bytes are a valid instruction 1460 * (related to this, see IsThereAValidBootSector() in partlist.c). 1461 * 1462 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle(). 1463 */ 1464 1465 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000); 1466 1467 /* If we have not the 0xAA55 then it's raw partition */ 1468 if (Mbr->Magic != PARTITION_MAGIC) 1469 { 1470 DiskEntry->DiskStyle = PARTITION_STYLE_RAW; 1471 } 1472 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */ 1473 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI && 1474 Mbr->Partition[1].PartitionType == 0 && 1475 Mbr->Partition[2].PartitionType == 0 && 1476 Mbr->Partition[3].PartitionType == 0) 1477 { 1478 DiskEntry->DiskStyle = PARTITION_STYLE_GPT; 1479 } 1480 /* Otherwise, partition table is in MBR */ 1481 else 1482 { 1483 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 1484 } 1485 1486 /* Free the MBR sector buffer */ 1487 RtlFreeHeap(ProcessHeap, 0, Mbr); 1488 1489 1490 for (ListEntry = List->BiosDiskListHead.Flink; 1491 ListEntry != &List->BiosDiskListHead; 1492 ListEntry = ListEntry->Flink) 1493 { 1494 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 1495 /* FIXME: 1496 * Compare the size from bios and the reported size from driver. 1497 * If we have more than one disk with a zero or with the same signature 1498 * we must create new signatures and reboot. After the reboot, 1499 * it is possible to identify the disks. 1500 */ 1501 if (BiosDiskEntry->Signature == Signature && 1502 BiosDiskEntry->Checksum == Checksum && 1503 BiosDiskEntry->DiskEntry == NULL) 1504 { 1505 if (!DiskEntry->BiosFound) 1506 { 1507 DiskEntry->HwAdapterNumber = BiosDiskEntry->AdapterNumber; 1508 DiskEntry->HwControllerNumber = BiosDiskEntry->ControllerNumber; 1509 DiskEntry->HwDiskNumber = BiosDiskEntry->DiskNumber; 1510 1511 if (DiskEntry->MediaType == RemovableMedia) 1512 { 1513 /* Set the removable disk number to zero */ 1514 DiskEntry->HwFixedDiskNumber = 0; 1515 } 1516 else // if (DiskEntry->MediaType == FixedMedia) 1517 { 1518 /* The fixed disk number will later be adjusted using the number of removable disks */ 1519 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber; 1520 } 1521 1522 DiskEntry->BiosFound = TRUE; 1523 BiosDiskEntry->DiskEntry = DiskEntry; 1524 break; 1525 } 1526 else 1527 { 1528 // FIXME: What to do? 1529 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber, Identifier); 1530 } 1531 } 1532 } 1533 1534 if (!DiskEntry->BiosFound) 1535 { 1536 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber); 1537 } 1538 1539 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart; 1540 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder; 1541 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack; 1542 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector; 1543 1544 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders); 1545 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder); 1546 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack); 1547 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector); 1548 1549 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 1550 (ULONGLONG)DiskGeometry.TracksPerCylinder * 1551 (ULONGLONG)DiskGeometry.SectorsPerTrack; 1552 1553 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack; 1554 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder * 1555 DiskGeometry.SectorsPerTrack; 1556 1557 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart); 1558 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment); 1559 1560 DiskEntry->DiskNumber = DiskNumber; 1561 DiskEntry->Port = ScsiAddress.PortNumber; 1562 DiskEntry->Bus = ScsiAddress.PathId; 1563 DiskEntry->Id = ScsiAddress.TargetId; 1564 1565 GetDriverName(DiskEntry); 1566 /* 1567 * Actually it would be more correct somehow to use: 1568 * 1569 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo; 1570 * ULONG ReturnedLength; 1571 * 1572 * Status = NtQueryObject(SomeHandleToTheDisk, 1573 * ObjectNameInformation, 1574 * &NameInfo, 1575 * sizeof(NameInfo), 1576 * &ReturnedLength); 1577 * etc... 1578 * 1579 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267 1580 */ 1581 1582 InitializeListHead(&DiskEntry->PrimaryPartListHead); 1583 InitializeListHead(&DiskEntry->LogicalPartListHead); 1584 1585 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber); 1586 1587 1588 /* 1589 * We now retrieve the disk partition layout 1590 */ 1591 1592 /* 1593 * Stop there now if the disk is GPT-partitioned, 1594 * since we currently do not support such disks. 1595 */ 1596 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1597 { 1598 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1599 return; 1600 } 1601 1602 /* Allocate a layout buffer with 4 partition entries first */ 1603 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 1604 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 1605 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap, 1606 HEAP_ZERO_MEMORY, 1607 LayoutBufferSize); 1608 if (DiskEntry->LayoutBuffer == NULL) 1609 { 1610 DPRINT1("Failed to allocate the disk layout buffer!\n"); 1611 return; 1612 } 1613 1614 /* Keep looping while the drive layout buffer is too small */ 1615 for (;;) 1616 { 1617 DPRINT1("Buffer size: %lu\n", LayoutBufferSize); 1618 Status = NtDeviceIoControlFile(FileHandle, 1619 NULL, 1620 NULL, 1621 NULL, 1622 &Iosb, 1623 IOCTL_DISK_GET_DRIVE_LAYOUT, 1624 NULL, 1625 0, 1626 DiskEntry->LayoutBuffer, 1627 LayoutBufferSize); 1628 if (NT_SUCCESS(Status)) 1629 break; 1630 1631 if (Status != STATUS_BUFFER_TOO_SMALL) 1632 { 1633 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status); 1634 return; 1635 } 1636 1637 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION); 1638 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap, 1639 HEAP_ZERO_MEMORY, 1640 DiskEntry->LayoutBuffer, 1641 LayoutBufferSize); 1642 if (NewLayoutBuffer == NULL) 1643 { 1644 DPRINT1("Failed to reallocate the disk layout buffer!\n"); 1645 return; 1646 } 1647 1648 DiskEntry->LayoutBuffer = NewLayoutBuffer; 1649 } 1650 1651 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount); 1652 1653 #ifdef DUMP_PARTITION_TABLE 1654 DumpPartitionTable(DiskEntry); 1655 #endif 1656 1657 if (IsSuperFloppy(DiskEntry)) 1658 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber); 1659 1660 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 && 1661 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 && 1662 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED) 1663 { 1664 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0) 1665 { 1666 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack); 1667 } 1668 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0) 1669 { 1670 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1671 } 1672 else 1673 { 1674 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart); 1675 } 1676 } 1677 else 1678 { 1679 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1680 } 1681 1682 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1683 { 1684 DiskEntry->NewDisk = TRUE; 1685 DiskEntry->LayoutBuffer->PartitionCount = 4; 1686 1687 for (i = 0; i < 4; i++) 1688 { 1689 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1690 } 1691 } 1692 else 1693 { 1694 /* Enumerate and add the first four primary partitions */ 1695 for (i = 0; i < 4; i++) 1696 { 1697 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE); 1698 } 1699 1700 /* Enumerate and add the remaining partitions as logical ones */ 1701 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4) 1702 { 1703 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE); 1704 } 1705 } 1706 1707 ScanForUnpartitionedDiskSpace(DiskEntry); 1708 } 1709 1710 /* 1711 * Retrieve the system disk, i.e. the fixed disk that is accessible by the 1712 * firmware during boot time and where the system partition resides. 1713 * If no system partition has been determined, we retrieve the first disk 1714 * that verifies the mentioned criteria above. 1715 */ 1716 static 1717 PDISKENTRY 1718 GetSystemDisk( 1719 IN PPARTLIST List) 1720 { 1721 PLIST_ENTRY Entry; 1722 PDISKENTRY DiskEntry; 1723 1724 /* Check for empty disk list */ 1725 if (IsListEmpty(&List->DiskListHead)) 1726 return NULL; 1727 1728 /* 1729 * If we already have a system partition, the system disk 1730 * is the one on which the system partition resides. 1731 */ 1732 if (List->SystemPartition) 1733 return List->SystemPartition->DiskEntry; 1734 1735 /* Loop over the disks and find the correct one */ 1736 for (Entry = List->DiskListHead.Flink; 1737 Entry != &List->DiskListHead; 1738 Entry = Entry->Flink) 1739 { 1740 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1741 1742 /* The disk must be a fixed disk and be found by the firmware */ 1743 if (DiskEntry->MediaType == FixedMedia && DiskEntry->BiosFound) 1744 { 1745 break; 1746 } 1747 } 1748 if (Entry == &List->DiskListHead) 1749 { 1750 /* We haven't encountered any suitable disk */ 1751 return NULL; 1752 } 1753 1754 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1755 { 1756 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1757 } 1758 1759 return DiskEntry; 1760 } 1761 1762 /* 1763 * Retrieve the actual "active" partition of the given disk. 1764 * On MBR disks, partition with the Active/Boot flag set; 1765 * on GPT disks, partition with the correct GUID. 1766 */ 1767 BOOLEAN 1768 IsPartitionActive( 1769 IN PPARTENTRY PartEntry) 1770 { 1771 // TODO: Support for GPT disks! 1772 1773 if (IsContainerPartition(PartEntry->PartitionType)) 1774 return FALSE; 1775 1776 /* Check if the partition is partitioned, used and active */ 1777 if (PartEntry->IsPartitioned && 1778 // !IsContainerPartition(PartEntry->PartitionType) && 1779 PartEntry->BootIndicator) 1780 { 1781 /* Yes it is */ 1782 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1783 return TRUE; 1784 } 1785 1786 return FALSE; 1787 } 1788 1789 static 1790 PPARTENTRY 1791 GetActiveDiskPartition( 1792 IN PDISKENTRY DiskEntry) 1793 { 1794 PLIST_ENTRY ListEntry; 1795 PPARTENTRY PartEntry; 1796 PPARTENTRY ActivePartition = NULL; 1797 1798 /* Check for empty disk list */ 1799 // ASSERT(DiskEntry); 1800 if (!DiskEntry) 1801 return NULL; 1802 1803 /* Check for empty partition list */ 1804 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1805 return NULL; 1806 1807 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1808 { 1809 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1810 return NULL; 1811 } 1812 1813 /* Scan all (primary) partitions to find the active disk partition */ 1814 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 1815 ListEntry != &DiskEntry->PrimaryPartListHead; 1816 ListEntry = ListEntry->Flink) 1817 { 1818 /* Retrieve the partition */ 1819 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1820 if (IsPartitionActive(PartEntry)) 1821 { 1822 /* Yes, we've found it */ 1823 ASSERT(DiskEntry == PartEntry->DiskEntry); 1824 ASSERT(PartEntry->IsPartitioned); 1825 1826 ActivePartition = PartEntry; 1827 1828 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n", 1829 PartEntry->PartitionNumber, DiskEntry->DiskNumber, 1830 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter); 1831 break; 1832 } 1833 } 1834 1835 /* Check if the disk is new and if so, use its first partition as the active system partition */ 1836 if (DiskEntry->NewDisk && ActivePartition != NULL) 1837 { 1838 // FIXME: What to do?? 1839 DPRINT1("NewDisk TRUE but already existing active partition?\n"); 1840 } 1841 1842 /* Return the active partition found (or none) */ 1843 return ActivePartition; 1844 } 1845 1846 PPARTLIST 1847 CreatePartitionList(VOID) 1848 { 1849 PPARTLIST List; 1850 PDISKENTRY SystemDisk; 1851 OBJECT_ATTRIBUTES ObjectAttributes; 1852 SYSTEM_DEVICE_INFORMATION Sdi; 1853 IO_STATUS_BLOCK Iosb; 1854 ULONG ReturnSize; 1855 NTSTATUS Status; 1856 ULONG DiskNumber; 1857 HANDLE FileHandle; 1858 UNICODE_STRING Name; 1859 WCHAR Buffer[MAX_PATH]; 1860 1861 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 1862 0, 1863 sizeof(PARTLIST)); 1864 if (List == NULL) 1865 return NULL; 1866 1867 List->SystemPartition = NULL; 1868 1869 InitializeListHead(&List->DiskListHead); 1870 InitializeListHead(&List->BiosDiskListHead); 1871 1872 /* 1873 * Enumerate the disks seen by the BIOS; this will be used later 1874 * to map drives seen by NTOS with their corresponding BIOS names. 1875 */ 1876 EnumerateBiosDiskEntries(List); 1877 1878 /* Enumerate disks seen by NTOS */ 1879 Status = NtQuerySystemInformation(SystemDeviceInformation, 1880 &Sdi, 1881 sizeof(Sdi), 1882 &ReturnSize); 1883 if (!NT_SUCCESS(Status)) 1884 { 1885 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status); 1886 RtlFreeHeap(ProcessHeap, 0, List); 1887 return NULL; 1888 } 1889 1890 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) 1891 { 1892 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 1893 L"\\Device\\Harddisk%lu\\Partition0", 1894 DiskNumber); 1895 RtlInitUnicodeString(&Name, Buffer); 1896 1897 InitializeObjectAttributes(&ObjectAttributes, 1898 &Name, 1899 OBJ_CASE_INSENSITIVE, 1900 NULL, 1901 NULL); 1902 1903 Status = NtOpenFile(&FileHandle, 1904 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 1905 &ObjectAttributes, 1906 &Iosb, 1907 FILE_SHARE_READ | FILE_SHARE_WRITE, 1908 FILE_SYNCHRONOUS_IO_NONALERT); 1909 if (NT_SUCCESS(Status)) 1910 { 1911 AddDiskToList(FileHandle, DiskNumber, List); 1912 NtClose(FileHandle); 1913 } 1914 } 1915 1916 UpdateDiskSignatures(List); 1917 UpdateHwDiskNumbers(List); 1918 AssignDriveLetters(List); 1919 1920 /* 1921 * Retrieve the system partition: the active partition on the system 1922 * disk (the one that will be booted by default by the hardware). 1923 */ 1924 SystemDisk = GetSystemDisk(List); 1925 List->SystemPartition = (SystemDisk ? GetActiveDiskPartition(SystemDisk) : NULL); 1926 1927 return List; 1928 } 1929 1930 VOID 1931 DestroyPartitionList( 1932 IN PPARTLIST List) 1933 { 1934 PDISKENTRY DiskEntry; 1935 PBIOSDISKENTRY BiosDiskEntry; 1936 PPARTENTRY PartEntry; 1937 PLIST_ENTRY Entry; 1938 1939 /* Release disk and partition info */ 1940 while (!IsListEmpty(&List->DiskListHead)) 1941 { 1942 Entry = RemoveHeadList(&List->DiskListHead); 1943 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1944 1945 /* Release driver name */ 1946 RtlFreeUnicodeString(&DiskEntry->DriverName); 1947 1948 /* Release primary partition list */ 1949 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1950 { 1951 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead); 1952 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1953 1954 RtlFreeHeap(ProcessHeap, 0, PartEntry); 1955 } 1956 1957 /* Release logical partition list */ 1958 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 1959 { 1960 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 1961 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1962 1963 RtlFreeHeap(ProcessHeap, 0, PartEntry); 1964 } 1965 1966 /* Release layout buffer */ 1967 if (DiskEntry->LayoutBuffer != NULL) 1968 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer); 1969 1970 /* Release disk entry */ 1971 RtlFreeHeap(ProcessHeap, 0, DiskEntry); 1972 } 1973 1974 /* Release the bios disk info */ 1975 while (!IsListEmpty(&List->BiosDiskListHead)) 1976 { 1977 Entry = RemoveHeadList(&List->BiosDiskListHead); 1978 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry); 1979 1980 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry); 1981 } 1982 1983 /* Release list head */ 1984 RtlFreeHeap(ProcessHeap, 0, List); 1985 } 1986 1987 PDISKENTRY 1988 GetDiskByBiosNumber( 1989 IN PPARTLIST List, 1990 IN ULONG HwDiskNumber) 1991 { 1992 PDISKENTRY DiskEntry; 1993 PLIST_ENTRY Entry; 1994 1995 /* Loop over the disks and find the correct one */ 1996 for (Entry = List->DiskListHead.Flink; 1997 Entry != &List->DiskListHead; 1998 Entry = Entry->Flink) 1999 { 2000 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2001 2002 if (DiskEntry->HwDiskNumber == HwDiskNumber) 2003 { 2004 /* Disk found */ 2005 return DiskEntry; 2006 } 2007 } 2008 2009 /* Disk not found, stop there */ 2010 return NULL; 2011 } 2012 2013 PDISKENTRY 2014 GetDiskByNumber( 2015 IN PPARTLIST List, 2016 IN ULONG DiskNumber) 2017 { 2018 PDISKENTRY DiskEntry; 2019 PLIST_ENTRY Entry; 2020 2021 /* Loop over the disks and find the correct one */ 2022 for (Entry = List->DiskListHead.Flink; 2023 Entry != &List->DiskListHead; 2024 Entry = Entry->Flink) 2025 { 2026 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2027 2028 if (DiskEntry->DiskNumber == DiskNumber) 2029 { 2030 /* Disk found */ 2031 return DiskEntry; 2032 } 2033 } 2034 2035 /* Disk not found, stop there */ 2036 return NULL; 2037 } 2038 2039 PDISKENTRY 2040 GetDiskBySCSI( 2041 IN PPARTLIST List, 2042 IN USHORT Port, 2043 IN USHORT Bus, 2044 IN USHORT Id) 2045 { 2046 PDISKENTRY DiskEntry; 2047 PLIST_ENTRY Entry; 2048 2049 /* Loop over the disks and find the correct one */ 2050 for (Entry = List->DiskListHead.Flink; 2051 Entry != &List->DiskListHead; 2052 Entry = Entry->Flink) 2053 { 2054 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2055 2056 if (DiskEntry->Port == Port && 2057 DiskEntry->Bus == Bus && 2058 DiskEntry->Id == Id) 2059 { 2060 /* Disk found */ 2061 return DiskEntry; 2062 } 2063 } 2064 2065 /* Disk not found, stop there */ 2066 return NULL; 2067 } 2068 2069 PDISKENTRY 2070 GetDiskBySignature( 2071 IN PPARTLIST List, 2072 IN ULONG Signature) 2073 { 2074 PDISKENTRY DiskEntry; 2075 PLIST_ENTRY Entry; 2076 2077 /* Loop over the disks and find the correct one */ 2078 for (Entry = List->DiskListHead.Flink; 2079 Entry != &List->DiskListHead; 2080 Entry = Entry->Flink) 2081 { 2082 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2083 2084 if (DiskEntry->LayoutBuffer->Signature == Signature) 2085 { 2086 /* Disk found */ 2087 return DiskEntry; 2088 } 2089 } 2090 2091 /* Disk not found, stop there */ 2092 return NULL; 2093 } 2094 2095 PPARTENTRY 2096 GetPartition( 2097 // IN PPARTLIST List, 2098 IN PDISKENTRY DiskEntry, 2099 IN ULONG PartitionNumber) 2100 { 2101 PPARTENTRY PartEntry; 2102 PLIST_ENTRY Entry; 2103 2104 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2105 { 2106 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2107 return NULL; 2108 } 2109 2110 /* Disk found, loop over the primary partitions first... */ 2111 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 2112 Entry != &DiskEntry->PrimaryPartListHead; 2113 Entry = Entry->Flink) 2114 { 2115 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2116 2117 if (PartEntry->PartitionNumber == PartitionNumber) 2118 { 2119 /* Partition found */ 2120 return PartEntry; 2121 } 2122 } 2123 2124 /* ... then over the logical partitions if needed */ 2125 for (Entry = DiskEntry->LogicalPartListHead.Flink; 2126 Entry != &DiskEntry->LogicalPartListHead; 2127 Entry = Entry->Flink) 2128 { 2129 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2130 2131 if (PartEntry->PartitionNumber == PartitionNumber) 2132 { 2133 /* Partition found */ 2134 return PartEntry; 2135 } 2136 } 2137 2138 /* The partition was not found on the disk, stop there */ 2139 return NULL; 2140 } 2141 2142 BOOLEAN 2143 GetDiskOrPartition( 2144 IN PPARTLIST List, 2145 IN ULONG DiskNumber, 2146 IN ULONG PartitionNumber OPTIONAL, 2147 OUT PDISKENTRY* pDiskEntry, 2148 OUT PPARTENTRY* pPartEntry OPTIONAL) 2149 { 2150 PDISKENTRY DiskEntry; 2151 PPARTENTRY PartEntry = NULL; 2152 2153 /* Find the disk */ 2154 DiskEntry = GetDiskByNumber(List, DiskNumber); 2155 if (!DiskEntry) 2156 return FALSE; 2157 2158 /* If we have a partition (PartitionNumber != 0), find it */ 2159 if (PartitionNumber != 0) 2160 { 2161 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2162 { 2163 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2164 return FALSE; 2165 } 2166 2167 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber); 2168 if (!PartEntry) 2169 return FALSE; 2170 ASSERT(PartEntry->DiskEntry == DiskEntry); 2171 } 2172 2173 /* Return the disk (and optionally the partition) */ 2174 *pDiskEntry = DiskEntry; 2175 if (pPartEntry) *pPartEntry = PartEntry; 2176 return TRUE; 2177 } 2178 2179 // 2180 // NOTE: Was introduced broken in r6258 by Casper 2181 // 2182 PPARTENTRY 2183 SelectPartition( 2184 IN PPARTLIST List, 2185 IN ULONG DiskNumber, 2186 IN ULONG PartitionNumber) 2187 { 2188 PDISKENTRY DiskEntry; 2189 PPARTENTRY PartEntry; 2190 2191 DiskEntry = GetDiskByNumber(List, DiskNumber); 2192 if (!DiskEntry) 2193 return NULL; 2194 2195 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber); 2196 if (!PartEntry) 2197 return NULL; 2198 2199 ASSERT(PartEntry->DiskEntry == DiskEntry); 2200 ASSERT(DiskEntry->DiskNumber == DiskNumber); 2201 ASSERT(PartEntry->PartitionNumber == PartitionNumber); 2202 2203 return PartEntry; 2204 } 2205 2206 PPARTENTRY 2207 GetNextPartition( 2208 IN PPARTLIST List, 2209 IN PPARTENTRY CurrentPart OPTIONAL) 2210 { 2211 PLIST_ENTRY DiskListEntry; 2212 PLIST_ENTRY PartListEntry; 2213 PDISKENTRY CurrentDisk; 2214 2215 /* Fail if no disks are available */ 2216 if (IsListEmpty(&List->DiskListHead)) 2217 return NULL; 2218 2219 /* Check for the next usable entry on the current partition's disk */ 2220 if (CurrentPart != NULL) 2221 { 2222 CurrentDisk = CurrentPart->DiskEntry; 2223 2224 if (CurrentPart->LogicalPartition) 2225 { 2226 /* Logical partition */ 2227 2228 PartListEntry = CurrentPart->ListEntry.Flink; 2229 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2230 { 2231 /* Next logical partition */ 2232 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2233 return CurrentPart; 2234 } 2235 else 2236 { 2237 PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink; 2238 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2239 { 2240 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2241 return CurrentPart; 2242 } 2243 } 2244 } 2245 else 2246 { 2247 /* Primary or extended partition */ 2248 2249 if (CurrentPart->IsPartitioned && 2250 IsContainerPartition(CurrentPart->PartitionType)) 2251 { 2252 /* First logical partition */ 2253 PartListEntry = CurrentDisk->LogicalPartListHead.Flink; 2254 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2255 { 2256 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2257 return CurrentPart; 2258 } 2259 } 2260 else 2261 { 2262 /* Next primary partition */ 2263 PartListEntry = CurrentPart->ListEntry.Flink; 2264 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2265 { 2266 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2267 return CurrentPart; 2268 } 2269 } 2270 } 2271 } 2272 2273 /* Search for the first partition entry on the next disk */ 2274 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink 2275 : List->DiskListHead.Flink); 2276 DiskListEntry != &List->DiskListHead; 2277 DiskListEntry = DiskListEntry->Flink) 2278 { 2279 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry); 2280 2281 if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT) 2282 { 2283 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2284 continue; 2285 } 2286 2287 PartListEntry = CurrentDisk->PrimaryPartListHead.Flink; 2288 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2289 { 2290 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2291 return CurrentPart; 2292 } 2293 } 2294 2295 return NULL; 2296 } 2297 2298 PPARTENTRY 2299 GetPrevPartition( 2300 IN PPARTLIST List, 2301 IN PPARTENTRY CurrentPart OPTIONAL) 2302 { 2303 PLIST_ENTRY DiskListEntry; 2304 PLIST_ENTRY PartListEntry; 2305 PDISKENTRY CurrentDisk; 2306 2307 /* Fail if no disks are available */ 2308 if (IsListEmpty(&List->DiskListHead)) 2309 return NULL; 2310 2311 /* Check for the previous usable entry on the current partition's disk */ 2312 if (CurrentPart != NULL) 2313 { 2314 CurrentDisk = CurrentPart->DiskEntry; 2315 2316 if (CurrentPart->LogicalPartition) 2317 { 2318 /* Logical partition */ 2319 2320 PartListEntry = CurrentPart->ListEntry.Blink; 2321 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2322 { 2323 /* Previous logical partition */ 2324 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2325 } 2326 else 2327 { 2328 /* Extended partition */ 2329 CurrentPart = CurrentDisk->ExtendedPartition; 2330 } 2331 return CurrentPart; 2332 } 2333 else 2334 { 2335 /* Primary or extended partition */ 2336 2337 PartListEntry = CurrentPart->ListEntry.Blink; 2338 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2339 { 2340 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2341 2342 if (CurrentPart->IsPartitioned && 2343 IsContainerPartition(CurrentPart->PartitionType)) 2344 { 2345 PartListEntry = CurrentDisk->LogicalPartListHead.Blink; 2346 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2347 } 2348 2349 return CurrentPart; 2350 } 2351 } 2352 } 2353 2354 /* Search for the last partition entry on the previous disk */ 2355 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink 2356 : List->DiskListHead.Blink); 2357 DiskListEntry != &List->DiskListHead; 2358 DiskListEntry = DiskListEntry->Blink) 2359 { 2360 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry); 2361 2362 if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT) 2363 { 2364 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2365 continue; 2366 } 2367 2368 PartListEntry = CurrentDisk->PrimaryPartListHead.Blink; 2369 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2370 { 2371 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2372 2373 if (CurrentPart->IsPartitioned && 2374 IsContainerPartition(CurrentPart->PartitionType)) 2375 { 2376 PartListEntry = CurrentDisk->LogicalPartListHead.Blink; 2377 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2378 { 2379 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2380 return CurrentPart; 2381 } 2382 } 2383 else 2384 { 2385 return CurrentPart; 2386 } 2387 } 2388 } 2389 2390 return NULL; 2391 } 2392 2393 // static 2394 FORCEINLINE 2395 BOOLEAN 2396 IsEmptyLayoutEntry( 2397 IN PPARTITION_INFORMATION PartitionInfo) 2398 { 2399 if (PartitionInfo->StartingOffset.QuadPart == 0 && 2400 PartitionInfo->PartitionLength.QuadPart == 0) 2401 { 2402 return TRUE; 2403 } 2404 2405 return FALSE; 2406 } 2407 2408 // static 2409 FORCEINLINE 2410 BOOLEAN 2411 IsSamePrimaryLayoutEntry( 2412 IN PPARTITION_INFORMATION PartitionInfo, 2413 IN PDISKENTRY DiskEntry, 2414 IN PPARTENTRY PartEntry) 2415 { 2416 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector && 2417 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) 2418 // PartitionInfo->PartitionType == PartEntry->PartitionType 2419 { 2420 return TRUE; 2421 } 2422 2423 return FALSE; 2424 } 2425 2426 static 2427 ULONG 2428 GetPrimaryPartitionCount( 2429 IN PDISKENTRY DiskEntry) 2430 { 2431 PLIST_ENTRY Entry; 2432 PPARTENTRY PartEntry; 2433 ULONG Count = 0; 2434 2435 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2436 { 2437 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2438 return 0; 2439 } 2440 2441 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 2442 Entry != &DiskEntry->PrimaryPartListHead; 2443 Entry = Entry->Flink) 2444 { 2445 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2446 if (PartEntry->IsPartitioned) 2447 Count++; 2448 } 2449 2450 return Count; 2451 } 2452 2453 static 2454 ULONG 2455 GetLogicalPartitionCount( 2456 IN PDISKENTRY DiskEntry) 2457 { 2458 PLIST_ENTRY ListEntry; 2459 PPARTENTRY PartEntry; 2460 ULONG Count = 0; 2461 2462 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2463 { 2464 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2465 return 0; 2466 } 2467 2468 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2469 ListEntry != &DiskEntry->LogicalPartListHead; 2470 ListEntry = ListEntry->Flink) 2471 { 2472 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2473 if (PartEntry->IsPartitioned) 2474 Count++; 2475 } 2476 2477 return Count; 2478 } 2479 2480 static 2481 BOOLEAN 2482 ReAllocateLayoutBuffer( 2483 IN PDISKENTRY DiskEntry) 2484 { 2485 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 2486 ULONG NewPartitionCount; 2487 ULONG CurrentPartitionCount = 0; 2488 ULONG LayoutBufferSize; 2489 ULONG i; 2490 2491 DPRINT1("ReAllocateLayoutBuffer()\n"); 2492 2493 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4; 2494 2495 if (DiskEntry->LayoutBuffer) 2496 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 2497 2498 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n", 2499 CurrentPartitionCount, NewPartitionCount); 2500 2501 if (CurrentPartitionCount == NewPartitionCount) 2502 return TRUE; 2503 2504 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 2505 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 2506 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap, 2507 HEAP_ZERO_MEMORY, 2508 DiskEntry->LayoutBuffer, 2509 LayoutBufferSize); 2510 if (NewLayoutBuffer == NULL) 2511 { 2512 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize); 2513 return FALSE; 2514 } 2515 2516 NewLayoutBuffer->PartitionCount = NewPartitionCount; 2517 2518 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */ 2519 if (NewPartitionCount > CurrentPartitionCount) 2520 { 2521 for (i = CurrentPartitionCount; i < NewPartitionCount; i++) 2522 { 2523 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 2524 } 2525 } 2526 2527 DiskEntry->LayoutBuffer = NewLayoutBuffer; 2528 2529 return TRUE; 2530 } 2531 2532 static 2533 VOID 2534 UpdateDiskLayout( 2535 IN PDISKENTRY DiskEntry) 2536 { 2537 PPARTITION_INFORMATION PartitionInfo; 2538 PPARTITION_INFORMATION LinkInfo = NULL; 2539 PLIST_ENTRY ListEntry; 2540 PPARTENTRY PartEntry; 2541 LARGE_INTEGER HiddenSectors64; 2542 ULONG Index; 2543 ULONG PartitionNumber = 1; 2544 2545 DPRINT1("UpdateDiskLayout()\n"); 2546 2547 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2548 { 2549 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2550 return; 2551 } 2552 2553 /* Resize the layout buffer if necessary */ 2554 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE) 2555 { 2556 DPRINT("ReAllocateLayoutBuffer() failed.\n"); 2557 return; 2558 } 2559 2560 /* Update the primary partition table */ 2561 Index = 0; 2562 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2563 ListEntry != &DiskEntry->PrimaryPartListHead; 2564 ListEntry = ListEntry->Flink) 2565 { 2566 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2567 2568 if (PartEntry->IsPartitioned) 2569 { 2570 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2571 2572 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2573 PartEntry->PartitionIndex = Index; 2574 2575 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2576 if (PartEntry->New) 2577 PartEntry->PartitionNumber = 0; 2578 2579 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0); 2580 2581 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry)) 2582 { 2583 DPRINT1("Updating primary partition entry %lu\n", Index); 2584 2585 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 2586 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2587 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart; 2588 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2589 PartitionInfo->PartitionType = PartEntry->PartitionType; 2590 PartitionInfo->BootIndicator = PartEntry->BootIndicator; 2591 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 2592 PartitionInfo->RewritePartition = TRUE; 2593 } 2594 2595 if (!IsContainerPartition(PartEntry->PartitionType)) 2596 PartitionNumber++; 2597 2598 Index++; 2599 } 2600 } 2601 2602 ASSERT(Index <= 4); 2603 2604 /* Update the logical partition table */ 2605 Index = 4; 2606 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2607 ListEntry != &DiskEntry->LogicalPartListHead; 2608 ListEntry = ListEntry->Flink) 2609 { 2610 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2611 2612 if (PartEntry->IsPartitioned) 2613 { 2614 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2615 2616 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2617 PartEntry->PartitionIndex = Index; 2618 2619 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2620 if (PartEntry->New) 2621 PartEntry->PartitionNumber = 0; 2622 2623 PartEntry->OnDiskPartitionNumber = PartitionNumber; 2624 2625 DPRINT1("Updating logical partition entry %lu\n", Index); 2626 2627 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 2628 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2629 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment; 2630 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2631 PartitionInfo->PartitionType = PartEntry->PartitionType; 2632 PartitionInfo->BootIndicator = FALSE; 2633 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 2634 PartitionInfo->RewritePartition = TRUE; 2635 2636 /* Fill the link entry of the previous partition entry */ 2637 if (LinkInfo != NULL) 2638 { 2639 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2640 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2641 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart; 2642 LinkInfo->HiddenSectors = HiddenSectors64.LowPart; 2643 LinkInfo->PartitionNumber = 0; 2644 LinkInfo->PartitionType = PARTITION_EXTENDED; 2645 LinkInfo->BootIndicator = FALSE; 2646 LinkInfo->RecognizedPartition = FALSE; 2647 LinkInfo->RewritePartition = TRUE; 2648 } 2649 2650 /* Save a pointer to the link entry of the current partition entry */ 2651 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1]; 2652 2653 PartitionNumber++; 2654 Index += 4; 2655 } 2656 } 2657 2658 /* Wipe unused primary partition entries */ 2659 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++) 2660 { 2661 DPRINT1("Primary partition entry %lu\n", Index); 2662 2663 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2664 2665 if (!IsEmptyLayoutEntry(PartitionInfo)) 2666 { 2667 DPRINT1("Wiping primary partition entry %lu\n", Index); 2668 2669 PartitionInfo->StartingOffset.QuadPart = 0; 2670 PartitionInfo->PartitionLength.QuadPart = 0; 2671 PartitionInfo->HiddenSectors = 0; 2672 PartitionInfo->PartitionNumber = 0; 2673 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 2674 PartitionInfo->BootIndicator = FALSE; 2675 PartitionInfo->RecognizedPartition = FALSE; 2676 PartitionInfo->RewritePartition = TRUE; 2677 } 2678 } 2679 2680 /* Wipe unused logical partition entries */ 2681 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++) 2682 { 2683 if (Index % 4 >= 2) 2684 { 2685 DPRINT1("Logical partition entry %lu\n", Index); 2686 2687 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2688 2689 if (!IsEmptyLayoutEntry(PartitionInfo)) 2690 { 2691 DPRINT1("Wiping partition entry %lu\n", Index); 2692 2693 PartitionInfo->StartingOffset.QuadPart = 0; 2694 PartitionInfo->PartitionLength.QuadPart = 0; 2695 PartitionInfo->HiddenSectors = 0; 2696 PartitionInfo->PartitionNumber = 0; 2697 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 2698 PartitionInfo->BootIndicator = FALSE; 2699 PartitionInfo->RecognizedPartition = FALSE; 2700 PartitionInfo->RewritePartition = TRUE; 2701 } 2702 } 2703 } 2704 2705 // HACK: See the FIXMEs in WritePartitions(): (Re)set the PartitionStyle to MBR. 2706 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 2707 2708 DiskEntry->Dirty = TRUE; 2709 2710 #ifdef DUMP_PARTITION_TABLE 2711 DumpPartitionTable(DiskEntry); 2712 #endif 2713 } 2714 2715 static 2716 PPARTENTRY 2717 GetPrevUnpartitionedEntry( 2718 IN PPARTENTRY PartEntry) 2719 { 2720 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2721 PPARTENTRY PrevPartEntry; 2722 PLIST_ENTRY ListHead; 2723 2724 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2725 { 2726 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2727 return NULL; 2728 } 2729 2730 if (PartEntry->LogicalPartition) 2731 ListHead = &DiskEntry->LogicalPartListHead; 2732 else 2733 ListHead = &DiskEntry->PrimaryPartListHead; 2734 2735 if (PartEntry->ListEntry.Blink != ListHead) 2736 { 2737 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink, 2738 PARTENTRY, 2739 ListEntry); 2740 if (!PrevPartEntry->IsPartitioned) 2741 { 2742 ASSERT(PrevPartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 2743 return PrevPartEntry; 2744 } 2745 } 2746 2747 return NULL; 2748 } 2749 2750 static 2751 PPARTENTRY 2752 GetNextUnpartitionedEntry( 2753 IN PPARTENTRY PartEntry) 2754 { 2755 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2756 PPARTENTRY NextPartEntry; 2757 PLIST_ENTRY ListHead; 2758 2759 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2760 { 2761 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2762 return NULL; 2763 } 2764 2765 if (PartEntry->LogicalPartition) 2766 ListHead = &DiskEntry->LogicalPartListHead; 2767 else 2768 ListHead = &DiskEntry->PrimaryPartListHead; 2769 2770 if (PartEntry->ListEntry.Flink != ListHead) 2771 { 2772 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink, 2773 PARTENTRY, 2774 ListEntry); 2775 if (!NextPartEntry->IsPartitioned) 2776 { 2777 ASSERT(NextPartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 2778 return NextPartEntry; 2779 } 2780 } 2781 2782 return NULL; 2783 } 2784 2785 BOOLEAN 2786 CreatePrimaryPartition( 2787 IN PPARTLIST List, 2788 IN OUT PPARTENTRY PartEntry, 2789 IN ULONGLONG SectorCount, 2790 IN BOOLEAN AutoCreate) 2791 { 2792 ERROR_NUMBER Error; 2793 2794 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount); 2795 2796 if (List == NULL || PartEntry == NULL || 2797 PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned) 2798 { 2799 return FALSE; 2800 } 2801 2802 Error = PrimaryPartitionCreationChecks(PartEntry); 2803 if (Error != NOT_AN_ERROR) 2804 { 2805 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error); 2806 return FALSE; 2807 } 2808 2809 /* Initialize the partition entry, inserting a new blank region if needed */ 2810 if (!InitializePartitionEntry(PartEntry, SectorCount, AutoCreate)) 2811 return FALSE; 2812 2813 ASSERT(PartEntry->LogicalPartition == FALSE); 2814 2815 UpdateDiskLayout(PartEntry->DiskEntry); 2816 AssignDriveLetters(List); 2817 2818 return TRUE; 2819 } 2820 2821 static 2822 VOID 2823 AddLogicalDiskSpace( 2824 IN PDISKENTRY DiskEntry) 2825 { 2826 ULONGLONG StartSector; 2827 ULONGLONG SectorCount; 2828 PPARTENTRY NewPartEntry; 2829 2830 DPRINT1("AddLogicalDiskSpace()\n"); 2831 2832 /* Create a partition entry that represents the empty space in the container partition */ 2833 2834 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 2835 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 2836 2837 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 2838 &DiskEntry->LogicalPartListHead, 2839 StartSector, 2840 SectorCount, 2841 TRUE); 2842 if (NewPartEntry == NULL) 2843 { 2844 DPRINT1("Failed to create a new empty region for extended partition space!\n"); 2845 return; 2846 } 2847 } 2848 2849 BOOLEAN 2850 CreateExtendedPartition( 2851 IN PPARTLIST List, 2852 IN OUT PPARTENTRY PartEntry, 2853 IN ULONGLONG SectorCount) 2854 { 2855 ERROR_NUMBER Error; 2856 2857 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount); 2858 2859 if (List == NULL || PartEntry == NULL || 2860 PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned) 2861 { 2862 return FALSE; 2863 } 2864 2865 Error = ExtendedPartitionCreationChecks(PartEntry); 2866 if (Error != NOT_AN_ERROR) 2867 { 2868 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error); 2869 return FALSE; 2870 } 2871 2872 /* Initialize the partition entry, inserting a new blank region if needed */ 2873 if (!InitializePartitionEntry(PartEntry, SectorCount, FALSE)) 2874 return FALSE; 2875 2876 ASSERT(PartEntry->LogicalPartition == FALSE); 2877 2878 if (PartEntry->StartSector.QuadPart < 1450560) 2879 { 2880 /* Partition starts below the 8.4GB boundary ==> CHS partition */ 2881 PartEntry->PartitionType = PARTITION_EXTENDED; 2882 } 2883 else 2884 { 2885 /* Partition starts above the 8.4GB boundary ==> LBA partition */ 2886 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED; 2887 } 2888 2889 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container) 2890 PartEntry->New = FALSE; 2891 PartEntry->FormatState = Formatted; 2892 2893 PartEntry->DiskEntry->ExtendedPartition = PartEntry; 2894 2895 AddLogicalDiskSpace(PartEntry->DiskEntry); 2896 2897 UpdateDiskLayout(PartEntry->DiskEntry); 2898 AssignDriveLetters(List); 2899 2900 return TRUE; 2901 } 2902 2903 BOOLEAN 2904 CreateLogicalPartition( 2905 IN PPARTLIST List, 2906 IN OUT PPARTENTRY PartEntry, 2907 IN ULONGLONG SectorCount, 2908 IN BOOLEAN AutoCreate) 2909 { 2910 ERROR_NUMBER Error; 2911 2912 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount); 2913 2914 if (List == NULL || PartEntry == NULL || 2915 PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned) 2916 { 2917 return FALSE; 2918 } 2919 2920 Error = LogicalPartitionCreationChecks(PartEntry); 2921 if (Error != NOT_AN_ERROR) 2922 { 2923 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error); 2924 return FALSE; 2925 } 2926 2927 /* Initialize the partition entry, inserting a new blank region if needed */ 2928 if (!InitializePartitionEntry(PartEntry, SectorCount, AutoCreate)) 2929 return FALSE; 2930 2931 ASSERT(PartEntry->LogicalPartition == TRUE); 2932 2933 UpdateDiskLayout(PartEntry->DiskEntry); 2934 AssignDriveLetters(List); 2935 2936 return TRUE; 2937 } 2938 2939 NTSTATUS 2940 DismountVolume( 2941 IN PPARTENTRY PartEntry) 2942 { 2943 NTSTATUS Status; 2944 NTSTATUS LockStatus; 2945 UNICODE_STRING Name; 2946 OBJECT_ATTRIBUTES ObjectAttributes; 2947 IO_STATUS_BLOCK IoStatusBlock; 2948 HANDLE PartitionHandle; 2949 WCHAR Buffer[MAX_PATH]; 2950 2951 /* Check whether the partition is valid and was mounted by the system */ 2952 if (!PartEntry->IsPartitioned || 2953 IsContainerPartition(PartEntry->PartitionType) || 2954 !IsRecognizedPartition(PartEntry->PartitionType) || 2955 PartEntry->FormatState == UnknownFormat || 2956 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means 2957 // it has been usually mounted with RawFS and thus needs to be dismounted. 2958 !*PartEntry->FileSystem || 2959 PartEntry->PartitionNumber == 0) 2960 { 2961 /* The partition is not mounted, so just return success */ 2962 return STATUS_SUCCESS; 2963 } 2964 2965 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2966 2967 /* Open the volume */ 2968 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 2969 L"\\Device\\Harddisk%lu\\Partition%lu", 2970 PartEntry->DiskEntry->DiskNumber, 2971 PartEntry->PartitionNumber); 2972 RtlInitUnicodeString(&Name, Buffer); 2973 2974 InitializeObjectAttributes(&ObjectAttributes, 2975 &Name, 2976 OBJ_CASE_INSENSITIVE, 2977 NULL, 2978 NULL); 2979 2980 Status = NtOpenFile(&PartitionHandle, 2981 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2982 &ObjectAttributes, 2983 &IoStatusBlock, 2984 FILE_SHARE_READ | FILE_SHARE_WRITE, 2985 FILE_SYNCHRONOUS_IO_NONALERT); 2986 if (!NT_SUCCESS(Status)) 2987 { 2988 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status); 2989 return Status; 2990 } 2991 2992 /* Lock the volume */ 2993 LockStatus = NtFsControlFile(PartitionHandle, 2994 NULL, 2995 NULL, 2996 NULL, 2997 &IoStatusBlock, 2998 FSCTL_LOCK_VOLUME, 2999 NULL, 3000 0, 3001 NULL, 3002 0); 3003 if (!NT_SUCCESS(LockStatus)) 3004 { 3005 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus); 3006 } 3007 3008 /* Dismount the volume */ 3009 Status = NtFsControlFile(PartitionHandle, 3010 NULL, 3011 NULL, 3012 NULL, 3013 &IoStatusBlock, 3014 FSCTL_DISMOUNT_VOLUME, 3015 NULL, 3016 0, 3017 NULL, 3018 0); 3019 if (!NT_SUCCESS(Status)) 3020 { 3021 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); 3022 } 3023 3024 /* Unlock the volume */ 3025 LockStatus = NtFsControlFile(PartitionHandle, 3026 NULL, 3027 NULL, 3028 NULL, 3029 &IoStatusBlock, 3030 FSCTL_UNLOCK_VOLUME, 3031 NULL, 3032 0, 3033 NULL, 3034 0); 3035 if (!NT_SUCCESS(LockStatus)) 3036 { 3037 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); 3038 } 3039 3040 /* Close the volume */ 3041 NtClose(PartitionHandle); 3042 3043 return Status; 3044 } 3045 3046 BOOLEAN 3047 DeletePartition( 3048 IN PPARTLIST List, 3049 IN PPARTENTRY PartEntry, 3050 OUT PPARTENTRY* FreeRegion OPTIONAL) 3051 { 3052 PDISKENTRY DiskEntry; 3053 PPARTENTRY PrevPartEntry; 3054 PPARTENTRY NextPartEntry; 3055 PPARTENTRY LogicalPartEntry; 3056 PLIST_ENTRY Entry; 3057 3058 if (List == NULL || PartEntry == NULL || 3059 PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned == FALSE) 3060 { 3061 return FALSE; 3062 } 3063 3064 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3065 3066 /* Clear the system partition if it is being deleted */ 3067 if (List->SystemPartition == PartEntry) 3068 { 3069 ASSERT(List->SystemPartition); 3070 List->SystemPartition = NULL; 3071 } 3072 3073 DiskEntry = PartEntry->DiskEntry; 3074 3075 /* Check which type of partition (primary/logical or extended) is being deleted */ 3076 if (DiskEntry->ExtendedPartition == PartEntry) 3077 { 3078 /* An extended partition is being deleted: delete all logical partition entries */ 3079 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 3080 { 3081 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 3082 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 3083 3084 /* Dismount the logical partition */ 3085 DismountVolume(LogicalPartEntry); 3086 3087 /* Delete it */ 3088 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry); 3089 } 3090 3091 DiskEntry->ExtendedPartition = NULL; 3092 } 3093 else 3094 { 3095 /* A primary partition is being deleted: dismount it */ 3096 DismountVolume(PartEntry); 3097 } 3098 3099 /* Adjust the unpartitioned disk space entries */ 3100 3101 /* Get pointer to previous and next unpartitioned entries */ 3102 PrevPartEntry = GetPrevUnpartitionedEntry(PartEntry); 3103 NextPartEntry = GetNextUnpartitionedEntry(PartEntry); 3104 3105 if (PrevPartEntry != NULL && NextPartEntry != NULL) 3106 { 3107 /* Merge the previous, current and next unpartitioned entries */ 3108 3109 /* Adjust the previous entry length */ 3110 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart); 3111 3112 /* Remove the current and next entries */ 3113 RemoveEntryList(&PartEntry->ListEntry); 3114 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3115 RemoveEntryList(&NextPartEntry->ListEntry); 3116 RtlFreeHeap(ProcessHeap, 0, NextPartEntry); 3117 3118 /* Optionally return the freed region */ 3119 if (FreeRegion) 3120 *FreeRegion = PrevPartEntry; 3121 } 3122 else if (PrevPartEntry != NULL && NextPartEntry == NULL) 3123 { 3124 /* Merge the current and the previous unpartitioned entries */ 3125 3126 /* Adjust the previous entry length */ 3127 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart; 3128 3129 /* Remove the current entry */ 3130 RemoveEntryList(&PartEntry->ListEntry); 3131 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3132 3133 /* Optionally return the freed region */ 3134 if (FreeRegion) 3135 *FreeRegion = PrevPartEntry; 3136 } 3137 else if (PrevPartEntry == NULL && NextPartEntry != NULL) 3138 { 3139 /* Merge the current and the next unpartitioned entries */ 3140 3141 /* Adjust the next entry offset and length */ 3142 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart; 3143 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart; 3144 3145 /* Remove the current entry */ 3146 RemoveEntryList(&PartEntry->ListEntry); 3147 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3148 3149 /* Optionally return the freed region */ 3150 if (FreeRegion) 3151 *FreeRegion = NextPartEntry; 3152 } 3153 else 3154 { 3155 /* Nothing to merge but change the current entry */ 3156 PartEntry->IsPartitioned = FALSE; 3157 PartEntry->OnDiskPartitionNumber = 0; 3158 PartEntry->PartitionNumber = 0; 3159 // PartEntry->PartitionIndex = 0; 3160 PartEntry->BootIndicator = FALSE; 3161 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED; 3162 PartEntry->FormatState = Unformatted; 3163 PartEntry->FileSystem[0] = L'\0'; 3164 PartEntry->DriveLetter = 0; 3165 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel)); 3166 3167 /* Optionally return the freed region */ 3168 if (FreeRegion) 3169 *FreeRegion = PartEntry; 3170 } 3171 3172 UpdateDiskLayout(DiskEntry); 3173 AssignDriveLetters(List); 3174 3175 return TRUE; 3176 } 3177 3178 static 3179 BOOLEAN 3180 IsSupportedActivePartition( 3181 IN PPARTENTRY PartEntry) 3182 { 3183 /* Check the type and the file system of this partition */ 3184 3185 /* 3186 * We do not support extended partition containers (on MBR disks) marked 3187 * as active, and containing code inside their extended boot records. 3188 */ 3189 if (IsContainerPartition(PartEntry->PartitionType)) 3190 { 3191 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n", 3192 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber); 3193 return FALSE; 3194 } 3195 3196 /* 3197 * ADDITIONAL CHECKS / BIG HACK: 3198 * 3199 * Retrieve its file system and check whether we have 3200 * write support for it. If that is the case we are fine 3201 * and we can use it directly. However if we don't have 3202 * write support we will need to change the active system 3203 * partition. 3204 * 3205 * NOTE that this is completely useless on architectures 3206 * where a real system partition is required, as on these 3207 * architectures the partition uses the FAT FS, for which 3208 * we do have write support. 3209 * NOTE also that for those architectures looking for a 3210 * partition boot indicator is insufficient. 3211 */ 3212 if (PartEntry->FormatState == Unformatted) 3213 { 3214 /* If this partition is mounted, it would use RawFS ("RAW") */ 3215 return TRUE; 3216 } 3217 else if ((PartEntry->FormatState == Preformatted) || 3218 (PartEntry->FormatState == Formatted)) 3219 { 3220 ASSERT(*PartEntry->FileSystem); 3221 3222 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */ 3223 if (wcsicmp(PartEntry->FileSystem, L"FAT") == 0 || 3224 wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 || 3225 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 || 3226 wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0) 3227 { 3228 return TRUE; 3229 } 3230 else 3231 { 3232 // WARNING: We cannot write on this FS yet! 3233 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n", 3234 PartEntry->FileSystem); 3235 return FALSE; 3236 } 3237 } 3238 else // if (PartEntry->FormatState == UnknownFormat) 3239 { 3240 ASSERT(!*PartEntry->FileSystem); 3241 3242 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n", 3243 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber); 3244 return FALSE; 3245 } 3246 3247 // HACK: WARNING: We cannot write on this FS yet! 3248 // See fsutil.c:InferFileSystem() 3249 if (PartEntry->PartitionType == PARTITION_IFS) 3250 { 3251 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n", 3252 PartEntry->FileSystem); 3253 return FALSE; 3254 } 3255 3256 return TRUE; 3257 } 3258 3259 PPARTENTRY 3260 FindSupportedSystemPartition( 3261 IN PPARTLIST List, 3262 IN BOOLEAN ForceSelect, 3263 IN PDISKENTRY AlternativeDisk OPTIONAL, 3264 IN PPARTENTRY AlternativePart OPTIONAL) 3265 { 3266 PLIST_ENTRY ListEntry; 3267 PDISKENTRY DiskEntry; 3268 PPARTENTRY PartEntry; 3269 PPARTENTRY ActivePartition; 3270 PPARTENTRY CandidatePartition = NULL; 3271 3272 /* Check for empty disk list */ 3273 if (IsListEmpty(&List->DiskListHead)) 3274 { 3275 /* No system partition! */ 3276 ASSERT(List->SystemPartition == NULL); 3277 goto NoSystemPartition; 3278 } 3279 3280 /* Adjust the optional alternative disk if needed */ 3281 if (!AlternativeDisk && AlternativePart) 3282 AlternativeDisk = AlternativePart->DiskEntry; 3283 3284 /* Ensure that the alternative partition is on the alternative disk */ 3285 if (AlternativePart) 3286 ASSERT(AlternativeDisk && (AlternativePart->DiskEntry == AlternativeDisk)); 3287 3288 /* Ensure that the alternative disk is in the list */ 3289 if (AlternativeDisk) 3290 ASSERT(AlternativeDisk->PartList == List); 3291 3292 /* Start fresh */ 3293 CandidatePartition = NULL; 3294 3295 // 3296 // Step 1 : Check the system disk. 3297 // 3298 3299 /* 3300 * First, check whether the system disk, i.e. the one that will be booted 3301 * by default by the hardware, contains an active partition. If so this 3302 * should be our system partition. 3303 */ 3304 DiskEntry = GetSystemDisk(List); 3305 3306 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3307 { 3308 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3309 goto UseAlternativeDisk; 3310 } 3311 3312 /* If we have a system partition (in the system disk), validate it */ 3313 ActivePartition = List->SystemPartition; 3314 if (ActivePartition && IsSupportedActivePartition(ActivePartition)) 3315 { 3316 CandidatePartition = ActivePartition; 3317 3318 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n", 3319 CandidatePartition->PartitionNumber, 3320 CandidatePartition->DiskEntry->DiskNumber, 3321 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3322 3323 /* Return the candidate system partition */ 3324 return CandidatePartition; 3325 } 3326 3327 /* If the system disk is not the optional alternative disk, perform the minimal checks */ 3328 if (DiskEntry != AlternativeDisk) 3329 { 3330 /* 3331 * No active partition has been recognized. Enumerate all the (primary) 3332 * partitions in the system disk, excluding the possible current active 3333 * partition, to find a new candidate. 3334 */ 3335 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3336 ListEntry != &DiskEntry->PrimaryPartListHead; 3337 ListEntry = ListEntry->Flink) 3338 { 3339 /* Retrieve the partition */ 3340 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3341 3342 /* Skip the current active partition */ 3343 if (PartEntry == ActivePartition) 3344 continue; 3345 3346 /* Check if the partition is partitioned and used */ 3347 if (PartEntry->IsPartitioned && 3348 !IsContainerPartition(PartEntry->PartitionType)) 3349 { 3350 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3351 3352 /* If we get a candidate active partition in the disk, validate it */ 3353 if (IsSupportedActivePartition(PartEntry)) 3354 { 3355 CandidatePartition = PartEntry; 3356 goto UseAlternativePartition; 3357 } 3358 } 3359 3360 #if 0 3361 /* Check if the partition is partitioned and used */ 3362 if (!PartEntry->IsPartitioned) 3363 { 3364 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 3365 3366 // TODO: Check for minimal size!! 3367 CandidatePartition = PartEntry; 3368 goto UseAlternativePartition; 3369 } 3370 #endif 3371 } 3372 3373 /* 3374 * Still nothing, look whether there is some free space that we can use 3375 * for the new system partition. We must be sure that the total number 3376 * of partition is less than the maximum allowed, and that the minimal 3377 * size is fine. 3378 */ 3379 // 3380 // TODO: Fix the handling of system partition being created in unpartitioned space!! 3381 // --> When to partition it? etc... 3382 // 3383 if (GetPrimaryPartitionCount(DiskEntry) < 4) 3384 { 3385 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3386 ListEntry != &DiskEntry->PrimaryPartListHead; 3387 ListEntry = ListEntry->Flink) 3388 { 3389 /* Retrieve the partition */ 3390 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3391 3392 /* Skip the current active partition */ 3393 if (PartEntry == ActivePartition) 3394 continue; 3395 3396 /* Check for unpartitioned space */ 3397 if (!PartEntry->IsPartitioned) 3398 { 3399 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 3400 3401 // TODO: Check for minimal size!! 3402 CandidatePartition = PartEntry; 3403 goto UseAlternativePartition; 3404 } 3405 } 3406 } 3407 } 3408 3409 3410 // 3411 // Step 2 : No active partition found: Check the alternative disk if specified. 3412 // 3413 3414 UseAlternativeDisk: 3415 if (!AlternativeDisk || (!ForceSelect && (DiskEntry != AlternativeDisk))) 3416 goto NoSystemPartition; 3417 3418 if (AlternativeDisk->DiskStyle == PARTITION_STYLE_GPT) 3419 { 3420 DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3421 goto NoSystemPartition; 3422 } 3423 3424 if (DiskEntry != AlternativeDisk) 3425 { 3426 /* Choose the alternative disk */ 3427 DiskEntry = AlternativeDisk; 3428 3429 /* If we get a candidate active partition, validate it */ 3430 ActivePartition = GetActiveDiskPartition(DiskEntry); 3431 if (ActivePartition && IsSupportedActivePartition(ActivePartition)) 3432 { 3433 CandidatePartition = ActivePartition; 3434 goto UseAlternativePartition; 3435 } 3436 } 3437 3438 /* We now may have an unsupported active partition, or none */ 3439 3440 /*** 3441 *** TODO: Improve the selection: 3442 *** - If we want a really separate system partition from the partition where 3443 *** we install, do something similar to what's done below in the code. 3444 *** - Otherwise if we allow for the system partition to be also the partition 3445 *** where we install, just directly fall down to using AlternativePart. 3446 ***/ 3447 3448 /* Retrieve the first partition of the disk */ 3449 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink, 3450 PARTENTRY, ListEntry); 3451 ASSERT(DiskEntry == PartEntry->DiskEntry); 3452 3453 CandidatePartition = PartEntry; 3454 3455 // 3456 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318 3457 // 3458 3459 /* Check if the disk is new and if so, use its first partition as the active system partition */ 3460 if (DiskEntry->NewDisk) 3461 { 3462 // !IsContainerPartition(PartEntry->PartitionType); 3463 if (!CandidatePartition->IsPartitioned || !CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */ 3464 { 3465 ASSERT(DiskEntry == CandidatePartition->DiskEntry); 3466 3467 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n", 3468 CandidatePartition->PartitionNumber, 3469 CandidatePartition->DiskEntry->DiskNumber, 3470 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3471 3472 /* Return the candidate system partition */ 3473 return CandidatePartition; 3474 } 3475 3476 // FIXME: What to do?? 3477 DPRINT1("NewDisk TRUE but first partition is used?\n"); 3478 } 3479 3480 /* 3481 * The disk is not new, check if any partition is initialized; 3482 * if not, the first one becomes the system partition. 3483 */ 3484 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3485 ListEntry != &DiskEntry->PrimaryPartListHead; 3486 ListEntry = ListEntry->Flink) 3487 { 3488 /* Retrieve the partition */ 3489 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3490 3491 /* Check if the partition is partitioned and is used */ 3492 // !IsContainerPartition(PartEntry->PartitionType); 3493 if (/* PartEntry->IsPartitioned && */ 3494 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator) 3495 { 3496 break; 3497 } 3498 } 3499 if (ListEntry == &DiskEntry->PrimaryPartListHead) 3500 { 3501 /* 3502 * OK we haven't encountered any used and active partition, 3503 * so use the first one as the system partition. 3504 */ 3505 ASSERT(DiskEntry == CandidatePartition->DiskEntry); 3506 3507 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n", 3508 CandidatePartition->PartitionNumber, 3509 CandidatePartition->DiskEntry->DiskNumber, 3510 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3511 3512 /* Return the candidate system partition */ 3513 return CandidatePartition; 3514 } 3515 3516 /* 3517 * The disk is not new, we did not find any actual active partition, 3518 * or the one we found was not supported, or any possible other candidate 3519 * is not supported. We then use the alternative partition if specified. 3520 */ 3521 if (AlternativePart) 3522 { 3523 DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n"); 3524 CandidatePartition = AlternativePart; 3525 goto UseAlternativePartition; 3526 } 3527 else 3528 { 3529 NoSystemPartition: 3530 DPRINT1("No valid or supported system partition has been found on this system!\n"); 3531 return NULL; 3532 } 3533 3534 UseAlternativePartition: 3535 /* 3536 * We are here because we did not find any (active) candidate system 3537 * partition that we know how to support. What we are going to do is 3538 * to change the existing system partition and use the alternative partition 3539 * (e.g. on which we install ReactOS) as the new system partition. 3540 * Then we will need to add in FreeLdr's boot menu an entry for booting 3541 * from the original system partition. 3542 */ 3543 ASSERT(CandidatePartition); 3544 3545 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n", 3546 CandidatePartition->PartitionNumber, 3547 CandidatePartition->DiskEntry->DiskNumber, 3548 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3549 3550 /* Return the candidate system partition */ 3551 return CandidatePartition; 3552 } 3553 3554 BOOLEAN 3555 SetActivePartition( 3556 IN PPARTLIST List, 3557 IN PPARTENTRY PartEntry, 3558 IN PPARTENTRY OldActivePart OPTIONAL) 3559 { 3560 /* Check for empty disk list */ 3561 if (IsListEmpty(&List->DiskListHead)) 3562 return FALSE; 3563 3564 /* Validate the partition entry */ 3565 if (!PartEntry) 3566 return FALSE; 3567 3568 /* 3569 * If the partition entry is already the system partition, or if it is 3570 * the same as the old active partition hint the user provided (and if 3571 * it is already active), just return success. 3572 */ 3573 if ((PartEntry == List->SystemPartition) || 3574 ((PartEntry == OldActivePart) && IsPartitionActive(OldActivePart))) 3575 { 3576 return TRUE; 3577 } 3578 3579 ASSERT(PartEntry->DiskEntry); 3580 3581 /* Ensure that the partition's disk is in the list */ 3582 ASSERT(PartEntry->DiskEntry->PartList == List); 3583 3584 /* 3585 * If the user provided an old active partition hint, verify that it is 3586 * indeeed active and belongs to the same disk where the new partition 3587 * belongs. Otherwise determine the current active partition on the disk 3588 * where the new partition belongs. 3589 */ 3590 if (!(OldActivePart && IsPartitionActive(OldActivePart) && (OldActivePart->DiskEntry == PartEntry->DiskEntry))) 3591 { 3592 /* It's not, determine the current active partition for the disk */ 3593 OldActivePart = GetActiveDiskPartition(PartEntry->DiskEntry); 3594 } 3595 3596 /* Unset the old active partition if it exists */ 3597 if (OldActivePart) 3598 { 3599 OldActivePart->BootIndicator = FALSE; 3600 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].BootIndicator = FALSE; 3601 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].RewritePartition = TRUE; 3602 OldActivePart->DiskEntry->Dirty = TRUE; 3603 } 3604 3605 /* Modify the system partition if the new partition is on the system disk */ 3606 if (PartEntry->DiskEntry == GetSystemDisk(List)) 3607 List->SystemPartition = PartEntry; 3608 3609 /* Set the new active partition */ 3610 PartEntry->BootIndicator = TRUE; 3611 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE; 3612 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; 3613 PartEntry->DiskEntry->Dirty = TRUE; 3614 3615 return TRUE; 3616 } 3617 3618 NTSTATUS 3619 WritePartitions( 3620 IN PDISKENTRY DiskEntry) 3621 { 3622 NTSTATUS Status; 3623 OBJECT_ATTRIBUTES ObjectAttributes; 3624 UNICODE_STRING Name; 3625 HANDLE FileHandle; 3626 IO_STATUS_BLOCK Iosb; 3627 ULONG BufferSize; 3628 PPARTITION_INFORMATION PartitionInfo; 3629 ULONG PartitionCount; 3630 PLIST_ENTRY ListEntry; 3631 PPARTENTRY PartEntry; 3632 WCHAR DstPath[MAX_PATH]; 3633 3634 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber); 3635 3636 /* If the disk is not dirty, there is nothing to do */ 3637 if (!DiskEntry->Dirty) 3638 return STATUS_SUCCESS; 3639 3640 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath), 3641 L"\\Device\\Harddisk%lu\\Partition0", 3642 DiskEntry->DiskNumber); 3643 RtlInitUnicodeString(&Name, DstPath); 3644 3645 InitializeObjectAttributes(&ObjectAttributes, 3646 &Name, 3647 OBJ_CASE_INSENSITIVE, 3648 NULL, 3649 NULL); 3650 3651 Status = NtOpenFile(&FileHandle, 3652 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 3653 &ObjectAttributes, 3654 &Iosb, 3655 0, 3656 FILE_SYNCHRONOUS_IO_NONALERT); 3657 if (!NT_SUCCESS(Status)) 3658 { 3659 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); 3660 return Status; 3661 } 3662 3663 #ifdef DUMP_PARTITION_TABLE 3664 DumpPartitionTable(DiskEntry); 3665 #endif 3666 3667 // 3668 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize 3669 // the disk in MBR or GPT format in case the disk was not initialized!! 3670 // For this we must ask the user which format to use. 3671 // 3672 3673 /* Save the original partition count to be restored later (see comment below) */ 3674 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 3675 3676 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */ 3677 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 3678 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION)); 3679 Status = NtDeviceIoControlFile(FileHandle, 3680 NULL, 3681 NULL, 3682 NULL, 3683 &Iosb, 3684 IOCTL_DISK_SET_DRIVE_LAYOUT, 3685 DiskEntry->LayoutBuffer, 3686 BufferSize, 3687 DiskEntry->LayoutBuffer, 3688 BufferSize); 3689 NtClose(FileHandle); 3690 3691 /* 3692 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts 3693 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count, 3694 * where such a table is expected to enumerate up to 4 partitions: 3695 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 . 3696 * Due to this we need to restore the original PartitionCount number. 3697 */ 3698 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount; 3699 3700 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */ 3701 if (!NT_SUCCESS(Status)) 3702 { 3703 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status); 3704 return Status; 3705 } 3706 3707 #ifdef DUMP_PARTITION_TABLE 3708 DumpPartitionTable(DiskEntry); 3709 #endif 3710 3711 /* Update the partition numbers */ 3712 3713 /* Update the primary partition table */ 3714 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3715 ListEntry != &DiskEntry->PrimaryPartListHead; 3716 ListEntry = ListEntry->Flink) 3717 { 3718 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3719 3720 if (PartEntry->IsPartitioned) 3721 { 3722 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3723 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 3724 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 3725 } 3726 } 3727 3728 /* Update the logical partition table */ 3729 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 3730 ListEntry != &DiskEntry->LogicalPartListHead; 3731 ListEntry = ListEntry->Flink) 3732 { 3733 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3734 3735 if (PartEntry->IsPartitioned) 3736 { 3737 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3738 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 3739 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 3740 } 3741 } 3742 3743 // 3744 // NOTE: Originally (see r40437), we used to install here also a new MBR 3745 // for this disk (by calling InstallMbrBootCodeToDisk), only if: 3746 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0. 3747 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set 3748 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk 3749 // was called too, the installation test was modified by checking whether 3750 // DiskEntry->NoMbr was TRUE (instead of NewDisk). 3751 // 3752 3753 // HACK: Parts of FIXMEs described above: (Re)set the PartitionStyle to MBR. 3754 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 3755 3756 /* The layout has been successfully updated, the disk is not dirty anymore */ 3757 DiskEntry->Dirty = FALSE; 3758 3759 return Status; 3760 } 3761 3762 BOOLEAN 3763 WritePartitionsToDisk( 3764 IN PPARTLIST List) 3765 { 3766 NTSTATUS Status; 3767 PLIST_ENTRY Entry; 3768 PDISKENTRY DiskEntry; 3769 3770 if (List == NULL) 3771 return TRUE; 3772 3773 for (Entry = List->DiskListHead.Flink; 3774 Entry != &List->DiskListHead; 3775 Entry = Entry->Flink) 3776 { 3777 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 3778 3779 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3780 { 3781 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3782 continue; 3783 } 3784 3785 if (DiskEntry->Dirty != FALSE) 3786 { 3787 Status = WritePartitions(DiskEntry); 3788 if (!NT_SUCCESS(Status)) 3789 { 3790 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n", 3791 DiskEntry->DiskNumber, Status); 3792 } 3793 } 3794 } 3795 3796 return TRUE; 3797 } 3798 3799 BOOLEAN 3800 SetMountedDeviceValue( 3801 IN WCHAR Letter, 3802 IN ULONG Signature, 3803 IN LARGE_INTEGER StartingOffset) 3804 { 3805 NTSTATUS Status; 3806 OBJECT_ATTRIBUTES ObjectAttributes; 3807 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices"); 3808 UNICODE_STRING ValueName; 3809 WCHAR ValueNameBuffer[16]; 3810 HANDLE KeyHandle; 3811 REG_DISK_MOUNT_INFO MountInfo; 3812 3813 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer), 3814 L"\\DosDevices\\%c:", Letter); 3815 RtlInitUnicodeString(&ValueName, ValueNameBuffer); 3816 3817 InitializeObjectAttributes(&ObjectAttributes, 3818 &KeyName, 3819 OBJ_CASE_INSENSITIVE, 3820 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 3821 NULL); 3822 3823 Status = NtOpenKey(&KeyHandle, 3824 KEY_ALL_ACCESS, 3825 &ObjectAttributes); 3826 if (!NT_SUCCESS(Status)) 3827 { 3828 Status = NtCreateKey(&KeyHandle, 3829 KEY_ALL_ACCESS, 3830 &ObjectAttributes, 3831 0, 3832 NULL, 3833 REG_OPTION_NON_VOLATILE, 3834 NULL); 3835 } 3836 if (!NT_SUCCESS(Status)) 3837 { 3838 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 3839 return FALSE; 3840 } 3841 3842 MountInfo.Signature = Signature; 3843 MountInfo.StartingOffset = StartingOffset; 3844 Status = NtSetValueKey(KeyHandle, 3845 &ValueName, 3846 0, 3847 REG_BINARY, 3848 (PVOID)&MountInfo, 3849 sizeof(MountInfo)); 3850 NtClose(KeyHandle); 3851 if (!NT_SUCCESS(Status)) 3852 { 3853 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 3854 return FALSE; 3855 } 3856 3857 return TRUE; 3858 } 3859 3860 BOOLEAN 3861 SetMountedDeviceValues( 3862 IN PPARTLIST List) 3863 { 3864 PLIST_ENTRY Entry1, Entry2; 3865 PDISKENTRY DiskEntry; 3866 PPARTENTRY PartEntry; 3867 LARGE_INTEGER StartingOffset; 3868 3869 if (List == NULL) 3870 return FALSE; 3871 3872 for (Entry1 = List->DiskListHead.Flink; 3873 Entry1 != &List->DiskListHead; 3874 Entry1 = Entry1->Flink) 3875 { 3876 DiskEntry = CONTAINING_RECORD(Entry1, 3877 DISKENTRY, 3878 ListEntry); 3879 3880 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3881 { 3882 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3883 continue; 3884 } 3885 3886 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 3887 Entry2 != &DiskEntry->PrimaryPartListHead; 3888 Entry2 = Entry2->Flink) 3889 { 3890 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 3891 if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType) 3892 { 3893 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3894 3895 /* Assign a "\DosDevices\#:" mount point to this partition */ 3896 if (PartEntry->DriveLetter) 3897 { 3898 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 3899 if (!SetMountedDeviceValue(PartEntry->DriveLetter, 3900 DiskEntry->LayoutBuffer->Signature, 3901 StartingOffset)) 3902 { 3903 return FALSE; 3904 } 3905 } 3906 } 3907 } 3908 3909 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 3910 Entry2 != &DiskEntry->LogicalPartListHead; 3911 Entry2 = Entry2->Flink) 3912 { 3913 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 3914 if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType) 3915 { 3916 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3917 3918 /* Assign a "\DosDevices\#:" mount point to this partition */ 3919 if (PartEntry->DriveLetter) 3920 { 3921 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 3922 if (!SetMountedDeviceValue(PartEntry->DriveLetter, 3923 DiskEntry->LayoutBuffer->Signature, 3924 StartingOffset)) 3925 { 3926 return FALSE; 3927 } 3928 } 3929 } 3930 } 3931 } 3932 3933 return TRUE; 3934 } 3935 3936 VOID 3937 SetMBRPartitionType( 3938 IN PPARTENTRY PartEntry, 3939 IN UCHAR PartitionType) 3940 { 3941 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 3942 3943 ASSERT(DiskEntry->DiskStyle == PARTITION_STYLE_MBR); 3944 3945 PartEntry->PartitionType = PartitionType; 3946 3947 DiskEntry->Dirty = TRUE; 3948 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType; 3949 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType); 3950 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; 3951 } 3952 3953 ERROR_NUMBER 3954 PrimaryPartitionCreationChecks( 3955 IN PPARTENTRY PartEntry) 3956 { 3957 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 3958 3959 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3960 { 3961 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3962 return ERROR_WARN_PARTITION; 3963 } 3964 3965 /* Fail if the partition is already in use */ 3966 if (PartEntry->IsPartitioned) 3967 return ERROR_NEW_PARTITION; 3968 3969 /* Only one primary partition is allowed on super-floppy */ 3970 if (IsSuperFloppy(DiskEntry)) 3971 return ERROR_PARTITION_TABLE_FULL; 3972 3973 /* Fail if there are already 4 primary partitions in the list */ 3974 if (GetPrimaryPartitionCount(DiskEntry) >= 4) 3975 return ERROR_PARTITION_TABLE_FULL; 3976 3977 return ERROR_SUCCESS; 3978 } 3979 3980 ERROR_NUMBER 3981 ExtendedPartitionCreationChecks( 3982 IN PPARTENTRY PartEntry) 3983 { 3984 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 3985 3986 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3987 { 3988 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3989 return ERROR_WARN_PARTITION; 3990 } 3991 3992 /* Fail if the partition is already in use */ 3993 if (PartEntry->IsPartitioned) 3994 return ERROR_NEW_PARTITION; 3995 3996 /* Only one primary partition is allowed on super-floppy */ 3997 if (IsSuperFloppy(DiskEntry)) 3998 return ERROR_PARTITION_TABLE_FULL; 3999 4000 /* Fail if there are already 4 primary partitions in the list */ 4001 if (GetPrimaryPartitionCount(DiskEntry) >= 4) 4002 return ERROR_PARTITION_TABLE_FULL; 4003 4004 /* Fail if there is another extended partition in the list */ 4005 if (DiskEntry->ExtendedPartition != NULL) 4006 return ERROR_ONLY_ONE_EXTENDED; 4007 4008 return ERROR_SUCCESS; 4009 } 4010 4011 ERROR_NUMBER 4012 LogicalPartitionCreationChecks( 4013 IN PPARTENTRY PartEntry) 4014 { 4015 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 4016 4017 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 4018 { 4019 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 4020 return ERROR_WARN_PARTITION; 4021 } 4022 4023 /* Fail if the partition is already in use */ 4024 if (PartEntry->IsPartitioned) 4025 return ERROR_NEW_PARTITION; 4026 4027 /* Only one primary partition is allowed on super-floppy */ 4028 if (IsSuperFloppy(DiskEntry)) 4029 return ERROR_PARTITION_TABLE_FULL; 4030 4031 return ERROR_SUCCESS; 4032 } 4033 4034 BOOLEAN 4035 GetNextUnformattedPartition( 4036 IN PPARTLIST List, 4037 OUT PDISKENTRY *pDiskEntry OPTIONAL, 4038 OUT PPARTENTRY *pPartEntry) 4039 { 4040 PLIST_ENTRY Entry1, Entry2; 4041 PDISKENTRY DiskEntry; 4042 PPARTENTRY PartEntry; 4043 4044 for (Entry1 = List->DiskListHead.Flink; 4045 Entry1 != &List->DiskListHead; 4046 Entry1 = Entry1->Flink) 4047 { 4048 DiskEntry = CONTAINING_RECORD(Entry1, 4049 DISKENTRY, 4050 ListEntry); 4051 4052 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 4053 { 4054 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 4055 continue; 4056 } 4057 4058 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 4059 Entry2 != &DiskEntry->PrimaryPartListHead; 4060 Entry2 = Entry2->Flink) 4061 { 4062 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 4063 if (PartEntry->IsPartitioned && PartEntry->New) 4064 { 4065 ASSERT(DiskEntry == PartEntry->DiskEntry); 4066 if (pDiskEntry) *pDiskEntry = DiskEntry; 4067 *pPartEntry = PartEntry; 4068 return TRUE; 4069 } 4070 } 4071 4072 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 4073 Entry2 != &DiskEntry->LogicalPartListHead; 4074 Entry2 = Entry2->Flink) 4075 { 4076 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 4077 if (PartEntry->IsPartitioned && PartEntry->New) 4078 { 4079 ASSERT(DiskEntry == PartEntry->DiskEntry); 4080 if (pDiskEntry) *pDiskEntry = DiskEntry; 4081 *pPartEntry = PartEntry; 4082 return TRUE; 4083 } 4084 } 4085 } 4086 4087 if (pDiskEntry) *pDiskEntry = NULL; 4088 *pPartEntry = NULL; 4089 4090 return FALSE; 4091 } 4092 4093 BOOLEAN 4094 GetNextUncheckedPartition( 4095 IN PPARTLIST List, 4096 OUT PDISKENTRY *pDiskEntry OPTIONAL, 4097 OUT PPARTENTRY *pPartEntry) 4098 { 4099 PLIST_ENTRY Entry1, Entry2; 4100 PDISKENTRY DiskEntry; 4101 PPARTENTRY PartEntry; 4102 4103 for (Entry1 = List->DiskListHead.Flink; 4104 Entry1 != &List->DiskListHead; 4105 Entry1 = Entry1->Flink) 4106 { 4107 DiskEntry = CONTAINING_RECORD(Entry1, 4108 DISKENTRY, 4109 ListEntry); 4110 4111 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 4112 { 4113 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 4114 continue; 4115 } 4116 4117 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 4118 Entry2 != &DiskEntry->PrimaryPartListHead; 4119 Entry2 = Entry2->Flink) 4120 { 4121 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 4122 if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) 4123 { 4124 ASSERT(DiskEntry == PartEntry->DiskEntry); 4125 if (pDiskEntry) *pDiskEntry = DiskEntry; 4126 *pPartEntry = PartEntry; 4127 return TRUE; 4128 } 4129 } 4130 4131 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 4132 Entry2 != &DiskEntry->LogicalPartListHead; 4133 Entry2 = Entry2->Flink) 4134 { 4135 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 4136 if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) 4137 { 4138 ASSERT(DiskEntry == PartEntry->DiskEntry); 4139 if (pDiskEntry) *pDiskEntry = DiskEntry; 4140 *pPartEntry = PartEntry; 4141 return TRUE; 4142 } 4143 } 4144 } 4145 4146 if (pDiskEntry) *pDiskEntry = NULL; 4147 *pPartEntry = NULL; 4148 4149 return FALSE; 4150 } 4151 4152 /* EOF */ 4153