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 = GetDiskSizeInBytes(DiskEntry); 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 VOID 678 AddLogicalDiskSpace( 679 _In_ PDISKENTRY DiskEntry) 680 { 681 ULONGLONG StartSector; 682 ULONGLONG SectorCount; 683 PPARTENTRY NewPartEntry; 684 685 DPRINT("AddLogicalDiskSpace()\n"); 686 687 /* Create a partition entry that represents the empty space in the container partition */ 688 689 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 690 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 691 692 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 693 &DiskEntry->LogicalPartListHead, 694 StartSector, 695 SectorCount, 696 TRUE); 697 if (!NewPartEntry) 698 DPRINT1("Failed to create a new empty region for full extended partition space!\n"); 699 } 700 701 // TODO: Improve upon the PartitionInfo parameter later 702 // (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example) 703 // So far we only use it as the optional type of the partition to create. 704 // 705 // See also CreatePartition(). 706 static 707 BOOLEAN 708 InitializePartitionEntry( 709 _Inout_ PPARTENTRY PartEntry, 710 _In_opt_ ULONGLONG SizeBytes, 711 _In_opt_ ULONG_PTR PartitionInfo) 712 { 713 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 714 ULONGLONG SectorCount; 715 BOOLEAN isContainer = IsContainerPartition((UCHAR)PartitionInfo); 716 717 DPRINT1("Current entry sector count: %I64u\n", PartEntry->SectorCount.QuadPart); 718 719 /* The entry must not be already partitioned and not be void */ 720 ASSERT(!PartEntry->IsPartitioned); 721 ASSERT(PartEntry->SectorCount.QuadPart); 722 723 /* Either we create a primary/logical partition, or we create an 724 * extended partition but the entry must not be logical space */ 725 ASSERT(!isContainer || !PartEntry->LogicalPartition); 726 727 /* Convert the size in bytes to sector count. SizeBytes being 728 * zero means the caller wants to use all the empty space. */ 729 if ((SizeBytes == 0) || (SizeBytes == GetPartEntrySizeInBytes(PartEntry))) 730 { 731 /* Use all of the unpartitioned disk space */ 732 SectorCount = PartEntry->SectorCount.QuadPart; 733 } 734 else 735 { 736 SectorCount = SizeBytes / DiskEntry->BytesPerSector; 737 if (SectorCount == 0) 738 { 739 /* SizeBytes was certainly less than the minimal size, so fail */ 740 DPRINT1("Partition size %I64u too small\n", SizeBytes); 741 return FALSE; 742 } 743 } 744 DPRINT1(" New sector count: %I64u\n", SectorCount); 745 746 /* Fail if we request more sectors than what the entry actually contains */ 747 if (SectorCount > PartEntry->SectorCount.QuadPart) 748 return FALSE; 749 750 if ((SectorCount == 0) || 751 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - 752 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)) 753 { 754 /* Reuse the whole current entry */ 755 } 756 else 757 { 758 ULONGLONG StartSector; 759 ULONGLONG SectorCount2; 760 PPARTENTRY NewPartEntry; 761 762 /* Create a partition entry that represents the remaining space 763 * after the partition to be initialized */ 764 765 StartSector = AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment); 766 SectorCount2 = PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - StartSector; 767 768 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 769 PartEntry->ListEntry.Flink, 770 StartSector, 771 SectorCount2, 772 PartEntry->LogicalPartition); 773 if (!NewPartEntry) 774 { 775 DPRINT1("Failed to create a new empty region for disk space!\n"); 776 return FALSE; 777 } 778 779 /* Resize down the partition entry; its StartSector remains the same */ 780 PartEntry->SectorCount.QuadPart = StartSector - PartEntry->StartSector.QuadPart; 781 } 782 783 /* Convert the partition entry to 'New (Unformatted)' */ 784 PartEntry->New = TRUE; 785 PartEntry->IsPartitioned = TRUE; 786 787 PartEntry->BootIndicator = FALSE; 788 if (PartitionInfo) 789 { 790 if (!isContainer) 791 { 792 PartEntry->PartitionType = (UCHAR)PartitionInfo; 793 } 794 else 795 { 796 /* Set the correct extended container partition type, 797 * depending on whether it is contained below or above 798 * the 1024-cylinder (usually 8.4GB/7.8GiB) boundary: 799 * - below: INT13h CHS partition; 800 * - above: Extended INT13h LBA partition. */ 801 if ((PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1) 802 / (DiskEntry->TracksPerCylinder * DiskEntry->SectorsPerTrack) < 1024) 803 { 804 PartEntry->PartitionType = PARTITION_EXTENDED; 805 } 806 else 807 { 808 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED; 809 } 810 } 811 } 812 else 813 { 814 // FIXME: Use FileSystemToMBRPartitionType() only for MBR, otherwise use PARTITION_BASIC_DATA_GUID. 815 ASSERT(!isContainer); 816 PartEntry->PartitionType = FileSystemToMBRPartitionType(L"RAW", 817 PartEntry->StartSector.QuadPart, 818 PartEntry->SectorCount.QuadPart); 819 } 820 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 821 822 PartEntry->FormatState = Unformatted; 823 PartEntry->FileSystem[0] = L'\0'; 824 825 if (isContainer) 826 { 827 DiskEntry->ExtendedPartition = PartEntry; 828 AddLogicalDiskSpace(DiskEntry); 829 } 830 831 DPRINT1("First Sector : %I64u\n", PartEntry->StartSector.QuadPart); 832 DPRINT1("Last Sector : %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1); 833 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart); 834 835 return TRUE; 836 } 837 838 839 static 840 VOID 841 AddPartitionToDisk( 842 IN ULONG DiskNumber, 843 IN PDISKENTRY DiskEntry, 844 IN ULONG PartitionIndex, 845 IN BOOLEAN LogicalPartition) 846 { 847 NTSTATUS Status; 848 PPARTITION_INFORMATION PartitionInfo; 849 PPARTENTRY PartEntry; 850 HANDLE PartitionHandle; 851 OBJECT_ATTRIBUTES ObjectAttributes; 852 IO_STATUS_BLOCK IoStatusBlock; 853 WCHAR PathBuffer[MAX_PATH]; 854 UNICODE_STRING Name; 855 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)]; 856 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer; 857 858 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 859 860 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED || 861 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType))) 862 { 863 return; 864 } 865 866 PartEntry = RtlAllocateHeap(ProcessHeap, 867 HEAP_ZERO_MEMORY, 868 sizeof(PARTENTRY)); 869 if (PartEntry == NULL) 870 return; 871 872 PartEntry->DiskEntry = DiskEntry; 873 874 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 875 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 876 877 PartEntry->BootIndicator = PartitionInfo->BootIndicator; 878 PartEntry->PartitionType = PartitionInfo->PartitionType; 879 880 PartEntry->LogicalPartition = LogicalPartition; 881 PartEntry->IsPartitioned = TRUE; 882 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber; 883 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 884 PartEntry->PartitionIndex = PartitionIndex; 885 886 /* Specify the partition as initially unformatted */ 887 PartEntry->FormatState = Unformatted; 888 PartEntry->FileSystem[0] = L'\0'; 889 890 /* Initialize the partition volume label */ 891 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel)); 892 893 if (IsContainerPartition(PartEntry->PartitionType)) 894 { 895 PartEntry->FormatState = Unformatted; 896 897 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL) 898 DiskEntry->ExtendedPartition = PartEntry; 899 } 900 else if (IsRecognizedPartition(PartEntry->PartitionType)) 901 { 902 ASSERT(PartitionInfo->RecognizedPartition); 903 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 904 905 /* Try to open the volume so as to mount it */ 906 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 907 L"\\Device\\Harddisk%lu\\Partition%lu", 908 DiskEntry->DiskNumber, 909 PartEntry->PartitionNumber); 910 RtlInitUnicodeString(&Name, PathBuffer); 911 912 InitializeObjectAttributes(&ObjectAttributes, 913 &Name, 914 OBJ_CASE_INSENSITIVE, 915 NULL, 916 NULL); 917 918 PartitionHandle = NULL; 919 Status = NtOpenFile(&PartitionHandle, 920 FILE_READ_DATA | SYNCHRONIZE, 921 &ObjectAttributes, 922 &IoStatusBlock, 923 FILE_SHARE_READ | FILE_SHARE_WRITE, 924 FILE_SYNCHRONOUS_IO_NONALERT); 925 if (!NT_SUCCESS(Status)) 926 { 927 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status); 928 } 929 930 if (PartitionHandle) 931 { 932 ASSERT(NT_SUCCESS(Status)); 933 934 /* We don't have a FS, try to guess one */ 935 Status = InferFileSystem(NULL, PartitionHandle, 936 PartEntry->FileSystem, 937 sizeof(PartEntry->FileSystem)); 938 if (!NT_SUCCESS(Status)) 939 DPRINT1("InferFileSystem() failed, Status 0x%08lx\n", Status); 940 } 941 if (*PartEntry->FileSystem) 942 { 943 ASSERT(PartitionHandle); 944 945 /* 946 * Handle partition mounted with RawFS: it is 947 * either unformatted or has an unknown format. 948 */ 949 if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0) 950 { 951 /* 952 * True unformatted partitions on NT are created with their 953 * partition type set to either one of the following values, 954 * and are mounted with RawFS. This is done this way since we 955 * are assured to have FAT support, which is the only FS that 956 * uses these partition types. Therefore, having a partition 957 * mounted with RawFS and with these partition types means that 958 * the FAT FS was unable to mount it beforehand and thus the 959 * partition is unformatted. 960 * However, any partition mounted by RawFS that does NOT have 961 * any of these partition types must be considered as having 962 * an unknown format. 963 */ 964 if (PartEntry->PartitionType == PARTITION_FAT_12 || 965 PartEntry->PartitionType == PARTITION_FAT_16 || 966 PartEntry->PartitionType == PARTITION_HUGE || 967 PartEntry->PartitionType == PARTITION_XINT13 || 968 PartEntry->PartitionType == PARTITION_FAT32 || 969 PartEntry->PartitionType == PARTITION_FAT32_XINT13) 970 { 971 PartEntry->FormatState = Unformatted; 972 } 973 else 974 { 975 /* Close the partition before dismounting */ 976 NtClose(PartitionHandle); 977 PartitionHandle = NULL; 978 /* 979 * Dismount the partition since RawFS owns it, and set its 980 * format to unknown (may or may not be actually formatted). 981 */ 982 DismountVolume(PartEntry); 983 PartEntry->FormatState = UnknownFormat; 984 PartEntry->FileSystem[0] = L'\0'; 985 } 986 } 987 else 988 { 989 PartEntry->FormatState = Preformatted; 990 } 991 } 992 else 993 { 994 PartEntry->FormatState = UnknownFormat; 995 } 996 997 /* Retrieve the partition volume label */ 998 if (PartitionHandle) 999 { 1000 Status = NtQueryVolumeInformationFile(PartitionHandle, 1001 &IoStatusBlock, 1002 &LabelBuffer, 1003 sizeof(LabelBuffer), 1004 FileFsVolumeInformation); 1005 if (NT_SUCCESS(Status)) 1006 { 1007 /* Copy the (possibly truncated) volume label and NULL-terminate it */ 1008 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel), 1009 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength); 1010 } 1011 else 1012 { 1013 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status); 1014 } 1015 } 1016 1017 /* Close the partition */ 1018 if (PartitionHandle) 1019 NtClose(PartitionHandle); 1020 } 1021 else 1022 { 1023 /* Unknown partition, hence unknown format (may or may not be actually formatted) */ 1024 PartEntry->FormatState = UnknownFormat; 1025 } 1026 1027 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition); 1028 } 1029 1030 static 1031 VOID 1032 ScanForUnpartitionedDiskSpace( 1033 IN PDISKENTRY DiskEntry) 1034 { 1035 ULONGLONG StartSector; 1036 ULONGLONG SectorCount; 1037 ULONGLONG LastStartSector; 1038 ULONGLONG LastSectorCount; 1039 ULONGLONG LastUnusedSectorCount; 1040 PPARTENTRY PartEntry; 1041 PPARTENTRY NewPartEntry; 1042 PLIST_ENTRY Entry; 1043 1044 DPRINT("ScanForUnpartitionedDiskSpace()\n"); 1045 1046 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1047 { 1048 DPRINT1("No primary partition!\n"); 1049 1050 /* Create a partition entry that represents the empty disk */ 1051 1052 if (DiskEntry->SectorAlignment < 2048) 1053 StartSector = 2048ULL; 1054 else 1055 StartSector = (ULONGLONG)DiskEntry->SectorAlignment; 1056 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector; 1057 1058 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1059 &DiskEntry->PrimaryPartListHead, 1060 StartSector, 1061 SectorCount, 1062 FALSE); 1063 if (!NewPartEntry) 1064 DPRINT1("Failed to create a new empty region for full disk space!\n"); 1065 1066 return; 1067 } 1068 1069 /* Start partition at head 1, cylinder 0 */ 1070 if (DiskEntry->SectorAlignment < 2048) 1071 LastStartSector = 2048ULL; 1072 else 1073 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment; 1074 LastSectorCount = 0ULL; 1075 LastUnusedSectorCount = 0ULL; 1076 1077 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 1078 Entry != &DiskEntry->PrimaryPartListHead; 1079 Entry = Entry->Flink) 1080 { 1081 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1082 1083 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 1084 PartEntry->SectorCount.QuadPart != 0ULL) 1085 { 1086 LastUnusedSectorCount = 1087 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 1088 1089 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 1090 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1091 { 1092 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 1093 1094 StartSector = LastStartSector + LastSectorCount; 1095 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1096 1097 /* Insert the table into the list */ 1098 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1099 &PartEntry->ListEntry, 1100 StartSector, 1101 SectorCount, 1102 FALSE); 1103 if (!NewPartEntry) 1104 { 1105 DPRINT1("Failed to create a new empty region for disk space!\n"); 1106 return; 1107 } 1108 } 1109 1110 LastStartSector = PartEntry->StartSector.QuadPart; 1111 LastSectorCount = PartEntry->SectorCount.QuadPart; 1112 } 1113 } 1114 1115 /* Check for trailing unpartitioned disk space */ 1116 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart) 1117 { 1118 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 1119 1120 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1121 { 1122 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 1123 1124 StartSector = LastStartSector + LastSectorCount; 1125 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1126 1127 /* Append the table to the list */ 1128 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1129 &DiskEntry->PrimaryPartListHead, 1130 StartSector, 1131 SectorCount, 1132 FALSE); 1133 if (!NewPartEntry) 1134 { 1135 DPRINT1("Failed to create a new empty region for trailing disk space!\n"); 1136 return; 1137 } 1138 } 1139 } 1140 1141 if (DiskEntry->ExtendedPartition != NULL) 1142 { 1143 if (IsListEmpty(&DiskEntry->LogicalPartListHead)) 1144 { 1145 DPRINT1("No logical partition!\n"); 1146 1147 /* Create a partition entry that represents the empty extended partition */ 1148 AddLogicalDiskSpace(DiskEntry); 1149 return; 1150 } 1151 1152 /* Start partition at head 1, cylinder 0 */ 1153 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 1154 LastSectorCount = 0ULL; 1155 LastUnusedSectorCount = 0ULL; 1156 1157 for (Entry = DiskEntry->LogicalPartListHead.Flink; 1158 Entry != &DiskEntry->LogicalPartListHead; 1159 Entry = Entry->Flink) 1160 { 1161 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1162 1163 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 1164 PartEntry->SectorCount.QuadPart != 0ULL) 1165 { 1166 LastUnusedSectorCount = 1167 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount); 1168 1169 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) && 1170 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1171 { 1172 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 1173 1174 StartSector = LastStartSector + LastSectorCount; 1175 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1176 1177 /* Insert the table into the list */ 1178 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1179 &PartEntry->ListEntry, 1180 StartSector, 1181 SectorCount, 1182 TRUE); 1183 if (!NewPartEntry) 1184 { 1185 DPRINT1("Failed to create a new empty region for extended partition space!\n"); 1186 return; 1187 } 1188 } 1189 1190 LastStartSector = PartEntry->StartSector.QuadPart; 1191 LastSectorCount = PartEntry->SectorCount.QuadPart; 1192 } 1193 } 1194 1195 /* Check for trailing unpartitioned disk space */ 1196 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart) 1197 { 1198 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + 1199 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), 1200 DiskEntry->SectorAlignment); 1201 1202 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1203 { 1204 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 1205 1206 StartSector = LastStartSector + LastSectorCount; 1207 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector; 1208 1209 /* Append the table to the list */ 1210 NewPartEntry = CreateInsertBlankRegion(DiskEntry, 1211 &DiskEntry->LogicalPartListHead, 1212 StartSector, 1213 SectorCount, 1214 TRUE); 1215 if (!NewPartEntry) 1216 { 1217 DPRINT1("Failed to create a new empty region for extended partition space!\n"); 1218 return; 1219 } 1220 } 1221 } 1222 } 1223 1224 DPRINT("ScanForUnpartitionedDiskSpace() done\n"); 1225 } 1226 1227 static 1228 VOID 1229 SetDiskSignature( 1230 IN PPARTLIST List, 1231 IN PDISKENTRY DiskEntry) 1232 { 1233 LARGE_INTEGER SystemTime; 1234 TIME_FIELDS TimeFields; 1235 PLIST_ENTRY Entry2; 1236 PDISKENTRY DiskEntry2; 1237 PUCHAR Buffer; 1238 1239 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1240 { 1241 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1242 return; 1243 } 1244 1245 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature; 1246 1247 while (TRUE) 1248 { 1249 NtQuerySystemTime(&SystemTime); 1250 RtlTimeToTimeFields(&SystemTime, &TimeFields); 1251 1252 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF); 1253 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF); 1254 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF); 1255 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF); 1256 1257 if (DiskEntry->LayoutBuffer->Signature == 0) 1258 { 1259 continue; 1260 } 1261 1262 /* Check if the signature already exist */ 1263 /* FIXME: 1264 * Check also signatures from disks, which are 1265 * not visible (bootable) by the bios. 1266 */ 1267 for (Entry2 = List->DiskListHead.Flink; 1268 Entry2 != &List->DiskListHead; 1269 Entry2 = Entry2->Flink) 1270 { 1271 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry); 1272 1273 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT) 1274 { 1275 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1276 continue; 1277 } 1278 1279 if (DiskEntry != DiskEntry2 && 1280 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature) 1281 break; 1282 } 1283 1284 if (Entry2 == &List->DiskListHead) 1285 break; 1286 } 1287 } 1288 1289 static 1290 VOID 1291 UpdateDiskSignatures( 1292 IN PPARTLIST List) 1293 { 1294 PLIST_ENTRY Entry; 1295 PDISKENTRY DiskEntry; 1296 1297 /* Update each disk */ 1298 for (Entry = List->DiskListHead.Flink; 1299 Entry != &List->DiskListHead; 1300 Entry = Entry->Flink) 1301 { 1302 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1303 1304 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1305 { 1306 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1307 continue; 1308 } 1309 1310 if (DiskEntry->LayoutBuffer && 1311 DiskEntry->LayoutBuffer->Signature == 0) 1312 { 1313 SetDiskSignature(List, DiskEntry); 1314 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE; 1315 } 1316 } 1317 } 1318 1319 static 1320 VOID 1321 UpdateHwDiskNumbers( 1322 IN PPARTLIST List) 1323 { 1324 PLIST_ENTRY ListEntry; 1325 PBIOSDISKENTRY BiosDiskEntry; 1326 PDISKENTRY DiskEntry; 1327 ULONG HwAdapterNumber = 0; 1328 ULONG HwControllerNumber = 0; 1329 ULONG RemovableDiskCount = 0; 1330 1331 /* 1332 * Enumerate the disks recognized by the BIOS and recompute the disk 1333 * numbers on the system when *ALL* removable disks are not connected. 1334 * The entries are inserted in increasing order of AdapterNumber, 1335 * ControllerNumber and DiskNumber. 1336 */ 1337 for (ListEntry = List->BiosDiskListHead.Flink; 1338 ListEntry != &List->BiosDiskListHead; 1339 ListEntry = ListEntry->Flink) 1340 { 1341 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 1342 DiskEntry = BiosDiskEntry->DiskEntry; 1343 1344 /* 1345 * If the adapter or controller numbers change, update them and reset 1346 * the number of removable disks on this adapter/controller. 1347 */ 1348 if (HwAdapterNumber != BiosDiskEntry->AdapterNumber || 1349 HwControllerNumber != BiosDiskEntry->ControllerNumber) 1350 { 1351 HwAdapterNumber = BiosDiskEntry->AdapterNumber; 1352 HwControllerNumber = BiosDiskEntry->ControllerNumber; 1353 RemovableDiskCount = 0; 1354 } 1355 1356 /* Adjust the actual hardware disk number */ 1357 if (DiskEntry) 1358 { 1359 ASSERT(DiskEntry->HwDiskNumber == BiosDiskEntry->DiskNumber); 1360 1361 if (DiskEntry->MediaType == RemovableMedia) 1362 { 1363 /* Increase the number of removable disks and set the disk number to zero */ 1364 ++RemovableDiskCount; 1365 DiskEntry->HwFixedDiskNumber = 0; 1366 } 1367 else // if (DiskEntry->MediaType == FixedMedia) 1368 { 1369 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */ 1370 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber - RemovableDiskCount; 1371 } 1372 } 1373 else 1374 { 1375 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry->DiskNumber); 1376 } 1377 } 1378 } 1379 1380 static 1381 VOID 1382 AddDiskToList( 1383 IN HANDLE FileHandle, 1384 IN ULONG DiskNumber, 1385 IN PPARTLIST List) 1386 { 1387 DISK_GEOMETRY DiskGeometry; 1388 SCSI_ADDRESS ScsiAddress; 1389 PDISKENTRY DiskEntry; 1390 IO_STATUS_BLOCK Iosb; 1391 NTSTATUS Status; 1392 PPARTITION_SECTOR Mbr; 1393 PULONG Buffer; 1394 LARGE_INTEGER FileOffset; 1395 WCHAR Identifier[20]; 1396 ULONG Checksum; 1397 ULONG Signature; 1398 ULONG i; 1399 PLIST_ENTRY ListEntry; 1400 PBIOSDISKENTRY BiosDiskEntry; 1401 ULONG LayoutBufferSize; 1402 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 1403 1404 /* Retrieve the drive geometry */ 1405 Status = NtDeviceIoControlFile(FileHandle, 1406 NULL, 1407 NULL, 1408 NULL, 1409 &Iosb, 1410 IOCTL_DISK_GET_DRIVE_GEOMETRY, 1411 NULL, 1412 0, 1413 &DiskGeometry, 1414 sizeof(DiskGeometry)); 1415 if (!NT_SUCCESS(Status)) 1416 return; 1417 1418 if (DiskGeometry.MediaType != FixedMedia && 1419 DiskGeometry.MediaType != RemovableMedia) 1420 { 1421 return; 1422 } 1423 1424 /* 1425 * FIXME: Here we suppose the disk is always SCSI. What if it is 1426 * of another type? To check this we need to retrieve the name of 1427 * the driver the disk device belongs to. 1428 */ 1429 Status = NtDeviceIoControlFile(FileHandle, 1430 NULL, 1431 NULL, 1432 NULL, 1433 &Iosb, 1434 IOCTL_SCSI_GET_ADDRESS, 1435 NULL, 1436 0, 1437 &ScsiAddress, 1438 sizeof(ScsiAddress)); 1439 if (!NT_SUCCESS(Status)) 1440 return; 1441 1442 /* 1443 * Check whether the disk is initialized, by looking at its MBR. 1444 * NOTE that this must be generalized to GPT disks as well! 1445 */ 1446 1447 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap, 1448 0, 1449 DiskGeometry.BytesPerSector); 1450 if (Mbr == NULL) 1451 return; 1452 1453 FileOffset.QuadPart = 0; 1454 Status = NtReadFile(FileHandle, 1455 NULL, 1456 NULL, 1457 NULL, 1458 &Iosb, 1459 (PVOID)Mbr, 1460 DiskGeometry.BytesPerSector, 1461 &FileOffset, 1462 NULL); 1463 if (!NT_SUCCESS(Status)) 1464 { 1465 RtlFreeHeap(ProcessHeap, 0, Mbr); 1466 DPRINT1("NtReadFile failed, status=%x\n", Status); 1467 return; 1468 } 1469 Signature = Mbr->Signature; 1470 1471 /* Calculate the MBR checksum */ 1472 Checksum = 0; 1473 Buffer = (PULONG)Mbr; 1474 for (i = 0; i < 128; i++) 1475 { 1476 Checksum += Buffer[i]; 1477 } 1478 Checksum = ~Checksum + 1; 1479 1480 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier), 1481 L"%08x-%08x-%c", 1482 Checksum, Signature, 1483 (Mbr->Magic == PARTITION_MAGIC) ? L'A' : L'X'); 1484 DPRINT("Identifier: %S\n", Identifier); 1485 1486 DiskEntry = RtlAllocateHeap(ProcessHeap, 1487 HEAP_ZERO_MEMORY, 1488 sizeof(DISKENTRY)); 1489 if (DiskEntry == NULL) 1490 { 1491 RtlFreeHeap(ProcessHeap, 0, Mbr); 1492 DPRINT1("Failed to allocate a new disk entry.\n"); 1493 return; 1494 } 1495 1496 DiskEntry->PartList = List; 1497 1498 #if 0 1499 { 1500 FILE_FS_DEVICE_INFORMATION FileFsDevice; 1501 1502 /* Query the device for its type */ 1503 Status = NtQueryVolumeInformationFile(FileHandle, 1504 &Iosb, 1505 &FileFsDevice, 1506 sizeof(FileFsDevice), 1507 FileFsDeviceInformation); 1508 if (!NT_SUCCESS(Status)) 1509 { 1510 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber, Identifier); 1511 } 1512 else 1513 { 1514 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber, FileFsDevice.DeviceType, FileFsDevice.Characteristics); 1515 } 1516 } 1517 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation). 1518 #endif 1519 DiskEntry->MediaType = DiskGeometry.MediaType; 1520 if (DiskEntry->MediaType == RemovableMedia) 1521 { 1522 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber, Identifier); 1523 } 1524 else // if (DiskEntry->MediaType == FixedMedia) 1525 { 1526 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber, Identifier); 1527 } 1528 1529 // DiskEntry->Checksum = Checksum; 1530 // DiskEntry->Signature = Signature; 1531 DiskEntry->BiosFound = FALSE; 1532 1533 /* 1534 * Check if this disk has a valid MBR: verify its signature, 1535 * and whether its two first bytes are a valid instruction 1536 * (related to this, see IsThereAValidBootSector() in partlist.c). 1537 * 1538 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle(). 1539 */ 1540 1541 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000); 1542 1543 /* If we have not the 0xAA55 then it's raw partition */ 1544 if (Mbr->Magic != PARTITION_MAGIC) 1545 { 1546 DiskEntry->DiskStyle = PARTITION_STYLE_RAW; 1547 } 1548 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */ 1549 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI && 1550 Mbr->Partition[1].PartitionType == 0 && 1551 Mbr->Partition[2].PartitionType == 0 && 1552 Mbr->Partition[3].PartitionType == 0) 1553 { 1554 DiskEntry->DiskStyle = PARTITION_STYLE_GPT; 1555 } 1556 /* Otherwise, partition table is in MBR */ 1557 else 1558 { 1559 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 1560 } 1561 1562 /* Free the MBR sector buffer */ 1563 RtlFreeHeap(ProcessHeap, 0, Mbr); 1564 1565 1566 for (ListEntry = List->BiosDiskListHead.Flink; 1567 ListEntry != &List->BiosDiskListHead; 1568 ListEntry = ListEntry->Flink) 1569 { 1570 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 1571 /* FIXME: 1572 * Compare the size from bios and the reported size from driver. 1573 * If we have more than one disk with a zero or with the same signature 1574 * we must create new signatures and reboot. After the reboot, 1575 * it is possible to identify the disks. 1576 */ 1577 if (BiosDiskEntry->Signature == Signature && 1578 BiosDiskEntry->Checksum == Checksum && 1579 BiosDiskEntry->DiskEntry == NULL) 1580 { 1581 if (!DiskEntry->BiosFound) 1582 { 1583 DiskEntry->HwAdapterNumber = BiosDiskEntry->AdapterNumber; 1584 DiskEntry->HwControllerNumber = BiosDiskEntry->ControllerNumber; 1585 DiskEntry->HwDiskNumber = BiosDiskEntry->DiskNumber; 1586 1587 if (DiskEntry->MediaType == RemovableMedia) 1588 { 1589 /* Set the removable disk number to zero */ 1590 DiskEntry->HwFixedDiskNumber = 0; 1591 } 1592 else // if (DiskEntry->MediaType == FixedMedia) 1593 { 1594 /* The fixed disk number will later be adjusted using the number of removable disks */ 1595 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber; 1596 } 1597 1598 DiskEntry->BiosFound = TRUE; 1599 BiosDiskEntry->DiskEntry = DiskEntry; 1600 break; 1601 } 1602 else 1603 { 1604 // FIXME: What to do? 1605 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber, Identifier); 1606 } 1607 } 1608 } 1609 1610 if (!DiskEntry->BiosFound) 1611 { 1612 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber); 1613 } 1614 1615 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart; 1616 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder; 1617 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack; 1618 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector; 1619 1620 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders); 1621 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder); 1622 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack); 1623 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector); 1624 1625 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 1626 (ULONGLONG)DiskGeometry.TracksPerCylinder * 1627 (ULONGLONG)DiskGeometry.SectorsPerTrack; 1628 1629 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack; 1630 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder * 1631 DiskGeometry.SectorsPerTrack; 1632 1633 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart); 1634 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment); 1635 1636 DiskEntry->DiskNumber = DiskNumber; 1637 DiskEntry->Port = ScsiAddress.PortNumber; 1638 DiskEntry->Bus = ScsiAddress.PathId; 1639 DiskEntry->Id = ScsiAddress.TargetId; 1640 1641 GetDriverName(DiskEntry); 1642 /* 1643 * Actually it would be more correct somehow to use: 1644 * 1645 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo; 1646 * ULONG ReturnedLength; 1647 * 1648 * Status = NtQueryObject(SomeHandleToTheDisk, 1649 * ObjectNameInformation, 1650 * &NameInfo, 1651 * sizeof(NameInfo), 1652 * &ReturnedLength); 1653 * etc... 1654 * 1655 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267 1656 */ 1657 1658 InitializeListHead(&DiskEntry->PrimaryPartListHead); 1659 InitializeListHead(&DiskEntry->LogicalPartListHead); 1660 1661 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber); 1662 1663 1664 /* 1665 * We now retrieve the disk partition layout 1666 */ 1667 1668 /* 1669 * Stop there now if the disk is GPT-partitioned, 1670 * since we currently do not support such disks. 1671 */ 1672 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1673 { 1674 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1675 return; 1676 } 1677 1678 /* Allocate a layout buffer with 4 partition entries first */ 1679 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 1680 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 1681 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap, 1682 HEAP_ZERO_MEMORY, 1683 LayoutBufferSize); 1684 if (DiskEntry->LayoutBuffer == NULL) 1685 { 1686 DPRINT1("Failed to allocate the disk layout buffer!\n"); 1687 return; 1688 } 1689 1690 /* Keep looping while the drive layout buffer is too small */ 1691 for (;;) 1692 { 1693 DPRINT1("Buffer size: %lu\n", LayoutBufferSize); 1694 Status = NtDeviceIoControlFile(FileHandle, 1695 NULL, 1696 NULL, 1697 NULL, 1698 &Iosb, 1699 IOCTL_DISK_GET_DRIVE_LAYOUT, 1700 NULL, 1701 0, 1702 DiskEntry->LayoutBuffer, 1703 LayoutBufferSize); 1704 if (NT_SUCCESS(Status)) 1705 break; 1706 1707 if (Status != STATUS_BUFFER_TOO_SMALL) 1708 { 1709 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status); 1710 return; 1711 } 1712 1713 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION); 1714 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap, 1715 HEAP_ZERO_MEMORY, 1716 DiskEntry->LayoutBuffer, 1717 LayoutBufferSize); 1718 if (NewLayoutBuffer == NULL) 1719 { 1720 DPRINT1("Failed to reallocate the disk layout buffer!\n"); 1721 return; 1722 } 1723 1724 DiskEntry->LayoutBuffer = NewLayoutBuffer; 1725 } 1726 1727 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount); 1728 1729 #ifdef DUMP_PARTITION_TABLE 1730 DumpPartitionTable(DiskEntry); 1731 #endif 1732 1733 if (IsSuperFloppy(DiskEntry)) 1734 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber); 1735 1736 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 && 1737 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 && 1738 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED) 1739 { 1740 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0) 1741 { 1742 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack); 1743 } 1744 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0) 1745 { 1746 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1747 } 1748 else 1749 { 1750 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart); 1751 } 1752 } 1753 else 1754 { 1755 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1756 } 1757 1758 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1759 { 1760 DiskEntry->NewDisk = TRUE; 1761 DiskEntry->LayoutBuffer->PartitionCount = 4; 1762 1763 for (i = 0; i < 4; i++) 1764 { 1765 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1766 } 1767 } 1768 else 1769 { 1770 /* Enumerate and add the first four primary partitions */ 1771 for (i = 0; i < 4; i++) 1772 { 1773 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE); 1774 } 1775 1776 /* Enumerate and add the remaining partitions as logical ones */ 1777 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4) 1778 { 1779 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE); 1780 } 1781 } 1782 1783 ScanForUnpartitionedDiskSpace(DiskEntry); 1784 } 1785 1786 /* 1787 * Retrieve the system disk, i.e. the fixed disk that is accessible by the 1788 * firmware during boot time and where the system partition resides. 1789 * If no system partition has been determined, we retrieve the first disk 1790 * that verifies the mentioned criteria above. 1791 */ 1792 static 1793 PDISKENTRY 1794 GetSystemDisk( 1795 IN PPARTLIST List) 1796 { 1797 PLIST_ENTRY Entry; 1798 PDISKENTRY DiskEntry; 1799 1800 /* Check for empty disk list */ 1801 if (IsListEmpty(&List->DiskListHead)) 1802 return NULL; 1803 1804 /* 1805 * If we already have a system partition, the system disk 1806 * is the one on which the system partition resides. 1807 */ 1808 if (List->SystemPartition) 1809 return List->SystemPartition->DiskEntry; 1810 1811 /* Loop over the disks and find the correct one */ 1812 for (Entry = List->DiskListHead.Flink; 1813 Entry != &List->DiskListHead; 1814 Entry = Entry->Flink) 1815 { 1816 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1817 1818 /* The disk must be a fixed disk and be found by the firmware */ 1819 if (DiskEntry->MediaType == FixedMedia && DiskEntry->BiosFound) 1820 { 1821 break; 1822 } 1823 } 1824 if (Entry == &List->DiskListHead) 1825 { 1826 /* We haven't encountered any suitable disk */ 1827 return NULL; 1828 } 1829 1830 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1831 { 1832 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1833 } 1834 1835 return DiskEntry; 1836 } 1837 1838 /* 1839 * Retrieve the actual "active" partition of the given disk. 1840 * On MBR disks, partition with the Active/Boot flag set; 1841 * on GPT disks, partition with the correct GUID. 1842 */ 1843 BOOLEAN 1844 IsPartitionActive( 1845 IN PPARTENTRY PartEntry) 1846 { 1847 // TODO: Support for GPT disks! 1848 1849 if (IsContainerPartition(PartEntry->PartitionType)) 1850 return FALSE; 1851 1852 /* Check if the partition is partitioned, used and active */ 1853 if (PartEntry->IsPartitioned && 1854 // !IsContainerPartition(PartEntry->PartitionType) && 1855 PartEntry->BootIndicator) 1856 { 1857 /* Yes it is */ 1858 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1859 return TRUE; 1860 } 1861 1862 return FALSE; 1863 } 1864 1865 static 1866 PPARTENTRY 1867 GetActiveDiskPartition( 1868 IN PDISKENTRY DiskEntry) 1869 { 1870 PLIST_ENTRY ListEntry; 1871 PPARTENTRY PartEntry; 1872 PPARTENTRY ActivePartition = NULL; 1873 1874 /* Check for empty disk list */ 1875 // ASSERT(DiskEntry); 1876 if (!DiskEntry) 1877 return NULL; 1878 1879 /* Check for empty partition list */ 1880 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1881 return NULL; 1882 1883 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 1884 { 1885 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 1886 return NULL; 1887 } 1888 1889 /* Scan all (primary) partitions to find the active disk partition */ 1890 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 1891 ListEntry != &DiskEntry->PrimaryPartListHead; 1892 ListEntry = ListEntry->Flink) 1893 { 1894 /* Retrieve the partition */ 1895 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1896 if (IsPartitionActive(PartEntry)) 1897 { 1898 /* Yes, we've found it */ 1899 ASSERT(DiskEntry == PartEntry->DiskEntry); 1900 ASSERT(PartEntry->IsPartitioned); 1901 1902 ActivePartition = PartEntry; 1903 1904 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n", 1905 PartEntry->PartitionNumber, DiskEntry->DiskNumber, 1906 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter); 1907 break; 1908 } 1909 } 1910 1911 /* Check if the disk is new and if so, use its first partition as the active system partition */ 1912 if (DiskEntry->NewDisk && ActivePartition != NULL) 1913 { 1914 // FIXME: What to do?? 1915 DPRINT1("NewDisk TRUE but already existing active partition?\n"); 1916 } 1917 1918 /* Return the active partition found (or none) */ 1919 return ActivePartition; 1920 } 1921 1922 PPARTLIST 1923 CreatePartitionList(VOID) 1924 { 1925 PPARTLIST List; 1926 PDISKENTRY SystemDisk; 1927 OBJECT_ATTRIBUTES ObjectAttributes; 1928 SYSTEM_DEVICE_INFORMATION Sdi; 1929 IO_STATUS_BLOCK Iosb; 1930 ULONG ReturnSize; 1931 NTSTATUS Status; 1932 ULONG DiskNumber; 1933 HANDLE FileHandle; 1934 UNICODE_STRING Name; 1935 WCHAR Buffer[MAX_PATH]; 1936 1937 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 1938 0, 1939 sizeof(PARTLIST)); 1940 if (List == NULL) 1941 return NULL; 1942 1943 List->SystemPartition = NULL; 1944 1945 InitializeListHead(&List->DiskListHead); 1946 InitializeListHead(&List->BiosDiskListHead); 1947 1948 /* 1949 * Enumerate the disks seen by the BIOS; this will be used later 1950 * to map drives seen by NTOS with their corresponding BIOS names. 1951 */ 1952 EnumerateBiosDiskEntries(List); 1953 1954 /* Enumerate disks seen by NTOS */ 1955 Status = NtQuerySystemInformation(SystemDeviceInformation, 1956 &Sdi, 1957 sizeof(Sdi), 1958 &ReturnSize); 1959 if (!NT_SUCCESS(Status)) 1960 { 1961 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx\n", Status); 1962 RtlFreeHeap(ProcessHeap, 0, List); 1963 return NULL; 1964 } 1965 1966 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) 1967 { 1968 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 1969 L"\\Device\\Harddisk%lu\\Partition0", 1970 DiskNumber); 1971 RtlInitUnicodeString(&Name, Buffer); 1972 1973 InitializeObjectAttributes(&ObjectAttributes, 1974 &Name, 1975 OBJ_CASE_INSENSITIVE, 1976 NULL, 1977 NULL); 1978 1979 Status = NtOpenFile(&FileHandle, 1980 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 1981 &ObjectAttributes, 1982 &Iosb, 1983 FILE_SHARE_READ | FILE_SHARE_WRITE, 1984 FILE_SYNCHRONOUS_IO_NONALERT); 1985 if (NT_SUCCESS(Status)) 1986 { 1987 AddDiskToList(FileHandle, DiskNumber, List); 1988 NtClose(FileHandle); 1989 } 1990 } 1991 1992 UpdateDiskSignatures(List); 1993 UpdateHwDiskNumbers(List); 1994 AssignDriveLetters(List); 1995 1996 /* 1997 * Retrieve the system partition: the active partition on the system 1998 * disk (the one that will be booted by default by the hardware). 1999 */ 2000 SystemDisk = GetSystemDisk(List); 2001 List->SystemPartition = (SystemDisk ? GetActiveDiskPartition(SystemDisk) : NULL); 2002 2003 return List; 2004 } 2005 2006 VOID 2007 DestroyPartitionList( 2008 IN PPARTLIST List) 2009 { 2010 PDISKENTRY DiskEntry; 2011 PBIOSDISKENTRY BiosDiskEntry; 2012 PPARTENTRY PartEntry; 2013 PLIST_ENTRY Entry; 2014 2015 /* Release disk and partition info */ 2016 while (!IsListEmpty(&List->DiskListHead)) 2017 { 2018 Entry = RemoveHeadList(&List->DiskListHead); 2019 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2020 2021 /* Release driver name */ 2022 RtlFreeUnicodeString(&DiskEntry->DriverName); 2023 2024 /* Release primary partition list */ 2025 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead)) 2026 { 2027 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead); 2028 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2029 2030 RtlFreeHeap(ProcessHeap, 0, PartEntry); 2031 } 2032 2033 /* Release logical partition list */ 2034 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 2035 { 2036 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 2037 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2038 2039 RtlFreeHeap(ProcessHeap, 0, PartEntry); 2040 } 2041 2042 /* Release layout buffer */ 2043 if (DiskEntry->LayoutBuffer != NULL) 2044 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer); 2045 2046 /* Release disk entry */ 2047 RtlFreeHeap(ProcessHeap, 0, DiskEntry); 2048 } 2049 2050 /* Release the bios disk info */ 2051 while (!IsListEmpty(&List->BiosDiskListHead)) 2052 { 2053 Entry = RemoveHeadList(&List->BiosDiskListHead); 2054 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry); 2055 2056 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry); 2057 } 2058 2059 /* Release list head */ 2060 RtlFreeHeap(ProcessHeap, 0, List); 2061 } 2062 2063 PDISKENTRY 2064 GetDiskByBiosNumber( 2065 _In_ PPARTLIST List, 2066 _In_ ULONG HwDiskNumber) 2067 { 2068 PDISKENTRY DiskEntry; 2069 PLIST_ENTRY Entry; 2070 2071 /* Loop over the disks and find the correct one */ 2072 for (Entry = List->DiskListHead.Flink; 2073 Entry != &List->DiskListHead; 2074 Entry = Entry->Flink) 2075 { 2076 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2077 2078 if (DiskEntry->HwDiskNumber == HwDiskNumber) 2079 return DiskEntry; /* Disk found, return it */ 2080 } 2081 2082 /* Disk not found, stop there */ 2083 return NULL; 2084 } 2085 2086 PDISKENTRY 2087 GetDiskByNumber( 2088 _In_ PPARTLIST List, 2089 _In_ ULONG DiskNumber) 2090 { 2091 PDISKENTRY DiskEntry; 2092 PLIST_ENTRY Entry; 2093 2094 /* Loop over the disks and find the correct one */ 2095 for (Entry = List->DiskListHead.Flink; 2096 Entry != &List->DiskListHead; 2097 Entry = Entry->Flink) 2098 { 2099 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2100 2101 if (DiskEntry->DiskNumber == DiskNumber) 2102 return DiskEntry; /* Disk found, return it */ 2103 } 2104 2105 /* Disk not found, stop there */ 2106 return NULL; 2107 } 2108 2109 PDISKENTRY 2110 GetDiskBySCSI( 2111 _In_ PPARTLIST List, 2112 _In_ USHORT Port, 2113 _In_ USHORT Bus, 2114 _In_ USHORT Id) 2115 { 2116 PDISKENTRY DiskEntry; 2117 PLIST_ENTRY Entry; 2118 2119 /* Loop over the disks and find the correct one */ 2120 for (Entry = List->DiskListHead.Flink; 2121 Entry != &List->DiskListHead; 2122 Entry = Entry->Flink) 2123 { 2124 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2125 2126 if (DiskEntry->Port == Port && 2127 DiskEntry->Bus == Bus && 2128 DiskEntry->Id == Id) 2129 { 2130 /* Disk found, return it */ 2131 return DiskEntry; 2132 } 2133 } 2134 2135 /* Disk not found, stop there */ 2136 return NULL; 2137 } 2138 2139 PDISKENTRY 2140 GetDiskBySignature( 2141 _In_ PPARTLIST List, 2142 _In_ ULONG Signature) 2143 { 2144 PDISKENTRY DiskEntry; 2145 PLIST_ENTRY Entry; 2146 2147 /* Loop over the disks and find the correct one */ 2148 for (Entry = List->DiskListHead.Flink; 2149 Entry != &List->DiskListHead; 2150 Entry = Entry->Flink) 2151 { 2152 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 2153 2154 if (DiskEntry->LayoutBuffer->Signature == Signature) 2155 return DiskEntry; /* Disk found, return it */ 2156 } 2157 2158 /* Disk not found, stop there */ 2159 return NULL; 2160 } 2161 2162 PPARTENTRY 2163 GetPartition( 2164 _In_ PDISKENTRY DiskEntry, 2165 _In_ ULONG PartitionNumber) 2166 { 2167 PPARTENTRY PartEntry; 2168 PLIST_ENTRY Entry; 2169 2170 /* Forbid whole-disk or extended container partition access */ 2171 if (PartitionNumber == 0) 2172 return NULL; 2173 2174 /* Loop over the primary partitions first... */ 2175 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 2176 Entry != &DiskEntry->PrimaryPartListHead; 2177 Entry = Entry->Flink) 2178 { 2179 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2180 2181 if (PartEntry->PartitionNumber == PartitionNumber) 2182 return PartEntry; /* Partition found, return it */ 2183 } 2184 2185 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2186 return NULL; 2187 2188 /* ... then over the logical partitions if needed */ 2189 for (Entry = DiskEntry->LogicalPartListHead.Flink; 2190 Entry != &DiskEntry->LogicalPartListHead; 2191 Entry = Entry->Flink) 2192 { 2193 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2194 2195 if (PartEntry->PartitionNumber == PartitionNumber) 2196 return PartEntry; /* Partition found, return it */ 2197 } 2198 2199 /* The partition was not found on the disk, stop there */ 2200 return NULL; 2201 } 2202 2203 PPARTENTRY 2204 SelectPartition( 2205 _In_ PPARTLIST List, 2206 _In_ ULONG DiskNumber, 2207 _In_ ULONG PartitionNumber) 2208 { 2209 PDISKENTRY DiskEntry; 2210 PPARTENTRY PartEntry; 2211 2212 /* Find the disk */ 2213 DiskEntry = GetDiskByNumber(List, DiskNumber); 2214 if (!DiskEntry) 2215 return NULL; 2216 ASSERT(DiskEntry->DiskNumber == DiskNumber); 2217 2218 /* Find the partition */ 2219 PartEntry = GetPartition(DiskEntry, PartitionNumber); 2220 if (!PartEntry) 2221 return NULL; 2222 ASSERT(PartEntry->DiskEntry == DiskEntry); 2223 ASSERT(PartEntry->PartitionNumber == PartitionNumber); 2224 2225 return PartEntry; 2226 } 2227 2228 PPARTENTRY 2229 GetNextPartition( 2230 IN PPARTLIST List, 2231 IN PPARTENTRY CurrentPart OPTIONAL) 2232 { 2233 PLIST_ENTRY DiskListEntry; 2234 PLIST_ENTRY PartListEntry; 2235 PDISKENTRY CurrentDisk; 2236 2237 /* Fail if no disks are available */ 2238 if (IsListEmpty(&List->DiskListHead)) 2239 return NULL; 2240 2241 /* Check for the next usable entry on the current partition's disk */ 2242 if (CurrentPart != NULL) 2243 { 2244 CurrentDisk = CurrentPart->DiskEntry; 2245 2246 if (CurrentPart->LogicalPartition) 2247 { 2248 /* Logical partition */ 2249 2250 PartListEntry = CurrentPart->ListEntry.Flink; 2251 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2252 { 2253 /* Next logical partition */ 2254 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2255 return CurrentPart; 2256 } 2257 else 2258 { 2259 PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink; 2260 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2261 { 2262 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2263 return CurrentPart; 2264 } 2265 } 2266 } 2267 else 2268 { 2269 /* Primary or extended partition */ 2270 2271 if (CurrentPart->IsPartitioned && 2272 IsContainerPartition(CurrentPart->PartitionType)) 2273 { 2274 /* First logical partition */ 2275 PartListEntry = CurrentDisk->LogicalPartListHead.Flink; 2276 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2277 { 2278 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2279 return CurrentPart; 2280 } 2281 } 2282 else 2283 { 2284 /* Next primary partition */ 2285 PartListEntry = CurrentPart->ListEntry.Flink; 2286 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2287 { 2288 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2289 return CurrentPart; 2290 } 2291 } 2292 } 2293 } 2294 2295 /* Search for the first partition entry on the next disk */ 2296 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink 2297 : List->DiskListHead.Flink); 2298 DiskListEntry != &List->DiskListHead; 2299 DiskListEntry = DiskListEntry->Flink) 2300 { 2301 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry); 2302 2303 if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT) 2304 { 2305 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2306 continue; 2307 } 2308 2309 PartListEntry = CurrentDisk->PrimaryPartListHead.Flink; 2310 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2311 { 2312 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2313 return CurrentPart; 2314 } 2315 } 2316 2317 return NULL; 2318 } 2319 2320 PPARTENTRY 2321 GetPrevPartition( 2322 IN PPARTLIST List, 2323 IN PPARTENTRY CurrentPart OPTIONAL) 2324 { 2325 PLIST_ENTRY DiskListEntry; 2326 PLIST_ENTRY PartListEntry; 2327 PDISKENTRY CurrentDisk; 2328 2329 /* Fail if no disks are available */ 2330 if (IsListEmpty(&List->DiskListHead)) 2331 return NULL; 2332 2333 /* Check for the previous usable entry on the current partition's disk */ 2334 if (CurrentPart != NULL) 2335 { 2336 CurrentDisk = CurrentPart->DiskEntry; 2337 2338 if (CurrentPart->LogicalPartition) 2339 { 2340 /* Logical partition */ 2341 2342 PartListEntry = CurrentPart->ListEntry.Blink; 2343 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2344 { 2345 /* Previous logical partition */ 2346 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2347 } 2348 else 2349 { 2350 /* Extended partition */ 2351 CurrentPart = CurrentDisk->ExtendedPartition; 2352 } 2353 return CurrentPart; 2354 } 2355 else 2356 { 2357 /* Primary or extended partition */ 2358 2359 PartListEntry = CurrentPart->ListEntry.Blink; 2360 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2361 { 2362 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2363 2364 if (CurrentPart->IsPartitioned && 2365 IsContainerPartition(CurrentPart->PartitionType)) 2366 { 2367 PartListEntry = CurrentDisk->LogicalPartListHead.Blink; 2368 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2369 } 2370 2371 return CurrentPart; 2372 } 2373 } 2374 } 2375 2376 /* Search for the last partition entry on the previous disk */ 2377 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink 2378 : List->DiskListHead.Blink); 2379 DiskListEntry != &List->DiskListHead; 2380 DiskListEntry = DiskListEntry->Blink) 2381 { 2382 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry); 2383 2384 if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT) 2385 { 2386 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2387 continue; 2388 } 2389 2390 PartListEntry = CurrentDisk->PrimaryPartListHead.Blink; 2391 if (PartListEntry != &CurrentDisk->PrimaryPartListHead) 2392 { 2393 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2394 2395 if (CurrentPart->IsPartitioned && 2396 IsContainerPartition(CurrentPart->PartitionType)) 2397 { 2398 PartListEntry = CurrentDisk->LogicalPartListHead.Blink; 2399 if (PartListEntry != &CurrentDisk->LogicalPartListHead) 2400 { 2401 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry); 2402 return CurrentPart; 2403 } 2404 } 2405 else 2406 { 2407 return CurrentPart; 2408 } 2409 } 2410 } 2411 2412 return NULL; 2413 } 2414 2415 static inline 2416 BOOLEAN 2417 IsEmptyLayoutEntry( 2418 _In_ PPARTITION_INFORMATION PartitionInfo) 2419 { 2420 return (PartitionInfo->StartingOffset.QuadPart == 0 && 2421 PartitionInfo->PartitionLength.QuadPart == 0); 2422 } 2423 2424 static inline 2425 BOOLEAN 2426 IsSamePrimaryLayoutEntry( 2427 _In_ PPARTITION_INFORMATION PartitionInfo, 2428 _In_ PPARTENTRY PartEntry) 2429 { 2430 return ((PartitionInfo->StartingOffset.QuadPart == GetPartEntryOffsetInBytes(PartEntry)) && 2431 (PartitionInfo->PartitionLength.QuadPart == GetPartEntrySizeInBytes(PartEntry))); 2432 // PartitionInfo->PartitionType == PartEntry->PartitionType 2433 } 2434 2435 2436 /** 2437 * @brief 2438 * Counts the number of partitioned disk regions in a given partition list. 2439 **/ 2440 static 2441 ULONG 2442 GetPartitionCount( 2443 _In_ PLIST_ENTRY PartListHead) 2444 { 2445 PLIST_ENTRY Entry; 2446 PPARTENTRY PartEntry; 2447 ULONG Count = 0; 2448 2449 for (Entry = PartListHead->Flink; 2450 Entry != PartListHead; 2451 Entry = Entry->Flink) 2452 { 2453 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2454 if (PartEntry->IsPartitioned) 2455 ++Count; 2456 } 2457 2458 return Count; 2459 } 2460 2461 #define GetPrimaryPartitionCount(DiskEntry) \ 2462 GetPartitionCount(&(DiskEntry)->PrimaryPartListHead) 2463 2464 #define GetLogicalPartitionCount(DiskEntry) \ 2465 (((DiskEntry)->DiskStyle == PARTITION_STYLE_MBR) \ 2466 ? GetPartitionCount(&(DiskEntry)->LogicalPartListHead) : 0) 2467 2468 2469 static 2470 BOOLEAN 2471 ReAllocateLayoutBuffer( 2472 IN PDISKENTRY DiskEntry) 2473 { 2474 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 2475 ULONG NewPartitionCount; 2476 ULONG CurrentPartitionCount = 0; 2477 ULONG LayoutBufferSize; 2478 ULONG i; 2479 2480 DPRINT1("ReAllocateLayoutBuffer()\n"); 2481 2482 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4; 2483 2484 if (DiskEntry->LayoutBuffer) 2485 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 2486 2487 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n", 2488 CurrentPartitionCount, NewPartitionCount); 2489 2490 if (CurrentPartitionCount == NewPartitionCount) 2491 return TRUE; 2492 2493 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 2494 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 2495 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap, 2496 HEAP_ZERO_MEMORY, 2497 DiskEntry->LayoutBuffer, 2498 LayoutBufferSize); 2499 if (NewLayoutBuffer == NULL) 2500 { 2501 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize); 2502 return FALSE; 2503 } 2504 2505 NewLayoutBuffer->PartitionCount = NewPartitionCount; 2506 2507 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */ 2508 if (NewPartitionCount > CurrentPartitionCount) 2509 { 2510 for (i = CurrentPartitionCount; i < NewPartitionCount; i++) 2511 { 2512 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 2513 } 2514 } 2515 2516 DiskEntry->LayoutBuffer = NewLayoutBuffer; 2517 2518 return TRUE; 2519 } 2520 2521 static 2522 VOID 2523 UpdateDiskLayout( 2524 IN PDISKENTRY DiskEntry) 2525 { 2526 PPARTITION_INFORMATION PartitionInfo; 2527 PPARTITION_INFORMATION LinkInfo; 2528 PLIST_ENTRY ListEntry; 2529 PPARTENTRY PartEntry; 2530 LARGE_INTEGER HiddenSectors64; 2531 ULONG Index; 2532 ULONG PartitionNumber = 1; 2533 2534 DPRINT1("UpdateDiskLayout()\n"); 2535 2536 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2537 { 2538 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2539 return; 2540 } 2541 2542 /* Resize the layout buffer if necessary */ 2543 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE) 2544 { 2545 DPRINT("ReAllocateLayoutBuffer() failed.\n"); 2546 return; 2547 } 2548 2549 /* Update the primary partition table */ 2550 Index = 0; 2551 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2552 ListEntry != &DiskEntry->PrimaryPartListHead; 2553 ListEntry = ListEntry->Flink) 2554 { 2555 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2556 2557 if (PartEntry->IsPartitioned) 2558 { 2559 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2560 2561 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2562 PartEntry->PartitionIndex = Index; 2563 2564 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2565 if (PartEntry->New) 2566 PartEntry->PartitionNumber = 0; 2567 2568 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0); 2569 2570 if (!IsSamePrimaryLayoutEntry(PartitionInfo, PartEntry)) 2571 { 2572 DPRINT1("Updating primary partition entry %lu\n", Index); 2573 2574 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry); 2575 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry); 2576 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart; 2577 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2578 PartitionInfo->PartitionType = PartEntry->PartitionType; 2579 PartitionInfo->BootIndicator = PartEntry->BootIndicator; 2580 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 2581 PartitionInfo->RewritePartition = TRUE; 2582 } 2583 2584 if (!IsContainerPartition(PartEntry->PartitionType)) 2585 PartitionNumber++; 2586 2587 Index++; 2588 } 2589 } 2590 2591 ASSERT(Index <= 4); 2592 2593 /* Update the logical partition table */ 2594 LinkInfo = NULL; 2595 Index = 4; 2596 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2597 ListEntry != &DiskEntry->LogicalPartListHead; 2598 ListEntry = ListEntry->Flink) 2599 { 2600 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2601 2602 if (PartEntry->IsPartitioned) 2603 { 2604 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2605 2606 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2607 PartEntry->PartitionIndex = Index; 2608 2609 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2610 if (PartEntry->New) 2611 PartEntry->PartitionNumber = 0; 2612 2613 PartEntry->OnDiskPartitionNumber = PartitionNumber; 2614 2615 DPRINT1("Updating logical partition entry %lu\n", Index); 2616 2617 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry); 2618 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry); 2619 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment; 2620 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2621 PartitionInfo->PartitionType = PartEntry->PartitionType; 2622 PartitionInfo->BootIndicator = FALSE; 2623 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 2624 PartitionInfo->RewritePartition = TRUE; 2625 2626 /* Fill the link entry of the previous partition entry */ 2627 if (LinkInfo) 2628 { 2629 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2630 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2631 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart; 2632 LinkInfo->HiddenSectors = HiddenSectors64.LowPart; 2633 LinkInfo->PartitionNumber = 0; 2634 2635 /* Extended partition links only use type 0x05, as observed 2636 * on Windows NT. Alternatively they could inherit the type 2637 * of the main extended container. */ 2638 LinkInfo->PartitionType = PARTITION_EXTENDED; // DiskEntry->ExtendedPartition->PartitionType; 2639 2640 LinkInfo->BootIndicator = FALSE; 2641 LinkInfo->RecognizedPartition = FALSE; 2642 LinkInfo->RewritePartition = TRUE; 2643 } 2644 2645 /* Save a pointer to the link entry of the current partition entry */ 2646 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1]; 2647 2648 PartitionNumber++; 2649 Index += 4; 2650 } 2651 } 2652 2653 /* Wipe unused primary partition entries */ 2654 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++) 2655 { 2656 DPRINT1("Primary partition entry %lu\n", Index); 2657 2658 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2659 2660 if (!IsEmptyLayoutEntry(PartitionInfo)) 2661 { 2662 DPRINT1("Wiping primary partition entry %lu\n", Index); 2663 2664 PartitionInfo->StartingOffset.QuadPart = 0; 2665 PartitionInfo->PartitionLength.QuadPart = 0; 2666 PartitionInfo->HiddenSectors = 0; 2667 PartitionInfo->PartitionNumber = 0; 2668 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 2669 PartitionInfo->BootIndicator = FALSE; 2670 PartitionInfo->RecognizedPartition = FALSE; 2671 PartitionInfo->RewritePartition = TRUE; 2672 } 2673 } 2674 2675 /* Wipe unused logical partition entries */ 2676 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++) 2677 { 2678 if (Index % 4 >= 2) 2679 { 2680 DPRINT1("Logical partition entry %lu\n", Index); 2681 2682 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2683 2684 if (!IsEmptyLayoutEntry(PartitionInfo)) 2685 { 2686 DPRINT1("Wiping partition entry %lu\n", Index); 2687 2688 PartitionInfo->StartingOffset.QuadPart = 0; 2689 PartitionInfo->PartitionLength.QuadPart = 0; 2690 PartitionInfo->HiddenSectors = 0; 2691 PartitionInfo->PartitionNumber = 0; 2692 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 2693 PartitionInfo->BootIndicator = FALSE; 2694 PartitionInfo->RecognizedPartition = FALSE; 2695 PartitionInfo->RewritePartition = TRUE; 2696 } 2697 } 2698 } 2699 2700 // HACK: See the FIXMEs in WritePartitions(): (Re)set the PartitionStyle to MBR. 2701 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 2702 2703 DiskEntry->Dirty = TRUE; 2704 2705 #ifdef DUMP_PARTITION_TABLE 2706 DumpPartitionTable(DiskEntry); 2707 #endif 2708 } 2709 2710 /** 2711 * @brief 2712 * Retrieves, if any, the unpartitioned disk region that is adjacent 2713 * (next or previous) to the specified partition. 2714 * 2715 * @param[in] PartEntry 2716 * Partition from where to find the adjacent unpartitioned region. 2717 * 2718 * @param[in] Direction 2719 * TRUE or FALSE to search the next or previous region, respectively. 2720 * 2721 * @return The adjacent unpartitioned region, if it exists, or NULL. 2722 **/ 2723 static 2724 PPARTENTRY 2725 GetAdjUnpartitionedEntry( 2726 _In_ PPARTENTRY PartEntry, 2727 _In_ BOOLEAN Direction) 2728 { 2729 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2730 PLIST_ENTRY ListHead, AdjEntry; 2731 2732 /* In case of MBR disks only, check the logical partitions if necessary */ 2733 if ((DiskEntry->DiskStyle == PARTITION_STYLE_MBR) && 2734 PartEntry->LogicalPartition) 2735 { 2736 ListHead = &DiskEntry->LogicalPartListHead; 2737 } 2738 else 2739 { 2740 ListHead = &DiskEntry->PrimaryPartListHead; 2741 } 2742 2743 if (Direction) 2744 AdjEntry = PartEntry->ListEntry.Flink; // Next region. 2745 else 2746 AdjEntry = PartEntry->ListEntry.Blink; // Previous region. 2747 2748 if (AdjEntry != ListHead) 2749 { 2750 PartEntry = CONTAINING_RECORD(AdjEntry, PARTENTRY, ListEntry); 2751 if (!PartEntry->IsPartitioned) 2752 { 2753 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 2754 return PartEntry; 2755 } 2756 } 2757 return NULL; 2758 } 2759 2760 ERROR_NUMBER 2761 PartitionCreationChecks( 2762 _In_ PPARTENTRY PartEntry) 2763 { 2764 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2765 2766 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2767 { 2768 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2769 return ERROR_WARN_PARTITION; 2770 } 2771 2772 /* Fail if the partition is already in use */ 2773 if (PartEntry->IsPartitioned) 2774 return ERROR_NEW_PARTITION; 2775 2776 /* 2777 * For primary partitions 2778 */ 2779 if (!PartEntry->LogicalPartition) 2780 { 2781 /* Only one primary partition is allowed on super-floppy */ 2782 if (IsSuperFloppy(DiskEntry)) 2783 return ERROR_PARTITION_TABLE_FULL; 2784 2785 /* Fail if there are already 4 primary partitions in the list */ 2786 if (GetPrimaryPartitionCount(DiskEntry) >= 4) 2787 return ERROR_PARTITION_TABLE_FULL; 2788 } 2789 /* 2790 * For logical partitions 2791 */ 2792 else 2793 { 2794 // TODO: Check that we are inside an extended partition!! 2795 // Then the following check will be useless. 2796 2797 /* Only one (primary) partition is allowed on super-floppy */ 2798 if (IsSuperFloppy(DiskEntry)) 2799 return ERROR_PARTITION_TABLE_FULL; 2800 } 2801 2802 return ERROR_SUCCESS; 2803 } 2804 2805 ERROR_NUMBER 2806 ExtendedPartitionCreationChecks( 2807 _In_ PPARTENTRY PartEntry) 2808 { 2809 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2810 2811 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 2812 { 2813 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 2814 return ERROR_WARN_PARTITION; 2815 } 2816 2817 /* Fail if the partition is already in use */ 2818 if (PartEntry->IsPartitioned) 2819 return ERROR_NEW_PARTITION; 2820 2821 /* Cannot create an extended partition within logical partition space */ 2822 if (PartEntry->LogicalPartition) 2823 return ERROR_ONLY_ONE_EXTENDED; 2824 2825 /* Only one primary partition is allowed on super-floppy */ 2826 if (IsSuperFloppy(DiskEntry)) 2827 return ERROR_PARTITION_TABLE_FULL; 2828 2829 /* Fail if there are already 4 primary partitions in the list */ 2830 if (GetPrimaryPartitionCount(DiskEntry) >= 4) 2831 return ERROR_PARTITION_TABLE_FULL; 2832 2833 /* Fail if there is another extended partition in the list */ 2834 if (DiskEntry->ExtendedPartition) 2835 return ERROR_ONLY_ONE_EXTENDED; 2836 2837 return ERROR_SUCCESS; 2838 } 2839 2840 // TODO: Improve upon the PartitionInfo parameter later 2841 // (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example) 2842 // So far we only use it as the optional type of the partition to create. 2843 BOOLEAN 2844 CreatePartition( 2845 _In_ PPARTLIST List, 2846 _Inout_ PPARTENTRY PartEntry, 2847 _In_opt_ ULONGLONG SizeBytes, 2848 _In_opt_ ULONG_PTR PartitionInfo) 2849 { 2850 ERROR_NUMBER Error; 2851 BOOLEAN isContainer = IsContainerPartition((UCHAR)PartitionInfo); 2852 PCSTR mainType = "Primary"; 2853 2854 if (isContainer) 2855 mainType = "Extended"; 2856 else if (PartEntry && PartEntry->LogicalPartition) 2857 mainType = "Logical"; 2858 2859 DPRINT1("CreatePartition(%s, %I64u bytes)\n", mainType, SizeBytes); 2860 2861 if (!List || !PartEntry || 2862 !PartEntry->DiskEntry || PartEntry->IsPartitioned) 2863 { 2864 return FALSE; 2865 } 2866 2867 if (isContainer) 2868 Error = ExtendedPartitionCreationChecks(PartEntry); 2869 else 2870 Error = PartitionCreationChecks(PartEntry); 2871 if (Error != NOT_AN_ERROR) 2872 { 2873 DPRINT1("PartitionCreationChecks(%s) failed with error %lu\n", mainType, Error); 2874 return FALSE; 2875 } 2876 2877 /* Initialize the partition entry, inserting a new blank region if needed */ 2878 if (!InitializePartitionEntry(PartEntry, SizeBytes, PartitionInfo)) 2879 return FALSE; 2880 2881 if (isContainer) 2882 { 2883 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container) 2884 PartEntry->New = FALSE; 2885 PartEntry->FormatState = Formatted; 2886 } 2887 2888 UpdateDiskLayout(PartEntry->DiskEntry); 2889 AssignDriveLetters(List); 2890 2891 return TRUE; 2892 } 2893 2894 NTSTATUS 2895 DismountVolume( 2896 IN PPARTENTRY PartEntry) 2897 { 2898 NTSTATUS Status; 2899 NTSTATUS LockStatus; 2900 UNICODE_STRING Name; 2901 OBJECT_ATTRIBUTES ObjectAttributes; 2902 IO_STATUS_BLOCK IoStatusBlock; 2903 HANDLE PartitionHandle; 2904 WCHAR Buffer[MAX_PATH]; 2905 2906 /* Check whether the partition is valid and was mounted by the system */ 2907 if (!PartEntry->IsPartitioned || 2908 IsContainerPartition(PartEntry->PartitionType) || 2909 !IsRecognizedPartition(PartEntry->PartitionType) || 2910 PartEntry->FormatState == UnknownFormat || 2911 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means 2912 // it has been usually mounted with RawFS and thus needs to be dismounted. 2913 !*PartEntry->FileSystem || 2914 PartEntry->PartitionNumber == 0) 2915 { 2916 /* The partition is not mounted, so just return success */ 2917 return STATUS_SUCCESS; 2918 } 2919 2920 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 2921 2922 /* Open the volume */ 2923 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 2924 L"\\Device\\Harddisk%lu\\Partition%lu", 2925 PartEntry->DiskEntry->DiskNumber, 2926 PartEntry->PartitionNumber); 2927 RtlInitUnicodeString(&Name, Buffer); 2928 2929 InitializeObjectAttributes(&ObjectAttributes, 2930 &Name, 2931 OBJ_CASE_INSENSITIVE, 2932 NULL, 2933 NULL); 2934 2935 Status = NtOpenFile(&PartitionHandle, 2936 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2937 &ObjectAttributes, 2938 &IoStatusBlock, 2939 FILE_SHARE_READ | FILE_SHARE_WRITE, 2940 FILE_SYNCHRONOUS_IO_NONALERT); 2941 if (!NT_SUCCESS(Status)) 2942 { 2943 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status); 2944 return Status; 2945 } 2946 2947 /* Lock the volume */ 2948 LockStatus = NtFsControlFile(PartitionHandle, 2949 NULL, 2950 NULL, 2951 NULL, 2952 &IoStatusBlock, 2953 FSCTL_LOCK_VOLUME, 2954 NULL, 2955 0, 2956 NULL, 2957 0); 2958 if (!NT_SUCCESS(LockStatus)) 2959 { 2960 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus); 2961 } 2962 2963 /* Dismount the volume */ 2964 Status = NtFsControlFile(PartitionHandle, 2965 NULL, 2966 NULL, 2967 NULL, 2968 &IoStatusBlock, 2969 FSCTL_DISMOUNT_VOLUME, 2970 NULL, 2971 0, 2972 NULL, 2973 0); 2974 if (!NT_SUCCESS(Status)) 2975 { 2976 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); 2977 } 2978 2979 /* Unlock the volume */ 2980 LockStatus = NtFsControlFile(PartitionHandle, 2981 NULL, 2982 NULL, 2983 NULL, 2984 &IoStatusBlock, 2985 FSCTL_UNLOCK_VOLUME, 2986 NULL, 2987 0, 2988 NULL, 2989 0); 2990 if (!NT_SUCCESS(LockStatus)) 2991 { 2992 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); 2993 } 2994 2995 /* Close the volume */ 2996 NtClose(PartitionHandle); 2997 2998 return Status; 2999 } 3000 3001 BOOLEAN 3002 DeletePartition( 3003 _In_ PPARTLIST List, 3004 _In_ PPARTENTRY PartEntry, 3005 _Out_opt_ PPARTENTRY* FreeRegion) 3006 { 3007 PDISKENTRY DiskEntry; 3008 PPARTENTRY PrevPartEntry; 3009 PPARTENTRY NextPartEntry; 3010 PPARTENTRY LogicalPartEntry; 3011 PLIST_ENTRY Entry; 3012 3013 if (!List || !PartEntry || 3014 !PartEntry->DiskEntry || !PartEntry->IsPartitioned) 3015 { 3016 return FALSE; 3017 } 3018 3019 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3020 3021 /* Clear the system partition if it is being deleted */ 3022 if (List->SystemPartition == PartEntry) 3023 { 3024 ASSERT(List->SystemPartition); 3025 List->SystemPartition = NULL; 3026 } 3027 3028 DiskEntry = PartEntry->DiskEntry; 3029 3030 /* Check which type of partition (primary/logical or extended) is being deleted */ 3031 if (DiskEntry->ExtendedPartition == PartEntry) 3032 { 3033 /* An extended partition is being deleted: delete all logical partition entries */ 3034 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 3035 { 3036 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 3037 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 3038 3039 /* Dismount the logical partition */ 3040 DismountVolume(LogicalPartEntry); 3041 3042 /* Delete it */ 3043 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry); 3044 } 3045 3046 DiskEntry->ExtendedPartition = NULL; 3047 } 3048 else 3049 { 3050 /* A primary partition is being deleted: dismount it */ 3051 DismountVolume(PartEntry); 3052 } 3053 3054 /* Adjust the unpartitioned disk space entries */ 3055 3056 /* Get pointer to previous and next unpartitioned entries */ 3057 PrevPartEntry = GetAdjUnpartitionedEntry(PartEntry, FALSE); 3058 NextPartEntry = GetAdjUnpartitionedEntry(PartEntry, TRUE); 3059 3060 if (PrevPartEntry != NULL && NextPartEntry != NULL) 3061 { 3062 /* Merge the previous, current and next unpartitioned entries */ 3063 3064 /* Adjust the previous entry length */ 3065 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart); 3066 3067 /* Remove the current and next entries */ 3068 RemoveEntryList(&PartEntry->ListEntry); 3069 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3070 RemoveEntryList(&NextPartEntry->ListEntry); 3071 RtlFreeHeap(ProcessHeap, 0, NextPartEntry); 3072 3073 /* Optionally return the freed region */ 3074 if (FreeRegion) 3075 *FreeRegion = PrevPartEntry; 3076 } 3077 else if (PrevPartEntry != NULL && NextPartEntry == NULL) 3078 { 3079 /* Merge the current and the previous unpartitioned entries */ 3080 3081 /* Adjust the previous entry length */ 3082 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart; 3083 3084 /* Remove the current entry */ 3085 RemoveEntryList(&PartEntry->ListEntry); 3086 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3087 3088 /* Optionally return the freed region */ 3089 if (FreeRegion) 3090 *FreeRegion = PrevPartEntry; 3091 } 3092 else if (PrevPartEntry == NULL && NextPartEntry != NULL) 3093 { 3094 /* Merge the current and the next unpartitioned entries */ 3095 3096 /* Adjust the next entry offset and length */ 3097 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart; 3098 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart; 3099 3100 /* Remove the current entry */ 3101 RemoveEntryList(&PartEntry->ListEntry); 3102 RtlFreeHeap(ProcessHeap, 0, PartEntry); 3103 3104 /* Optionally return the freed region */ 3105 if (FreeRegion) 3106 *FreeRegion = NextPartEntry; 3107 } 3108 else 3109 { 3110 /* Nothing to merge but change the current entry */ 3111 PartEntry->IsPartitioned = FALSE; 3112 PartEntry->OnDiskPartitionNumber = 0; 3113 PartEntry->PartitionNumber = 0; 3114 // PartEntry->PartitionIndex = 0; 3115 PartEntry->BootIndicator = FALSE; 3116 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED; 3117 PartEntry->FormatState = Unformatted; 3118 PartEntry->FileSystem[0] = L'\0'; 3119 PartEntry->DriveLetter = 0; 3120 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel)); 3121 3122 /* Optionally return the freed region */ 3123 if (FreeRegion) 3124 *FreeRegion = PartEntry; 3125 } 3126 3127 UpdateDiskLayout(DiskEntry); 3128 AssignDriveLetters(List); 3129 3130 return TRUE; 3131 } 3132 3133 static 3134 BOOLEAN 3135 IsSupportedActivePartition( 3136 IN PPARTENTRY PartEntry) 3137 { 3138 /* Check the type and the file system of this partition */ 3139 3140 /* 3141 * We do not support extended partition containers (on MBR disks) marked 3142 * as active, and containing code inside their extended boot records. 3143 */ 3144 if (IsContainerPartition(PartEntry->PartitionType)) 3145 { 3146 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n", 3147 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber); 3148 return FALSE; 3149 } 3150 3151 /* 3152 * ADDITIONAL CHECKS / BIG HACK: 3153 * 3154 * Retrieve its file system and check whether we have 3155 * write support for it. If that is the case we are fine 3156 * and we can use it directly. However if we don't have 3157 * write support we will need to change the active system 3158 * partition. 3159 * 3160 * NOTE that this is completely useless on architectures 3161 * where a real system partition is required, as on these 3162 * architectures the partition uses the FAT FS, for which 3163 * we do have write support. 3164 * NOTE also that for those architectures looking for a 3165 * partition boot indicator is insufficient. 3166 */ 3167 if (PartEntry->FormatState == Unformatted) 3168 { 3169 /* If this partition is mounted, it would use RawFS ("RAW") */ 3170 return TRUE; 3171 } 3172 else if ((PartEntry->FormatState == Preformatted) || 3173 (PartEntry->FormatState == Formatted)) 3174 { 3175 ASSERT(*PartEntry->FileSystem); 3176 3177 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */ 3178 if (wcsicmp(PartEntry->FileSystem, L"FAT") == 0 || 3179 wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 || 3180 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 || 3181 wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0) 3182 { 3183 return TRUE; 3184 } 3185 else 3186 { 3187 // WARNING: We cannot write on this FS yet! 3188 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n", 3189 PartEntry->FileSystem); 3190 return FALSE; 3191 } 3192 } 3193 else // if (PartEntry->FormatState == UnknownFormat) 3194 { 3195 ASSERT(!*PartEntry->FileSystem); 3196 3197 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n", 3198 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber); 3199 return FALSE; 3200 } 3201 3202 // HACK: WARNING: We cannot write on this FS yet! 3203 // See fsutil.c:InferFileSystem() 3204 if (PartEntry->PartitionType == PARTITION_IFS) 3205 { 3206 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n", 3207 PartEntry->FileSystem); 3208 return FALSE; 3209 } 3210 3211 return TRUE; 3212 } 3213 3214 PPARTENTRY 3215 FindSupportedSystemPartition( 3216 IN PPARTLIST List, 3217 IN BOOLEAN ForceSelect, 3218 IN PDISKENTRY AlternativeDisk OPTIONAL, 3219 IN PPARTENTRY AlternativePart OPTIONAL) 3220 { 3221 PLIST_ENTRY ListEntry; 3222 PDISKENTRY DiskEntry; 3223 PPARTENTRY PartEntry; 3224 PPARTENTRY ActivePartition; 3225 PPARTENTRY CandidatePartition = NULL; 3226 3227 /* Check for empty disk list */ 3228 if (IsListEmpty(&List->DiskListHead)) 3229 { 3230 /* No system partition! */ 3231 ASSERT(List->SystemPartition == NULL); 3232 goto NoSystemPartition; 3233 } 3234 3235 /* Adjust the optional alternative disk if needed */ 3236 if (!AlternativeDisk && AlternativePart) 3237 AlternativeDisk = AlternativePart->DiskEntry; 3238 3239 /* Ensure that the alternative partition is on the alternative disk */ 3240 if (AlternativePart) 3241 ASSERT(AlternativeDisk && (AlternativePart->DiskEntry == AlternativeDisk)); 3242 3243 /* Ensure that the alternative disk is in the list */ 3244 if (AlternativeDisk) 3245 ASSERT(AlternativeDisk->PartList == List); 3246 3247 /* Start fresh */ 3248 CandidatePartition = NULL; 3249 3250 // 3251 // Step 1 : Check the system disk. 3252 // 3253 3254 /* 3255 * First, check whether the system disk, i.e. the one that will be booted 3256 * by default by the hardware, contains an active partition. If so this 3257 * should be our system partition. 3258 */ 3259 DiskEntry = GetSystemDisk(List); 3260 if (!DiskEntry) 3261 { 3262 /* No system disk found, directly go check the alternative disk */ 3263 goto UseAlternativeDisk; 3264 } 3265 3266 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3267 { 3268 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3269 goto UseAlternativeDisk; 3270 } 3271 3272 /* If we have a system partition (in the system disk), validate it */ 3273 ActivePartition = List->SystemPartition; 3274 if (ActivePartition && IsSupportedActivePartition(ActivePartition)) 3275 { 3276 CandidatePartition = ActivePartition; 3277 3278 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n", 3279 CandidatePartition->PartitionNumber, 3280 CandidatePartition->DiskEntry->DiskNumber, 3281 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3282 3283 /* Return the candidate system partition */ 3284 return CandidatePartition; 3285 } 3286 3287 /* If the system disk is not the optional alternative disk, perform the minimal checks */ 3288 if (DiskEntry != AlternativeDisk) 3289 { 3290 /* 3291 * No active partition has been recognized. Enumerate all the (primary) 3292 * partitions in the system disk, excluding the possible current active 3293 * partition, to find a new candidate. 3294 */ 3295 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3296 ListEntry != &DiskEntry->PrimaryPartListHead; 3297 ListEntry = ListEntry->Flink) 3298 { 3299 /* Retrieve the partition */ 3300 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3301 3302 /* Skip the current active partition */ 3303 if (PartEntry == ActivePartition) 3304 continue; 3305 3306 /* Check if the partition is partitioned and used */ 3307 if (PartEntry->IsPartitioned && 3308 !IsContainerPartition(PartEntry->PartitionType)) 3309 { 3310 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3311 3312 /* If we get a candidate active partition in the disk, validate it */ 3313 if (IsSupportedActivePartition(PartEntry)) 3314 { 3315 CandidatePartition = PartEntry; 3316 goto UseAlternativePartition; 3317 } 3318 } 3319 3320 #if 0 3321 /* Check if the partition is partitioned and used */ 3322 if (!PartEntry->IsPartitioned) 3323 { 3324 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 3325 3326 // TODO: Check for minimal size!! 3327 CandidatePartition = PartEntry; 3328 goto UseAlternativePartition; 3329 } 3330 #endif 3331 } 3332 3333 /* 3334 * Still nothing, look whether there is some free space that we can use 3335 * for the new system partition. We must be sure that the total number 3336 * of partition is less than the maximum allowed, and that the minimal 3337 * size is fine. 3338 */ 3339 // 3340 // TODO: Fix the handling of system partition being created in unpartitioned space!! 3341 // --> When to partition it? etc... 3342 // 3343 if (GetPrimaryPartitionCount(DiskEntry) < 4) 3344 { 3345 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3346 ListEntry != &DiskEntry->PrimaryPartListHead; 3347 ListEntry = ListEntry->Flink) 3348 { 3349 /* Retrieve the partition */ 3350 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3351 3352 /* Skip the current active partition */ 3353 if (PartEntry == ActivePartition) 3354 continue; 3355 3356 /* Check for unpartitioned space */ 3357 if (!PartEntry->IsPartitioned) 3358 { 3359 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 3360 3361 // TODO: Check for minimal size!! 3362 CandidatePartition = PartEntry; 3363 goto UseAlternativePartition; 3364 } 3365 } 3366 } 3367 } 3368 3369 3370 // 3371 // Step 2 : No active partition found: Check the alternative disk if specified. 3372 // 3373 3374 UseAlternativeDisk: 3375 if (!AlternativeDisk || (!ForceSelect && (DiskEntry != AlternativeDisk))) 3376 goto NoSystemPartition; 3377 3378 if (AlternativeDisk->DiskStyle == PARTITION_STYLE_GPT) 3379 { 3380 DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3381 goto NoSystemPartition; 3382 } 3383 3384 if (DiskEntry != AlternativeDisk) 3385 { 3386 /* Choose the alternative disk */ 3387 DiskEntry = AlternativeDisk; 3388 3389 /* If we get a candidate active partition, validate it */ 3390 ActivePartition = GetActiveDiskPartition(DiskEntry); 3391 if (ActivePartition && IsSupportedActivePartition(ActivePartition)) 3392 { 3393 CandidatePartition = ActivePartition; 3394 goto UseAlternativePartition; 3395 } 3396 } 3397 3398 /* We now may have an unsupported active partition, or none */ 3399 3400 /*** 3401 *** TODO: Improve the selection: 3402 *** - If we want a really separate system partition from the partition where 3403 *** we install, do something similar to what's done below in the code. 3404 *** - Otherwise if we allow for the system partition to be also the partition 3405 *** where we install, just directly fall down to using AlternativePart. 3406 ***/ 3407 3408 /* Retrieve the first partition of the disk */ 3409 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink, 3410 PARTENTRY, ListEntry); 3411 ASSERT(DiskEntry == PartEntry->DiskEntry); 3412 3413 CandidatePartition = PartEntry; 3414 3415 // 3416 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318 3417 // 3418 3419 /* Check if the disk is new and if so, use its first partition as the active system partition */ 3420 if (DiskEntry->NewDisk) 3421 { 3422 // !IsContainerPartition(PartEntry->PartitionType); 3423 if (!CandidatePartition->IsPartitioned || !CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */ 3424 { 3425 ASSERT(DiskEntry == CandidatePartition->DiskEntry); 3426 3427 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n", 3428 CandidatePartition->PartitionNumber, 3429 CandidatePartition->DiskEntry->DiskNumber, 3430 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3431 3432 /* Return the candidate system partition */ 3433 return CandidatePartition; 3434 } 3435 3436 // FIXME: What to do?? 3437 DPRINT1("NewDisk TRUE but first partition is used?\n"); 3438 } 3439 3440 /* 3441 * The disk is not new, check if any partition is initialized; 3442 * if not, the first one becomes the system partition. 3443 */ 3444 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3445 ListEntry != &DiskEntry->PrimaryPartListHead; 3446 ListEntry = ListEntry->Flink) 3447 { 3448 /* Retrieve the partition */ 3449 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3450 3451 /* Check if the partition is partitioned and is used */ 3452 // !IsContainerPartition(PartEntry->PartitionType); 3453 if (/* PartEntry->IsPartitioned && */ 3454 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator) 3455 { 3456 break; 3457 } 3458 } 3459 if (ListEntry == &DiskEntry->PrimaryPartListHead) 3460 { 3461 /* 3462 * OK we haven't encountered any used and active partition, 3463 * so use the first one as the system partition. 3464 */ 3465 ASSERT(DiskEntry == CandidatePartition->DiskEntry); 3466 3467 DPRINT1("Use 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 /* 3477 * The disk is not new, we did not find any actual active partition, 3478 * or the one we found was not supported, or any possible other candidate 3479 * is not supported. We then use the alternative partition if specified. 3480 */ 3481 if (AlternativePart) 3482 { 3483 DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n"); 3484 CandidatePartition = AlternativePart; 3485 goto UseAlternativePartition; 3486 } 3487 else 3488 { 3489 NoSystemPartition: 3490 DPRINT1("No valid or supported system partition has been found on this system!\n"); 3491 return NULL; 3492 } 3493 3494 UseAlternativePartition: 3495 /* 3496 * We are here because we did not find any (active) candidate system 3497 * partition that we know how to support. What we are going to do is 3498 * to change the existing system partition and use the alternative partition 3499 * (e.g. on which we install ReactOS) as the new system partition. 3500 * Then we will need to add in FreeLdr's boot menu an entry for booting 3501 * from the original system partition. 3502 */ 3503 ASSERT(CandidatePartition); 3504 3505 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n", 3506 CandidatePartition->PartitionNumber, 3507 CandidatePartition->DiskEntry->DiskNumber, 3508 (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter); 3509 3510 /* Return the candidate system partition */ 3511 return CandidatePartition; 3512 } 3513 3514 BOOLEAN 3515 SetActivePartition( 3516 IN PPARTLIST List, 3517 IN PPARTENTRY PartEntry, 3518 IN PPARTENTRY OldActivePart OPTIONAL) 3519 { 3520 /* Check for empty disk list */ 3521 if (IsListEmpty(&List->DiskListHead)) 3522 return FALSE; 3523 3524 /* Validate the partition entry */ 3525 if (!PartEntry) 3526 return FALSE; 3527 3528 /* 3529 * If the partition entry is already the system partition, or if it is 3530 * the same as the old active partition hint the user provided (and if 3531 * it is already active), just return success. 3532 */ 3533 if ((PartEntry == List->SystemPartition) || 3534 ((PartEntry == OldActivePart) && IsPartitionActive(OldActivePart))) 3535 { 3536 return TRUE; 3537 } 3538 3539 ASSERT(PartEntry->DiskEntry); 3540 3541 /* Ensure that the partition's disk is in the list */ 3542 ASSERT(PartEntry->DiskEntry->PartList == List); 3543 3544 /* 3545 * If the user provided an old active partition hint, verify that it is 3546 * indeeed active and belongs to the same disk where the new partition 3547 * belongs. Otherwise determine the current active partition on the disk 3548 * where the new partition belongs. 3549 */ 3550 if (!(OldActivePart && IsPartitionActive(OldActivePart) && (OldActivePart->DiskEntry == PartEntry->DiskEntry))) 3551 { 3552 /* It's not, determine the current active partition for the disk */ 3553 OldActivePart = GetActiveDiskPartition(PartEntry->DiskEntry); 3554 } 3555 3556 /* Unset the old active partition if it exists */ 3557 if (OldActivePart) 3558 { 3559 OldActivePart->BootIndicator = FALSE; 3560 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].BootIndicator = FALSE; 3561 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].RewritePartition = TRUE; 3562 OldActivePart->DiskEntry->Dirty = TRUE; 3563 } 3564 3565 /* Modify the system partition if the new partition is on the system disk */ 3566 if (PartEntry->DiskEntry == GetSystemDisk(List)) 3567 List->SystemPartition = PartEntry; 3568 3569 /* Set the new active partition */ 3570 PartEntry->BootIndicator = TRUE; 3571 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE; 3572 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; 3573 PartEntry->DiskEntry->Dirty = TRUE; 3574 3575 return TRUE; 3576 } 3577 3578 NTSTATUS 3579 WritePartitions( 3580 IN PDISKENTRY DiskEntry) 3581 { 3582 NTSTATUS Status; 3583 OBJECT_ATTRIBUTES ObjectAttributes; 3584 UNICODE_STRING Name; 3585 HANDLE FileHandle; 3586 IO_STATUS_BLOCK Iosb; 3587 ULONG BufferSize; 3588 PPARTITION_INFORMATION PartitionInfo; 3589 ULONG PartitionCount; 3590 PLIST_ENTRY ListEntry; 3591 PPARTENTRY PartEntry; 3592 WCHAR DstPath[MAX_PATH]; 3593 3594 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber); 3595 3596 /* If the disk is not dirty, there is nothing to do */ 3597 if (!DiskEntry->Dirty) 3598 return STATUS_SUCCESS; 3599 3600 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath), 3601 L"\\Device\\Harddisk%lu\\Partition0", 3602 DiskEntry->DiskNumber); 3603 RtlInitUnicodeString(&Name, DstPath); 3604 3605 InitializeObjectAttributes(&ObjectAttributes, 3606 &Name, 3607 OBJ_CASE_INSENSITIVE, 3608 NULL, 3609 NULL); 3610 3611 Status = NtOpenFile(&FileHandle, 3612 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 3613 &ObjectAttributes, 3614 &Iosb, 3615 0, 3616 FILE_SYNCHRONOUS_IO_NONALERT); 3617 if (!NT_SUCCESS(Status)) 3618 { 3619 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); 3620 return Status; 3621 } 3622 3623 #ifdef DUMP_PARTITION_TABLE 3624 DumpPartitionTable(DiskEntry); 3625 #endif 3626 3627 // 3628 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize 3629 // the disk in MBR or GPT format in case the disk was not initialized!! 3630 // For this we must ask the user which format to use. 3631 // 3632 3633 /* Save the original partition count to be restored later (see comment below) */ 3634 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 3635 3636 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */ 3637 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 3638 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION)); 3639 Status = NtDeviceIoControlFile(FileHandle, 3640 NULL, 3641 NULL, 3642 NULL, 3643 &Iosb, 3644 IOCTL_DISK_SET_DRIVE_LAYOUT, 3645 DiskEntry->LayoutBuffer, 3646 BufferSize, 3647 DiskEntry->LayoutBuffer, 3648 BufferSize); 3649 NtClose(FileHandle); 3650 3651 /* 3652 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts 3653 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count, 3654 * where such a table is expected to enumerate up to 4 partitions: 3655 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 . 3656 * Due to this we need to restore the original PartitionCount number. 3657 */ 3658 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount; 3659 3660 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */ 3661 if (!NT_SUCCESS(Status)) 3662 { 3663 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status); 3664 return Status; 3665 } 3666 3667 #ifdef DUMP_PARTITION_TABLE 3668 DumpPartitionTable(DiskEntry); 3669 #endif 3670 3671 /* Update the partition numbers */ 3672 3673 /* Update the primary partition table */ 3674 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 3675 ListEntry != &DiskEntry->PrimaryPartListHead; 3676 ListEntry = ListEntry->Flink) 3677 { 3678 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3679 3680 if (PartEntry->IsPartitioned) 3681 { 3682 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3683 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 3684 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 3685 } 3686 } 3687 3688 /* Update the logical partition table */ 3689 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 3690 ListEntry != &DiskEntry->LogicalPartListHead; 3691 ListEntry = ListEntry->Flink) 3692 { 3693 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 3694 3695 if (PartEntry->IsPartitioned) 3696 { 3697 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3698 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 3699 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 3700 } 3701 } 3702 3703 // 3704 // NOTE: Originally (see r40437), we used to install here also a new MBR 3705 // for this disk (by calling InstallMbrBootCodeToDisk), only if: 3706 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0. 3707 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set 3708 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk 3709 // was called too, the installation test was modified by checking whether 3710 // DiskEntry->NoMbr was TRUE (instead of NewDisk). 3711 // 3712 3713 // HACK: Parts of FIXMEs described above: (Re)set the PartitionStyle to MBR. 3714 DiskEntry->DiskStyle = PARTITION_STYLE_MBR; 3715 3716 /* The layout has been successfully updated, the disk is not dirty anymore */ 3717 DiskEntry->Dirty = FALSE; 3718 3719 return Status; 3720 } 3721 3722 BOOLEAN 3723 WritePartitionsToDisk( 3724 IN PPARTLIST List) 3725 { 3726 NTSTATUS Status; 3727 PLIST_ENTRY Entry; 3728 PDISKENTRY DiskEntry; 3729 3730 if (List == NULL) 3731 return TRUE; 3732 3733 for (Entry = List->DiskListHead.Flink; 3734 Entry != &List->DiskListHead; 3735 Entry = Entry->Flink) 3736 { 3737 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 3738 3739 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3740 { 3741 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3742 continue; 3743 } 3744 3745 if (DiskEntry->Dirty != FALSE) 3746 { 3747 Status = WritePartitions(DiskEntry); 3748 if (!NT_SUCCESS(Status)) 3749 { 3750 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n", 3751 DiskEntry->DiskNumber, Status); 3752 } 3753 } 3754 } 3755 3756 return TRUE; 3757 } 3758 3759 BOOLEAN 3760 SetMountedDeviceValue( 3761 IN WCHAR Letter, 3762 IN ULONG Signature, 3763 IN LARGE_INTEGER StartingOffset) 3764 { 3765 NTSTATUS Status; 3766 OBJECT_ATTRIBUTES ObjectAttributes; 3767 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices"); 3768 UNICODE_STRING ValueName; 3769 WCHAR ValueNameBuffer[16]; 3770 HANDLE KeyHandle; 3771 REG_DISK_MOUNT_INFO MountInfo; 3772 3773 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer), 3774 L"\\DosDevices\\%c:", Letter); 3775 RtlInitUnicodeString(&ValueName, ValueNameBuffer); 3776 3777 InitializeObjectAttributes(&ObjectAttributes, 3778 &KeyName, 3779 OBJ_CASE_INSENSITIVE, 3780 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 3781 NULL); 3782 3783 Status = NtOpenKey(&KeyHandle, 3784 KEY_ALL_ACCESS, 3785 &ObjectAttributes); 3786 if (!NT_SUCCESS(Status)) 3787 { 3788 Status = NtCreateKey(&KeyHandle, 3789 KEY_ALL_ACCESS, 3790 &ObjectAttributes, 3791 0, 3792 NULL, 3793 REG_OPTION_NON_VOLATILE, 3794 NULL); 3795 } 3796 if (!NT_SUCCESS(Status)) 3797 { 3798 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 3799 return FALSE; 3800 } 3801 3802 MountInfo.Signature = Signature; 3803 MountInfo.StartingOffset = StartingOffset; 3804 Status = NtSetValueKey(KeyHandle, 3805 &ValueName, 3806 0, 3807 REG_BINARY, 3808 (PVOID)&MountInfo, 3809 sizeof(MountInfo)); 3810 NtClose(KeyHandle); 3811 if (!NT_SUCCESS(Status)) 3812 { 3813 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 3814 return FALSE; 3815 } 3816 3817 return TRUE; 3818 } 3819 3820 BOOLEAN 3821 SetMountedDeviceValues( 3822 IN PPARTLIST List) 3823 { 3824 PLIST_ENTRY Entry1, Entry2; 3825 PDISKENTRY DiskEntry; 3826 PPARTENTRY PartEntry; 3827 LARGE_INTEGER StartingOffset; 3828 3829 if (List == NULL) 3830 return FALSE; 3831 3832 for (Entry1 = List->DiskListHead.Flink; 3833 Entry1 != &List->DiskListHead; 3834 Entry1 = Entry1->Flink) 3835 { 3836 DiskEntry = CONTAINING_RECORD(Entry1, 3837 DISKENTRY, 3838 ListEntry); 3839 3840 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) 3841 { 3842 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); 3843 continue; 3844 } 3845 3846 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 3847 Entry2 != &DiskEntry->PrimaryPartListHead; 3848 Entry2 = Entry2->Flink) 3849 { 3850 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 3851 if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType) 3852 { 3853 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3854 3855 /* Assign a "\DosDevices\#:" mount point to this partition */ 3856 if (PartEntry->DriveLetter) 3857 { 3858 StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry); 3859 if (!SetMountedDeviceValue(PartEntry->DriveLetter, 3860 DiskEntry->LayoutBuffer->Signature, 3861 StartingOffset)) 3862 { 3863 return FALSE; 3864 } 3865 } 3866 } 3867 } 3868 3869 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 3870 Entry2 != &DiskEntry->LogicalPartListHead; 3871 Entry2 = Entry2->Flink) 3872 { 3873 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 3874 if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType) 3875 { 3876 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 3877 3878 /* Assign a "\DosDevices\#:" mount point to this partition */ 3879 if (PartEntry->DriveLetter) 3880 { 3881 StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry); 3882 if (!SetMountedDeviceValue(PartEntry->DriveLetter, 3883 DiskEntry->LayoutBuffer->Signature, 3884 StartingOffset)) 3885 { 3886 return FALSE; 3887 } 3888 } 3889 } 3890 } 3891 } 3892 3893 return TRUE; 3894 } 3895 3896 VOID 3897 SetMBRPartitionType( 3898 IN PPARTENTRY PartEntry, 3899 IN UCHAR PartitionType) 3900 { 3901 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 3902 3903 ASSERT(DiskEntry->DiskStyle == PARTITION_STYLE_MBR); 3904 3905 PartEntry->PartitionType = PartitionType; 3906 3907 DiskEntry->Dirty = TRUE; 3908 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType; 3909 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType); 3910 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; 3911 } 3912 3913 /* EOF */ 3914