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