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