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