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