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