Reactos
at master 3060 lines 107 kB view raw
1/* 2 * PROJECT: ReactOS DiskPart 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/diskpart/partlist.c 5 * PURPOSE: Manages all the partitions of the OS in an interactive way. 6 * PROGRAMMERS: Eric Kohl 7 */ 8 9/* INCLUDES *******************************************************************/ 10 11#include "diskpart.h" 12 13#define NDEBUG 14#include <debug.h> 15 16#define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\ 17{\ 18 PLIST_ENTRY current;\ 19\ 20 current = (ListHead)->Flink;\ 21 while (current != (ListHead))\ 22 {\ 23 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\ 24 (NewEntry)->SortField)\ 25 {\ 26 break;\ 27 }\ 28 current = current->Flink;\ 29 }\ 30\ 31 InsertTailList(current, &((NewEntry)->ListEntryField));\ 32} 33 34/* We have to define it there, because it is not in the MS DDK */ 35#define PARTITION_LINUX 0x83 36 37#define PARTITION_TBL_SIZE 4 38 39#define MBR_MAGIC 0xAA55 40 41#include <pshpack1.h> 42 43typedef struct _PARTITION 44{ 45 unsigned char BootFlags; /* bootable? 0=no, 128=yes */ 46 unsigned char StartingHead; /* beginning head number */ 47 unsigned char StartingSector; /* beginning sector number */ 48 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */ 49 unsigned char PartitionType; /* Operating System type indicator code */ 50 unsigned char EndingHead; /* ending head number */ 51 unsigned char EndingSector; /* ending sector number */ 52 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */ 53 unsigned int StartingBlock; /* first sector relative to start of disk */ 54 unsigned int SectorCount; /* number of sectors in partition */ 55} PARTITION, *PPARTITION; 56 57typedef struct _PARTITION_SECTOR 58{ 59 UCHAR BootCode[440]; /* 0x000 */ 60 ULONG Signature; /* 0x1B8 */ 61 UCHAR Reserved[2]; /* 0x1BC */ 62 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */ 63 USHORT Magic; /* 0x1FE */ 64} PARTITION_SECTOR, *PPARTITION_SECTOR; 65 66#include <poppack.h> 67 68 69/* GLOBALS ********************************************************************/ 70 71LIST_ENTRY DiskListHead; 72LIST_ENTRY BiosDiskListHead; 73LIST_ENTRY VolumeListHead; 74 75PDISKENTRY CurrentDisk = NULL; 76PPARTENTRY CurrentPartition = NULL; 77PVOLENTRY CurrentVolume = NULL; 78 79 80/* FUNCTIONS ******************************************************************/ 81 82#ifdef DUMP_PARTITION_TABLE 83VOID 84DumpPartitionTable( 85 _In_ PDISKENTRY DiskEntry) 86{ 87 PPARTITION_INFORMATION_EX PartitionInfo; 88 ULONG i; 89 90 DbgPrint("\n"); 91 92 if (DiskEntry->LayoutBuffer->PartitionStyle == PARTITION_STYLE_MBR) 93 { 94 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n"); 95 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n"); 96 97 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++) 98 { 99 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i]; 100 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n", 101 i, 102 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector, 103 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector, 104 PartitionInfo->Mbr.HiddenSectors, 105 PartitionInfo->PartitionNumber, 106 PartitionInfo->Mbr.PartitionType, 107 PartitionInfo->Mbr.BootIndicator ? '*': ' ', 108 PartitionInfo->RewritePartition ? 'Y': 'N'); 109 } 110 } 111 else if (DiskEntry->LayoutBuffer->PartitionStyle == PARTITION_STYLE_GPT) 112 { 113 DbgPrint("Index Start Length Nr RW Type \n"); 114 DbgPrint("----- ------------ ------------ -- -- --------\n"); 115 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++) 116 { 117 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i]; 118 119 DbgPrint(" %3lu %12I64u %12I64u %2lu %c %08lx\n", 120 i, 121 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector, 122 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector, 123 PartitionInfo->PartitionNumber, 124 PartitionInfo->RewritePartition ? 'Y': 'N', 125 PartitionInfo->Gpt.PartitionType.Data1); 126 } 127 } 128 129 DbgPrint("\n"); 130} 131#endif 132 133#ifdef DUMP_PARTITION_LIST 134VOID 135DumpPartitionList( 136 _In_ PDISKENTRY DiskEntry) 137{ 138 PLIST_ENTRY ListEntry; 139 PPARTENTRY PartEntry; 140 141 DbgPrint("\n"); 142 143 if (DiskEntry->PartitionStyle == PARTITION_STYLE_GPT) 144 { 145 DbgPrint("Disk Start Disk End Disk Length \n"); 146 DbgPrint("------------ ------------ ------------\n"); 147 DbgPrint("%12I64u %12I64u %12I64u\n", 148 DiskEntry->StartSector.QuadPart, 149 DiskEntry->EndSector.QuadPart, 150 DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1); 151 152 DbgPrint("\n"); 153 154 DbgPrint("Start End Length Nr Type P\n"); 155 DbgPrint("------------ ------------ ------------ --- -------- --\n"); 156 157 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 158 ListEntry != &DiskEntry->PrimaryPartListHead; 159 ListEntry = ListEntry->Flink) 160 { 161 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 162 163 DbgPrint("%12I64u %12I64u %12I64u %3lu %08lx %c\n", 164 PartEntry->StartSector.QuadPart, 165 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1, 166 PartEntry->SectorCount.QuadPart, 167 PartEntry->PartitionNumber, 168 PartEntry->Gpt.PartitionType.Data1, 169 PartEntry->IsPartitioned ? 'Y': 'N'); 170 } 171 } 172 else if (DiskEntry->PartitionStyle == PARTITION_STYLE_MBR) 173 { 174 DbgPrint("Disk Start Disk End Disk Length \n"); 175 DbgPrint("------------ ------------ ------------\n"); 176 DbgPrint("%12I64u %12I64u %12I64u\n", 177 DiskEntry->StartSector.QuadPart, 178 DiskEntry->EndSector.QuadPart, 179 DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1); 180 181 } 182 183 DbgPrint("\n"); 184} 185#endif 186 187 188ULONGLONG 189AlignDown( 190 _In_ ULONGLONG Value, 191 _In_ ULONG Alignment) 192{ 193 ULONGLONG Temp; 194 195 Temp = Value / Alignment; 196 197 return Temp * Alignment; 198} 199 200static 201VOID 202GetDriverName( 203 PDISKENTRY DiskEntry) 204{ 205 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 206 WCHAR KeyName[32]; 207 NTSTATUS Status; 208 209 RtlInitUnicodeString(&DiskEntry->DriverName, 210 NULL); 211 212 StringCchPrintfW(KeyName, ARRAYSIZE(KeyName), 213 L"\\Scsi\\Scsi Port %lu", 214 DiskEntry->Port); 215 216 RtlZeroMemory(&QueryTable, 217 sizeof(QueryTable)); 218 219 QueryTable[0].Name = L"Driver"; 220 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 221 QueryTable[0].EntryContext = &DiskEntry->DriverName; 222 223 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP, 224 KeyName, 225 QueryTable, 226 NULL, 227 NULL); 228 if (!NT_SUCCESS(Status)) 229 { 230 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 231 } 232} 233 234static 235NTSTATUS 236NTAPI 237DiskIdentifierQueryRoutine( 238 PWSTR ValueName, 239 ULONG ValueType, 240 PVOID ValueData, 241 ULONG ValueLength, 242 PVOID Context, 243 PVOID EntryContext) 244{ 245 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 246 UNICODE_STRING NameU; 247 248 if (ValueType == REG_SZ && 249 ValueLength == 20 * sizeof(WCHAR)) 250 { 251 NameU.Buffer = (PWCHAR)ValueData; 252 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR); 253 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum); 254 255 NameU.Buffer = (PWCHAR)ValueData + 9; 256 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature); 257 258 return STATUS_SUCCESS; 259 } 260 261 return STATUS_UNSUCCESSFUL; 262} 263 264static 265NTSTATUS 266NTAPI 267DiskConfigurationDataQueryRoutine( 268 PWSTR ValueName, 269 ULONG ValueType, 270 PVOID ValueData, 271 ULONG ValueLength, 272 PVOID Context, 273 PVOID EntryContext) 274{ 275 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 276 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 277 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; 278 ULONG i; 279 280 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 281 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 282 return STATUS_UNSUCCESSFUL; 283 284 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 285 286 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 287#if 0 288 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 289 FullResourceDescriptor->PartialResourceList.Revision != 1) 290 return STATUS_UNSUCCESSFUL; 291#endif 292 293 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 294 { 295 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 296 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)) 297 continue; 298 299 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1]; 300 BiosDiskEntry->DiskGeometry = *DiskGeometry; 301 302 return STATUS_SUCCESS; 303 } 304 305 return STATUS_UNSUCCESSFUL; 306} 307 308static 309NTSTATUS 310NTAPI 311SystemConfigurationDataQueryRoutine( 312 PWSTR ValueName, 313 ULONG ValueType, 314 PVOID ValueData, 315 ULONG ValueLength, 316 PVOID Context, 317 PVOID EntryContext) 318{ 319 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 320 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context; 321 ULONG i; 322 323 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 324 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR)) 325 return STATUS_UNSUCCESSFUL; 326 327 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 328 329 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 330#if 0 331 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 332 FullResourceDescriptor->PartialResourceList.Revision != 1) 333 return STATUS_UNSUCCESSFUL; 334#endif 335 336 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 337 { 338 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 339 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0) 340 continue; 341 342 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0, 343 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 344 if (*Int13Drives == NULL) 345 return STATUS_NO_MEMORY; 346 347 memcpy(*Int13Drives, 348 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1], 349 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 350 return STATUS_SUCCESS; 351 } 352 353 return STATUS_UNSUCCESSFUL; 354} 355 356 357#define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter" 358 359static 360VOID 361EnumerateBiosDiskEntries(VOID) 362{ 363 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 364 WCHAR Name[120]; 365 ULONG AdapterCount; 366 ULONG DiskCount; 367 NTSTATUS Status; 368 PCM_INT13_DRIVE_PARAMETER Int13Drives; 369 PBIOSDISKENTRY BiosDiskEntry; 370 371 memset(QueryTable, 0, sizeof(QueryTable)); 372 373 QueryTable[1].Name = L"Configuration Data"; 374 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine; 375 Int13Drives = NULL; 376 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 377 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System", 378 &QueryTable[1], 379 (PVOID)&Int13Drives, 380 NULL); 381 if (!NT_SUCCESS(Status)) 382 { 383 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status); 384 return; 385 } 386 387 AdapterCount = 0; 388 while (1) 389 { 390 StringCchPrintfW(Name, ARRAYSIZE(Name), 391 L"%s\\%lu", ROOT_NAME, AdapterCount); 392 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 393 Name, 394 &QueryTable[2], 395 NULL, 396 NULL); 397 if (!NT_SUCCESS(Status)) 398 { 399 break; 400 } 401 402 StringCchPrintfW(Name, ARRAYSIZE(Name), 403 L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount); 404 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 405 Name, 406 &QueryTable[2], 407 NULL, 408 NULL); 409 if (NT_SUCCESS(Status)) 410 { 411 while (1) 412 { 413 StringCchPrintfW(Name, ARRAYSIZE(Name), 414 L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount); 415 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 416 Name, 417 &QueryTable[2], 418 NULL, 419 NULL); 420 if (!NT_SUCCESS(Status)) 421 { 422 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 423 return; 424 } 425 426 StringCchPrintfW(Name, ARRAYSIZE(Name), 427 L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount); 428 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 429 Name, 430 &QueryTable[2], 431 NULL, 432 NULL); 433 if (NT_SUCCESS(Status)) 434 { 435 QueryTable[0].Name = L"Identifier"; 436 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine; 437 QueryTable[1].Name = L"Configuration Data"; 438 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine; 439 440 DiskCount = 0; 441 while (1) 442 { 443 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY)); 444 if (BiosDiskEntry == NULL) 445 { 446 break; 447 } 448 449 StringCchPrintfW(Name, ARRAYSIZE(Name), 450 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount); 451 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 452 Name, 453 QueryTable, 454 (PVOID)BiosDiskEntry, 455 NULL); 456 if (!NT_SUCCESS(Status)) 457 { 458 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 459 break; 460 } 461 462 BiosDiskEntry->DiskNumber = DiskCount; 463 BiosDiskEntry->Recognized = FALSE; 464 465 if (DiskCount < Int13Drives[0].NumberDrives) 466 { 467 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount]; 468 } 469 else 470 { 471 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount); 472 } 473 474 InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry); 475 476 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber); 477 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature); 478 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum); 479 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector); 480 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders); 481 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads); 482 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect); 483 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders); 484 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack); 485 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads); 486 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives); 487 488 DiskCount++; 489 } 490 } 491 492 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 493 return; 494 } 495 } 496 497 AdapterCount++; 498 } 499 500 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 501} 502 503 504static 505VOID 506AddMbrPartitionToDisk( 507 ULONG DiskNumber, 508 PDISKENTRY DiskEntry, 509 ULONG PartitionIndex, 510 BOOLEAN LogicalPartition) 511{ 512 PPARTITION_INFORMATION_EX PartitionInfo; 513 PPARTENTRY PartEntry; 514 515 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 516 if (PartitionInfo->Mbr.PartitionType == 0 || 517 (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->Mbr.PartitionType))) 518 return; 519 520 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 521 HEAP_ZERO_MEMORY, 522 sizeof(PARTENTRY)); 523 if (PartEntry == NULL) 524 { 525 /* TODO: Error message */ 526 return; 527 } 528 529 PartEntry->DiskEntry = DiskEntry; 530 531 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 532 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 533 534 PartEntry->Mbr.BootIndicator = PartitionInfo->Mbr.BootIndicator; 535 PartEntry->Mbr.PartitionType = PartitionInfo->Mbr.PartitionType; 536 537 PartEntry->LogicalPartition = LogicalPartition; 538 PartEntry->IsPartitioned = TRUE; 539 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 540 PartEntry->PartitionIndex = PartitionIndex; 541 542 if (IsContainerPartition(PartEntry->Mbr.PartitionType)) 543 { 544 PartEntry->FormatState = Unformatted; 545 546 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL) 547 DiskEntry->ExtendedPartition = PartEntry; 548 } 549 else if ((PartEntry->Mbr.PartitionType == PARTITION_FAT_12) || 550 (PartEntry->Mbr.PartitionType == PARTITION_FAT_16) || 551 (PartEntry->Mbr.PartitionType == PARTITION_HUGE) || 552 (PartEntry->Mbr.PartitionType == PARTITION_XINT13) || 553 (PartEntry->Mbr.PartitionType == PARTITION_FAT32) || 554 (PartEntry->Mbr.PartitionType == PARTITION_FAT32_XINT13)) 555 { 556#if 0 557 if (CheckFatFormat()) 558 { 559 PartEntry->FormatState = Preformatted; 560 } 561 else 562 { 563 PartEntry->FormatState = Unformatted; 564 } 565#endif 566 PartEntry->FormatState = Preformatted; 567 } 568 else if (PartEntry->Mbr.PartitionType == PARTITION_LINUX) 569 { 570#if 0 571 if (CheckExt2Format()) 572 { 573 PartEntry->FormatState = Preformatted; 574 } 575 else 576 { 577 PartEntry->FormatState = Unformatted; 578 } 579#endif 580 PartEntry->FormatState = Preformatted; 581 } 582 else if (PartEntry->Mbr.PartitionType == PARTITION_IFS) 583 { 584#if 0 585 if (CheckNtfsFormat()) 586 { 587 PartEntry->FormatState = Preformatted; 588 } 589 else if (CheckHpfsFormat()) 590 { 591 PartEntry->FormatState = Preformatted; 592 } 593 else 594 { 595 PartEntry->FormatState = Unformatted; 596 } 597#endif 598 PartEntry->FormatState = Preformatted; 599 } 600 else 601 { 602 PartEntry->FormatState = UnknownFormat; 603 } 604 605 if (LogicalPartition) 606 InsertTailList(&DiskEntry->LogicalPartListHead, 607 &PartEntry->ListEntry); 608 else 609 InsertTailList(&DiskEntry->PrimaryPartListHead, 610 &PartEntry->ListEntry); 611} 612 613 614static 615VOID 616AddGptPartitionToDisk( 617 ULONG DiskNumber, 618 PDISKENTRY DiskEntry, 619 ULONG PartitionIndex) 620{ 621 PPARTITION_INFORMATION_EX PartitionInfo; 622 PPARTENTRY PartEntry; 623 624 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 625 if (IsEqualGUID(&PartitionInfo->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID)) 626 return; 627 628 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 629 HEAP_ZERO_MEMORY, 630 sizeof(PARTENTRY)); 631 if (PartEntry == NULL) 632 { 633 /* TODO: Error message */ 634 return; 635 } 636 637 PartEntry->DiskEntry = DiskEntry; 638 639 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 640 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 641 642 CopyMemory(&PartEntry->Gpt.PartitionType, &PartitionInfo->Gpt.PartitionType, sizeof(GUID)); 643 CopyMemory(&PartEntry->Gpt.PartitionId, &PartitionInfo->Gpt.PartitionId, sizeof(GUID)); 644 PartEntry->Gpt.Attributes = PartitionInfo->Gpt.Attributes; 645 646 PartEntry->LogicalPartition = FALSE; 647 PartEntry->IsPartitioned = TRUE; 648 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 649 PartEntry->PartitionIndex = PartitionIndex; 650 651 /* TODO: Determine the format state */ 652 PartEntry->FormatState = Unformatted; 653 654 InsertTailList(&DiskEntry->PrimaryPartListHead, 655 &PartEntry->ListEntry); 656} 657 658 659VOID 660ScanForUnpartitionedMbrDiskSpace( 661 PDISKENTRY DiskEntry) 662{ 663 ULONGLONG StartSector, EndSector; 664 ULONGLONG LastStartSector; 665 ULONGLONG LastSectorCount; 666 ULONGLONG LastUnusedSectorCount; 667 PPARTENTRY PartEntry; 668 PPARTENTRY NewPartEntry; 669 PLIST_ENTRY Entry; 670 671 DPRINT("ScanForUnpartitionedMbrDiskSpace()\n"); 672 673 /* Calculate the disk sector limits */ 674 /* Limit the SectorCount to 2^32 sectors for MBR disks */ 675 StartSector = (ULONGLONG)DiskEntry->SectorAlignment; 676 EndSector = min(DiskEntry->SectorCount.QuadPart, 0x100000000) - 1; 677 678 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 679 { 680 DPRINT1("No primary partition!\n"); 681 682 /* Create a partition table that represents the empty disk */ 683 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 684 HEAP_ZERO_MEMORY, 685 sizeof(PARTENTRY)); 686 if (NewPartEntry == NULL) 687 return; 688 689 NewPartEntry->DiskEntry = DiskEntry; 690 691 NewPartEntry->IsPartitioned = FALSE; 692 NewPartEntry->StartSector.QuadPart = StartSector; 693 NewPartEntry->SectorCount.QuadPart = AlignDown(EndSector + 1, DiskEntry->SectorAlignment) - 694 NewPartEntry->StartSector.QuadPart; 695 696 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 697 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 698 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 699 700 NewPartEntry->FormatState = Unformatted; 701 702 InsertTailList(&DiskEntry->PrimaryPartListHead, 703 &NewPartEntry->ListEntry); 704 705 return; 706 } 707 708 /* Start at the first usable sector */ 709 LastStartSector = StartSector; 710 LastSectorCount = 0ULL; 711 LastUnusedSectorCount = 0ULL; 712 713 Entry = DiskEntry->PrimaryPartListHead.Flink; 714 while (Entry != &DiskEntry->PrimaryPartListHead) 715 { 716 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 717 718 if (PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED || 719 PartEntry->SectorCount.QuadPart != 0ULL) 720 { 721 LastUnusedSectorCount = 722 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 723 724 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 725 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 726 { 727 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 728 729 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 730 HEAP_ZERO_MEMORY, 731 sizeof(PARTENTRY)); 732 if (NewPartEntry == NULL) 733 return; 734 735 NewPartEntry->DiskEntry = DiskEntry; 736 737 NewPartEntry->IsPartitioned = FALSE; 738 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 739 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 740 NewPartEntry->StartSector.QuadPart; 741 742 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 743 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 744 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 745 746 NewPartEntry->FormatState = Unformatted; 747 748 /* Insert the table into the list */ 749 InsertTailList(&PartEntry->ListEntry, 750 &NewPartEntry->ListEntry); 751 } 752 753 LastStartSector = PartEntry->StartSector.QuadPart; 754 LastSectorCount = PartEntry->SectorCount.QuadPart; 755 } 756 757 Entry = Entry->Flink; 758 } 759 760 /* Check for trailing unpartitioned disk space */ 761 if ((LastStartSector + LastSectorCount) < (EndSector + 1)) 762 { 763 LastUnusedSectorCount = AlignDown((EndSector + 1) - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 764 765 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 766 { 767 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 768 769 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 770 HEAP_ZERO_MEMORY, 771 sizeof(PARTENTRY)); 772 if (NewPartEntry == NULL) 773 return; 774 775 NewPartEntry->DiskEntry = DiskEntry; 776 777 NewPartEntry->IsPartitioned = FALSE; 778 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 779 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 780 NewPartEntry->StartSector.QuadPart; 781 782 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 783 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 784 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 785 786 NewPartEntry->FormatState = Unformatted; 787 788 /* Append the table to the list */ 789 InsertTailList(&DiskEntry->PrimaryPartListHead, 790 &NewPartEntry->ListEntry); 791 } 792 } 793 794 if (DiskEntry->ExtendedPartition != NULL) 795 { 796 if (IsListEmpty(&DiskEntry->LogicalPartListHead)) 797 { 798 DPRINT1("No logical partition!\n"); 799 800 /* Create a partition table entry that represents the empty extended partition */ 801 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 802 HEAP_ZERO_MEMORY, 803 sizeof(PARTENTRY)); 804 if (NewPartEntry == NULL) 805 return; 806 807 NewPartEntry->DiskEntry = DiskEntry; 808 NewPartEntry->LogicalPartition = TRUE; 809 810 NewPartEntry->IsPartitioned = FALSE; 811 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 812 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 813 814 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 815 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 816 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 817 818 NewPartEntry->FormatState = Unformatted; 819 820 InsertTailList(&DiskEntry->LogicalPartListHead, 821 &NewPartEntry->ListEntry); 822 823 return; 824 } 825 826 /* Start partition at head 1, cylinder 0 */ 827 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 828 LastSectorCount = 0ULL; 829 LastUnusedSectorCount = 0ULL; 830 831 Entry = DiskEntry->LogicalPartListHead.Flink; 832 while (Entry != &DiskEntry->LogicalPartListHead) 833 { 834 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 835 836 if (PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED || 837 PartEntry->SectorCount.QuadPart != 0ULL) 838 { 839 LastUnusedSectorCount = 840 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount); 841 842 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) && 843 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 844 { 845 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 846 847 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 848 HEAP_ZERO_MEMORY, 849 sizeof(PARTENTRY)); 850 if (NewPartEntry == NULL) 851 return; 852 853 NewPartEntry->DiskEntry = DiskEntry; 854 NewPartEntry->LogicalPartition = TRUE; 855 856 NewPartEntry->IsPartitioned = FALSE; 857 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 858 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 859 NewPartEntry->StartSector.QuadPart; 860 861 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 862 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 863 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 864 865 NewPartEntry->FormatState = Unformatted; 866 867 /* Insert the table into the list */ 868 InsertTailList(&PartEntry->ListEntry, 869 &NewPartEntry->ListEntry); 870 } 871 872 LastStartSector = PartEntry->StartSector.QuadPart; 873 LastSectorCount = PartEntry->SectorCount.QuadPart; 874 } 875 876 Entry = Entry->Flink; 877 } 878 879 /* Check for trailing unpartitioned disk space */ 880 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart) 881 { 882 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), 883 DiskEntry->SectorAlignment); 884 885 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 886 { 887 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 888 889 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 890 HEAP_ZERO_MEMORY, 891 sizeof(PARTENTRY)); 892 if (NewPartEntry == NULL) 893 return; 894 895 NewPartEntry->DiskEntry = DiskEntry; 896 NewPartEntry->LogicalPartition = TRUE; 897 898 NewPartEntry->IsPartitioned = FALSE; 899 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 900 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 901 NewPartEntry->StartSector.QuadPart; 902 903 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 904 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 905 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 906 907 NewPartEntry->FormatState = Unformatted; 908 909 /* Append the table to the list */ 910 InsertTailList(&DiskEntry->LogicalPartListHead, 911 &NewPartEntry->ListEntry); 912 } 913 } 914 } 915 916 DPRINT("ScanForUnpartitionedMbrDiskSpace() done\n"); 917} 918 919 920VOID 921ScanForUnpartitionedGptDiskSpace( 922 PDISKENTRY DiskEntry) 923{ 924 ULONGLONG LastStartSector; 925 ULONGLONG LastSectorCount; 926 ULONGLONG LastUnusedSectorCount; 927 PPARTENTRY PartEntry; 928 PPARTENTRY NewPartEntry; 929 PLIST_ENTRY Entry; 930 931 DPRINT("ScanForUnpartitionedGptDiskSpace()\n"); 932 933#ifdef DUMP_PARTITION_LIST 934 DumpPartitionList(DiskEntry); 935#endif 936 937 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 938 { 939 DPRINT("No partitions!\n"); 940 941 /* Create a partition table that represents the empty disk */ 942 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 943 HEAP_ZERO_MEMORY, 944 sizeof(PARTENTRY)); 945 if (NewPartEntry == NULL) 946 return; 947 948 NewPartEntry->DiskEntry = DiskEntry; 949 950 NewPartEntry->IsPartitioned = FALSE; 951 NewPartEntry->StartSector.QuadPart = DiskEntry->StartSector.QuadPart; 952 NewPartEntry->SectorCount.QuadPart = DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1; 953 954 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 955 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 956 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 957 958 NewPartEntry->FormatState = Unformatted; 959 960 InsertTailList(&DiskEntry->PrimaryPartListHead, 961 &NewPartEntry->ListEntry); 962 963#ifdef DUMP_PARTITION_LIST 964 DumpPartitionList(DiskEntry); 965#endif 966 967 return; 968 } 969 970 /* Start at the first usable sector */ 971 LastStartSector = DiskEntry->StartSector.QuadPart; 972 LastSectorCount = 0ULL; 973 LastUnusedSectorCount = 0ULL; 974 975 Entry = DiskEntry->PrimaryPartListHead.Flink; 976 while (Entry != &DiskEntry->PrimaryPartListHead) 977 { 978 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 979 980 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID) || 981 PartEntry->SectorCount.QuadPart != 0ULL) 982 { 983 LastUnusedSectorCount = 984 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 985 986 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 987 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 988 { 989 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 990 991 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 992 HEAP_ZERO_MEMORY, 993 sizeof(PARTENTRY)); 994 if (NewPartEntry == NULL) 995 return; 996 997 NewPartEntry->DiskEntry = DiskEntry; 998 999 NewPartEntry->IsPartitioned = FALSE; 1000 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 1001 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 1002 NewPartEntry->StartSector.QuadPart; 1003 1004 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 1005 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 1006 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 1007 1008 NewPartEntry->FormatState = Unformatted; 1009 1010 /* Insert the table into the list */ 1011 InsertTailList(&PartEntry->ListEntry, 1012 &NewPartEntry->ListEntry); 1013 } 1014 1015 LastStartSector = PartEntry->StartSector.QuadPart; 1016 LastSectorCount = PartEntry->SectorCount.QuadPart; 1017 } 1018 1019 Entry = Entry->Flink; 1020 } 1021 1022 /* Check for trailing unpartitioned disk space */ 1023 if ((LastStartSector + LastSectorCount) < DiskEntry->EndSector.QuadPart + 1) 1024 { 1025 LastUnusedSectorCount = AlignDown(DiskEntry->EndSector.QuadPart + 1 - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 1026 1027 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 1028 { 1029 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 1030 1031 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 1032 HEAP_ZERO_MEMORY, 1033 sizeof(PARTENTRY)); 1034 if (NewPartEntry == NULL) 1035 return; 1036 1037 NewPartEntry->DiskEntry = DiskEntry; 1038 1039 NewPartEntry->IsPartitioned = FALSE; 1040 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 1041 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 1042 NewPartEntry->StartSector.QuadPart; 1043 1044 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 1045 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 1046 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 1047 1048 NewPartEntry->FormatState = Unformatted; 1049 1050 /* Append the table to the list */ 1051 InsertTailList(&DiskEntry->PrimaryPartListHead, 1052 &NewPartEntry->ListEntry); 1053 } 1054 } 1055 1056#ifdef DUMP_PARTITION_LIST 1057 DumpPartitionList(DiskEntry); 1058#endif 1059 1060 DPRINT("ScanForUnpartitionedGptDiskSpace() done\n"); 1061} 1062 1063 1064VOID 1065ReadLayoutBuffer( 1066 _In_ HANDLE FileHandle, 1067 _In_ PDISKENTRY DiskEntry) 1068{ 1069 ULONG LayoutBufferSize; 1070 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer; 1071 IO_STATUS_BLOCK Iosb; 1072 NTSTATUS Status; 1073 1074 /* Allocate a layout buffer with 4 partition entries first */ 1075 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 1076 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX)); 1077 DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 1078 HEAP_ZERO_MEMORY, 1079 LayoutBufferSize); 1080 if (DiskEntry->LayoutBuffer == NULL) 1081 { 1082 DPRINT1("Failed to allocate the disk layout buffer!\n"); 1083 return; 1084 } 1085 1086 for (;;) 1087 { 1088 DPRINT("Buffer size: %lu\n", LayoutBufferSize); 1089 Status = NtDeviceIoControlFile(FileHandle, 1090 NULL, 1091 NULL, 1092 NULL, 1093 &Iosb, 1094 IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 1095 NULL, 1096 0, 1097 DiskEntry->LayoutBuffer, 1098 LayoutBufferSize); 1099 if (NT_SUCCESS(Status)) 1100 break; 1101 1102 if (Status != STATUS_BUFFER_TOO_SMALL) 1103 { 1104 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status); 1105 return; 1106 } 1107 1108 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION_EX); 1109 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 1110 HEAP_ZERO_MEMORY, 1111 DiskEntry->LayoutBuffer, 1112 LayoutBufferSize); 1113 if (NewLayoutBuffer == NULL) 1114 { 1115 DPRINT1("Failed to reallocate the disk layout buffer!\n"); 1116 return; 1117 } 1118 1119 DiskEntry->LayoutBuffer = NewLayoutBuffer; 1120 } 1121} 1122 1123 1124static 1125VOID 1126AddDiskToList( 1127 HANDLE FileHandle, 1128 ULONG DiskNumber) 1129{ 1130 DISK_GEOMETRY DiskGeometry; 1131 SCSI_ADDRESS ScsiAddress; 1132 PDISKENTRY DiskEntry; 1133 IO_STATUS_BLOCK Iosb; 1134 NTSTATUS Status; 1135 PPARTITION_SECTOR Mbr; 1136 PULONG Buffer; 1137 LARGE_INTEGER FileOffset; 1138 WCHAR Identifier[20]; 1139 ULONG Checksum; 1140 ULONG Signature; 1141 ULONG i; 1142 PLIST_ENTRY ListEntry; 1143 PBIOSDISKENTRY BiosDiskEntry; 1144 1145 Status = NtDeviceIoControlFile(FileHandle, 1146 NULL, 1147 NULL, 1148 NULL, 1149 &Iosb, 1150 IOCTL_DISK_GET_DRIVE_GEOMETRY, 1151 NULL, 1152 0, 1153 &DiskGeometry, 1154 sizeof(DISK_GEOMETRY)); 1155 if (!NT_SUCCESS(Status)) 1156 { 1157 return; 1158 } 1159 1160 if (DiskGeometry.MediaType != FixedMedia && 1161 DiskGeometry.MediaType != RemovableMedia) 1162 { 1163 return; 1164 } 1165 1166 Status = NtDeviceIoControlFile(FileHandle, 1167 NULL, 1168 NULL, 1169 NULL, 1170 &Iosb, 1171 IOCTL_SCSI_GET_ADDRESS, 1172 NULL, 1173 0, 1174 &ScsiAddress, 1175 sizeof(SCSI_ADDRESS)); 1176 if (!NT_SUCCESS(Status)) 1177 { 1178 return; 1179 } 1180 1181 PBYTE pBuffer = NULL; 1182 1183 pBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 1184 HEAP_ZERO_MEMORY, 1185 1024); 1186 1187 STORAGE_PROPERTY_QUERY StoragePropertyQuery; 1188 StoragePropertyQuery.PropertyId = StorageDeviceProperty; 1189 StoragePropertyQuery.QueryType = PropertyStandardQuery; 1190 Status = NtDeviceIoControlFile(FileHandle, 1191 NULL, 1192 NULL, 1193 NULL, 1194 &Iosb, 1195 IOCTL_STORAGE_QUERY_PROPERTY, 1196 &StoragePropertyQuery, 1197 sizeof(STORAGE_PROPERTY_QUERY), 1198 pBuffer, 1199 1024); 1200 if (!NT_SUCCESS(Status)) 1201 { 1202 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer); 1203 pBuffer = NULL; 1204 } 1205 1206 1207 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(), 1208 0, 1209 DiskGeometry.BytesPerSector); 1210 if (Mbr == NULL) 1211 { 1212 return; 1213 } 1214 1215 FileOffset.QuadPart = 0; 1216 Status = NtReadFile(FileHandle, 1217 NULL, 1218 NULL, 1219 NULL, 1220 &Iosb, 1221 (PVOID)Mbr, 1222 DiskGeometry.BytesPerSector, 1223 &FileOffset, 1224 NULL); 1225 if (!NT_SUCCESS(Status)) 1226 { 1227 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 1228 DPRINT1("NtReadFile failed, status=%x\n", Status); 1229 return; 1230 } 1231 Signature = Mbr->Signature; 1232 1233 /* Calculate the MBR checksum */ 1234 Checksum = 0; 1235 Buffer = (PULONG)Mbr; 1236 for (i = 0; i < 128; i++) 1237 { 1238 Checksum += Buffer[i]; 1239 } 1240 Checksum = ~Checksum + 1; 1241 1242 StringCchPrintfW(Identifier, ARRAYSIZE(Identifier), 1243 L"%08x-%08x-A", Checksum, Signature); 1244 DPRINT("Identifier: %S\n", Identifier); 1245 1246 DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(), 1247 HEAP_ZERO_MEMORY, 1248 sizeof(DISKENTRY)); 1249 if (DiskEntry == NULL) 1250 { 1251 if (pBuffer) 1252 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer); 1253 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 1254 return; 1255 } 1256 1257 if (pBuffer) 1258 { 1259 PSTORAGE_DESCRIPTOR_HEADER pDescriptorHeader; 1260 1261 pDescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)pBuffer; 1262 DPRINT("DescriptorHeader.Size %lu\n", pDescriptorHeader->Size); 1263 1264 if (pDescriptorHeader->Size <= 1024) 1265 { 1266 PSTORAGE_DEVICE_DESCRIPTOR pDeviceDescriptor; 1267 pDeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)pBuffer; 1268 DPRINT("VendorIdOffset %lu\n", pDeviceDescriptor->VendorIdOffset); 1269 DPRINT("ProductIdOffset %lu\n", pDeviceDescriptor->ProductIdOffset); 1270 DPRINT("ProductRevisionOffset %lu\n", pDeviceDescriptor->ProductRevisionOffset); 1271 DPRINT("SerialNumberOffset %lu\n", pDeviceDescriptor->SerialNumberOffset); 1272 DPRINT("BusType: %u\n", pDeviceDescriptor->BusType); 1273 if (pDeviceDescriptor->VendorIdOffset) 1274 { 1275 DPRINT("Vendor: %s\n", (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset)); 1276 } 1277 1278 if (pDeviceDescriptor->ProductIdOffset) 1279 { 1280 DPRINT("Product: %s\n", (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset)); 1281 } 1282 1283 INT VendorLength = 0, ProductLength = 0; 1284 PWSTR VendorBuffer = NULL, ProductBuffer = NULL; 1285 1286 if (pDeviceDescriptor->VendorIdOffset) 1287 { 1288 VendorLength = MultiByteToWideChar(437, 1289 0, 1290 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset), 1291 -1, 1292 NULL, 1293 0); 1294 VendorBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 1295 HEAP_ZERO_MEMORY, 1296 VendorLength * sizeof(WCHAR)); 1297 if (VendorBuffer) 1298 MultiByteToWideChar(437, 1299 0, 1300 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset), 1301 -1, 1302 VendorBuffer, 1303 VendorLength); 1304 } 1305 1306 if (pDeviceDescriptor->ProductIdOffset) 1307 { 1308 ProductLength = MultiByteToWideChar(437, 1309 0, 1310 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset), 1311 -1, 1312 NULL, 1313 0); 1314 1315 ProductBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 1316 HEAP_ZERO_MEMORY, 1317 ProductLength * sizeof(WCHAR)); 1318 if (ProductBuffer) 1319 MultiByteToWideChar(437, 1320 0, 1321 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset), 1322 -1, 1323 ProductBuffer, 1324 ProductLength); 1325 } 1326 1327 DiskEntry->Description = RtlAllocateHeap(RtlGetProcessHeap(), 1328 HEAP_ZERO_MEMORY, 1329 (VendorLength + ProductLength + 2) * sizeof(WCHAR)); 1330 if (VendorBuffer) 1331 wcscat(DiskEntry->Description, VendorBuffer); 1332 1333 if ((VendorLength > 0) && (ProductLength > 0)) 1334 wcscat(DiskEntry->Description, L" "); 1335 1336 if (ProductBuffer) 1337 wcscat(DiskEntry->Description, ProductBuffer); 1338 1339 DiskEntry->BusType = pDeviceDescriptor->BusType; 1340 1341 if (VendorBuffer) 1342 RtlFreeHeap(RtlGetProcessHeap(), 0, VendorBuffer); 1343 1344 if (ProductBuffer) 1345 RtlFreeHeap(RtlGetProcessHeap(), 0, ProductBuffer); 1346 } 1347 1348 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer); 1349 } 1350 1351// DiskEntry->Checksum = Checksum; 1352// DiskEntry->Signature = Signature; 1353 DiskEntry->BiosFound = FALSE; 1354 1355 /* Check the disk partition style */ 1356 if (Mbr->Magic != MBR_MAGIC) 1357 { 1358 DPRINT("Partition style: RAW\n"); 1359 DiskEntry->PartitionStyle = PARTITION_STYLE_RAW; 1360 } 1361 else 1362 { 1363 if (Mbr->Partition[0].PartitionType == PARTITION_GPT) 1364 { 1365 DPRINT("Partition style: GPT\n"); 1366 DiskEntry->PartitionStyle = PARTITION_STYLE_GPT; 1367 } 1368 else 1369 { 1370 DPRINT("Partition style: MBR\n"); 1371 DiskEntry->PartitionStyle = PARTITION_STYLE_MBR; 1372 } 1373 } 1374 1375 /* Free Mbr sector buffer */ 1376 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 1377 1378 ListEntry = BiosDiskListHead.Flink; 1379 while (ListEntry != &BiosDiskListHead) 1380 { 1381 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 1382 /* FIXME: 1383 * Compare the size from bios and the reported size from driver. 1384 * If we have more than one disk with a zero or with the same signatur 1385 * we must create new signatures and reboot. After the reboot, 1386 * it is possible to identify the disks. 1387 */ 1388 if (BiosDiskEntry->Signature == Signature && 1389 BiosDiskEntry->Checksum == Checksum && 1390 !BiosDiskEntry->Recognized) 1391 { 1392 if (!DiskEntry->BiosFound) 1393 { 1394 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber; 1395 DiskEntry->BiosFound = TRUE; 1396 BiosDiskEntry->Recognized = TRUE; 1397 } 1398 else 1399 { 1400 } 1401 } 1402 ListEntry = ListEntry->Flink; 1403 } 1404 1405 if (!DiskEntry->BiosFound) 1406 { 1407#if 0 1408 RtlFreeHeap(ProcessHeap, 0, DiskEntry); 1409 return; 1410#else 1411 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber); 1412#endif 1413 } 1414 1415 InitializeListHead(&DiskEntry->PrimaryPartListHead); 1416 InitializeListHead(&DiskEntry->LogicalPartListHead); 1417 1418 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart; 1419 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder; 1420 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack; 1421 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector; 1422 1423 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders); 1424 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder); 1425 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack); 1426 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector); 1427 1428 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 1429 (ULONGLONG)DiskGeometry.TracksPerCylinder * 1430 (ULONGLONG)DiskGeometry.SectorsPerTrack; 1431 1432// DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack; 1433// DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder; 1434 DiskEntry->SectorAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector; 1435 DiskEntry->CylinderAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector; 1436 1437 DPRINT("SectorCount: %I64u\n", DiskEntry->SectorCount); 1438 DPRINT("SectorAlignment: %lu\n", DiskEntry->SectorAlignment); 1439 DPRINT("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment); 1440 1441 DiskEntry->DiskNumber = DiskNumber; 1442 DiskEntry->Port = ScsiAddress.PortNumber; 1443 DiskEntry->PathId = ScsiAddress.PathId; 1444 DiskEntry->TargetId = ScsiAddress.TargetId; 1445 DiskEntry->Lun = ScsiAddress.Lun; 1446 1447 GetDriverName(DiskEntry); 1448 1449 InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber); 1450 1451 ReadLayoutBuffer(FileHandle, DiskEntry); 1452 1453 DPRINT("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount); 1454 1455#ifdef DUMP_PARTITION_TABLE 1456 DumpPartitionTable(DiskEntry); 1457#endif 1458 1459 if (DiskEntry->PartitionStyle == PARTITION_STYLE_MBR) 1460 { 1461 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 && 1462 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 && 1463 DiskEntry->LayoutBuffer->PartitionEntry[0].Mbr.PartitionType != 0) 1464 { 1465 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0) 1466 { 1467 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack); 1468 } 1469 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0) 1470 { 1471 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1472 } 1473 else 1474 { 1475 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart); 1476 } 1477 } 1478 else 1479 { 1480 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1481 } 1482 1483 /* Calculate the number of usable sectors */ 1484 /* Limit the number of usable sectors to 2^32 */ 1485 DiskEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment; 1486 DiskEntry->EndSector.QuadPart = min(DiskEntry->SectorCount.QuadPart, 0x100000000) - 1; 1487 1488 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1489 { 1490 DiskEntry->NewDisk = TRUE; 1491 DiskEntry->LayoutBuffer->PartitionCount = 4; 1492 1493 for (i = 0; i < 4; i++) 1494 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1495 } 1496 else 1497 { 1498 for (i = 0; i < 4; i++) 1499 { 1500 AddMbrPartitionToDisk(DiskNumber, DiskEntry, i, FALSE); 1501 } 1502 1503 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4) 1504 { 1505 AddMbrPartitionToDisk(DiskNumber, DiskEntry, i, TRUE); 1506 } 1507 } 1508 1509 ScanForUnpartitionedMbrDiskSpace(DiskEntry); 1510 } 1511 else if (DiskEntry->PartitionStyle == PARTITION_STYLE_GPT) 1512 { 1513 /* Calculate the number of usable sectors */ 1514 DiskEntry->StartSector.QuadPart = AlignDown(DiskEntry->LayoutBuffer->Gpt.StartingUsableOffset.QuadPart / DiskEntry->BytesPerSector, 1515 DiskEntry->SectorAlignment) + (ULONGLONG)DiskEntry->SectorAlignment; 1516 DiskEntry->EndSector.QuadPart = AlignDown(DiskEntry->StartSector.QuadPart + (DiskEntry->LayoutBuffer->Gpt.UsableLength.QuadPart / DiskEntry->BytesPerSector) - 1, 1517 DiskEntry->SectorAlignment); 1518 1519 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1520 { 1521 DiskEntry->NewDisk = TRUE; 1522 } 1523 else 1524 { 1525 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++) 1526 { 1527 AddGptPartitionToDisk(DiskNumber, DiskEntry, i); 1528 } 1529 } 1530 1531 ScanForUnpartitionedGptDiskSpace(DiskEntry); 1532 } 1533} 1534 1535 1536NTSTATUS 1537CreatePartitionList(VOID) 1538{ 1539 OBJECT_ATTRIBUTES ObjectAttributes; 1540 SYSTEM_DEVICE_INFORMATION Sdi; 1541 IO_STATUS_BLOCK Iosb; 1542 ULONG ReturnSize; 1543 NTSTATUS Status; 1544 ULONG DiskNumber; 1545 WCHAR Buffer[MAX_PATH]; 1546 UNICODE_STRING Name; 1547 HANDLE FileHandle; 1548 1549 CurrentDisk = NULL; 1550 CurrentPartition = NULL; 1551 1552// BootDisk = NULL; 1553// BootPartition = NULL; 1554 1555// TempDisk = NULL; 1556// TempPartition = NULL; 1557// FormatState = Start; 1558 1559 InitializeListHead(&DiskListHead); 1560 InitializeListHead(&BiosDiskListHead); 1561 1562 EnumerateBiosDiskEntries(); 1563 1564 Status = NtQuerySystemInformation(SystemDeviceInformation, 1565 &Sdi, 1566 sizeof(SYSTEM_DEVICE_INFORMATION), 1567 &ReturnSize); 1568 if (!NT_SUCCESS(Status)) 1569 { 1570 return Status; 1571 } 1572 1573 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) 1574 { 1575 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 1576 L"\\Device\\Harddisk%d\\Partition0", 1577 DiskNumber); 1578 1579 RtlInitUnicodeString(&Name, 1580 Buffer); 1581 1582 InitializeObjectAttributes(&ObjectAttributes, 1583 &Name, 1584 0, 1585 NULL, 1586 NULL); 1587 1588 Status = NtOpenFile(&FileHandle, 1589 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 1590 &ObjectAttributes, 1591 &Iosb, 1592 FILE_SHARE_READ, 1593 FILE_SYNCHRONOUS_IO_NONALERT); 1594 if (NT_SUCCESS(Status)) 1595 { 1596 AddDiskToList(FileHandle, DiskNumber); 1597 1598 NtClose(FileHandle); 1599 } 1600 } 1601 1602// UpdateDiskSignatures(List); 1603 1604// AssignDriveLetters(List); 1605 1606 return STATUS_SUCCESS; 1607} 1608 1609 1610VOID 1611DestroyPartitionList(VOID) 1612{ 1613 PDISKENTRY DiskEntry; 1614 PBIOSDISKENTRY BiosDiskEntry; 1615 PPARTENTRY PartEntry; 1616 PLIST_ENTRY Entry; 1617 1618 CurrentDisk = NULL; 1619 CurrentPartition = NULL; 1620 1621 /* Release disk and partition info */ 1622 while (!IsListEmpty(&DiskListHead)) 1623 { 1624 Entry = RemoveHeadList(&DiskListHead); 1625 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1626 1627 /* Release driver name */ 1628 RtlFreeUnicodeString(&DiskEntry->DriverName); 1629 1630 /* Release primary partition list */ 1631 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1632 { 1633 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead); 1634 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1635 1636 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1637 } 1638 1639 /* Release logical partition list */ 1640 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 1641 { 1642 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 1643 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1644 1645 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1646 } 1647 1648 /* Release layout buffer */ 1649 if (DiskEntry->LayoutBuffer != NULL) 1650 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer); 1651 1652 if (DiskEntry->Description != NULL) 1653 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->Description); 1654 1655 if (DiskEntry->Location != NULL) 1656 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->Location); 1657 1658 /* Release disk entry */ 1659 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry); 1660 } 1661 1662 /* Release the bios disk info */ 1663 while (!IsListEmpty(&BiosDiskListHead)) 1664 { 1665 Entry = RemoveHeadList(&BiosDiskListHead); 1666 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry); 1667 1668 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 1669 } 1670} 1671 1672 1673static 1674VOID 1675GetVolumeExtents( 1676 _In_ HANDLE VolumeHandle, 1677 _In_ PVOLENTRY VolumeEntry) 1678{ 1679 DWORD dwBytesReturned = 0, dwLength, i; 1680 PVOLUME_DISK_EXTENTS pExtents; 1681 BOOL bResult; 1682 DWORD dwError; 1683 1684 dwLength = sizeof(VOLUME_DISK_EXTENTS); 1685 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); 1686 if (pExtents == NULL) 1687 return; 1688 1689 bResult = DeviceIoControl(VolumeHandle, 1690 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 1691 NULL, 1692 0, 1693 pExtents, 1694 dwLength, 1695 &dwBytesReturned, 1696 NULL); 1697 if (!bResult) 1698 { 1699 dwError = GetLastError(); 1700 1701 if (dwError != ERROR_MORE_DATA) 1702 { 1703 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1704 return; 1705 } 1706 else 1707 { 1708 dwLength = sizeof(VOLUME_DISK_EXTENTS) + ((pExtents->NumberOfDiskExtents - 1) * sizeof(DISK_EXTENT)); 1709 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1710 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); 1711 if (pExtents == NULL) 1712 { 1713 return; 1714 } 1715 1716 bResult = DeviceIoControl(VolumeHandle, 1717 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 1718 NULL, 1719 0, 1720 pExtents, 1721 dwLength, 1722 &dwBytesReturned, 1723 NULL); 1724 if (!bResult) 1725 { 1726 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1727 return; 1728 } 1729 } 1730 } 1731 1732 for (i = 0; i < pExtents->NumberOfDiskExtents; i++) 1733 VolumeEntry->Size.QuadPart += pExtents->Extents[i].ExtentLength.QuadPart; 1734 1735 VolumeEntry->pExtents = pExtents; 1736} 1737 1738 1739static 1740VOID 1741GetVolumeType( 1742 _In_ HANDLE VolumeHandle, 1743 _In_ PVOLENTRY VolumeEntry) 1744{ 1745 FILE_FS_DEVICE_INFORMATION DeviceInfo; 1746 IO_STATUS_BLOCK IoStatusBlock; 1747 NTSTATUS Status; 1748 1749 Status = NtQueryVolumeInformationFile(VolumeHandle, 1750 &IoStatusBlock, 1751 &DeviceInfo, 1752 sizeof(FILE_FS_DEVICE_INFORMATION), 1753 FileFsDeviceInformation); 1754 if (!NT_SUCCESS(Status)) 1755 return; 1756 1757 switch (DeviceInfo.DeviceType) 1758 { 1759 case FILE_DEVICE_CD_ROM: 1760 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 1761 VolumeEntry->VolumeType = VOLUME_TYPE_CDROM; 1762 break; 1763 1764 case FILE_DEVICE_DISK: 1765 case FILE_DEVICE_DISK_FILE_SYSTEM: 1766 if (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA) 1767 VolumeEntry->VolumeType = VOLUME_TYPE_REMOVABLE; 1768 else 1769 VolumeEntry->VolumeType = VOLUME_TYPE_PARTITION; 1770 break; 1771 1772 default: 1773 VolumeEntry->VolumeType = VOLUME_TYPE_UNKNOWN; 1774 break; 1775 } 1776} 1777 1778 1779static 1780VOID 1781GetVolumeSize( 1782 _In_ HANDLE VolumeHandle, 1783 _In_ PVOLENTRY VolumeEntry) 1784{ 1785 FILE_FS_FULL_SIZE_INFORMATION SizeInfo; 1786 FILE_FS_FULL_SIZE_INFORMATION FullSizeInfo; 1787 IO_STATUS_BLOCK IoStatusBlock; 1788 NTSTATUS Status; 1789 1790 ZeroMemory(&FullSizeInfo, sizeof(FullSizeInfo)); 1791 Status = NtQueryVolumeInformationFile(VolumeHandle, 1792 &IoStatusBlock, 1793 &FullSizeInfo, 1794 sizeof(FILE_FS_FULL_SIZE_INFORMATION), 1795 FileFsFullSizeInformation); 1796 if (NT_SUCCESS(Status)) 1797 { 1798 DPRINT("FullSizeInfo.TotalAllocationUnits %I64u\n", FullSizeInfo.TotalAllocationUnits.QuadPart); 1799 DPRINT("FullSizeInfo.SectorsPerAllocationUnit %lu\n", FullSizeInfo.SectorsPerAllocationUnit); 1800 DPRINT("FullSizeInfo.BytesPerSector %lu\n", FullSizeInfo.BytesPerSector); 1801 1802 VolumeEntry->TotalAllocationUnits.QuadPart = FullSizeInfo.TotalAllocationUnits.QuadPart; 1803 VolumeEntry->SectorsPerAllocationUnit = FullSizeInfo.SectorsPerAllocationUnit; 1804 VolumeEntry->BytesPerSector = FullSizeInfo.BytesPerSector; 1805 } 1806 else 1807 { 1808 ZeroMemory(&SizeInfo, sizeof(SizeInfo)); 1809 Status = NtQueryVolumeInformationFile(VolumeHandle, 1810 &IoStatusBlock, 1811 &SizeInfo, 1812 sizeof(FILE_FS_SIZE_INFORMATION), 1813 FileFsSizeInformation); 1814 if (NT_SUCCESS(Status)) 1815 { 1816 DPRINT("SizeInfo.TotalAllocationUnits %I64u\n", SizeInfo.TotalAllocationUnits.QuadPart); 1817 DPRINT("SizeInfo.SectorsPerAllocationUnit %lu\n", SizeInfo.SectorsPerAllocationUnit); 1818 DPRINT("SizeInfo.BytesPerSector %lu\n", SizeInfo.BytesPerSector); 1819 1820 VolumeEntry->TotalAllocationUnits.QuadPart = SizeInfo.TotalAllocationUnits.QuadPart; 1821 VolumeEntry->SectorsPerAllocationUnit = SizeInfo.SectorsPerAllocationUnit; 1822 VolumeEntry->BytesPerSector = SizeInfo.BytesPerSector; 1823 } 1824 else 1825 { 1826 DPRINT("GetVolumeSize() failed!\n"); 1827 } 1828 } 1829} 1830 1831 1832static 1833PDISKENTRY 1834GetDiskForVolume( 1835 _In_ PVOLENTRY VolumeEntry) 1836{ 1837 PLIST_ENTRY Entry; 1838 PDISKENTRY DiskEntry; 1839 INT i; 1840 1841 DPRINT("GetDiskFromVolume(%p)\n", VolumeEntry); 1842 1843 DPRINT("Extents: %p\n", VolumeEntry->pExtents); 1844 if (VolumeEntry->pExtents == NULL) 1845 return NULL; 1846 1847 DPRINT("Extents: %lu\n", VolumeEntry->pExtents->NumberOfDiskExtents); 1848 1849 Entry = DiskListHead.Flink; 1850 while (Entry != &DiskListHead) 1851 { 1852 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1853 1854 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++) 1855 { 1856 DPRINT("DiskNumber: %lu -- %lu\n", VolumeEntry->pExtents->Extents[i].DiskNumber, DiskEntry->DiskNumber); 1857 if (VolumeEntry->pExtents->Extents[i].DiskNumber == DiskEntry->DiskNumber) 1858 return DiskEntry; 1859 } 1860 1861 Entry = Entry->Flink; 1862 } 1863 1864 return NULL; 1865} 1866 1867 1868static 1869PPARTENTRY 1870GetPartitionForVolume( 1871 _In_ PVOLENTRY VolumeEntry) 1872{ 1873 PLIST_ENTRY Entry1, Entry2; 1874 PDISKENTRY DiskEntry; 1875 PPARTENTRY PartEntry; 1876 INT i; 1877 1878 DPRINT("GetPartitionFromVolume(%p)\n", VolumeEntry); 1879 1880 DPRINT("Extents: %p\n", VolumeEntry->pExtents); 1881 if (VolumeEntry->pExtents == NULL) 1882 return NULL; 1883 1884 DPRINT("Extents: %lu\n", VolumeEntry->pExtents->NumberOfDiskExtents); 1885 1886 Entry1 = DiskListHead.Flink; 1887 while (Entry1 != &DiskListHead) 1888 { 1889 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry); 1890 1891 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++) 1892 { 1893 DPRINT("DiskNumber: %lu -- %lu\n", VolumeEntry->pExtents->Extents[i].DiskNumber, DiskEntry->DiskNumber); 1894 if (VolumeEntry->pExtents->Extents[i].DiskNumber == DiskEntry->DiskNumber) 1895 { 1896 1897 Entry2 = DiskEntry->PrimaryPartListHead.Flink; 1898 while (Entry2 != &DiskEntry->PrimaryPartListHead) 1899 { 1900 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 1901 1902 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) && 1903 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector)) 1904 return PartEntry; 1905 1906 Entry2 = Entry2->Flink; 1907 } 1908 1909 Entry2 = DiskEntry->LogicalPartListHead.Flink; 1910 while (Entry2 != &DiskEntry->LogicalPartListHead) 1911 { 1912 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 1913 1914 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) && 1915 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector)) 1916 return PartEntry; 1917 1918 Entry2 = Entry2->Flink; 1919 } 1920 } 1921 } 1922 1923 Entry1 = Entry1->Flink; 1924 } 1925 1926 return NULL; 1927} 1928 1929 1930static 1931VOID 1932IsVolumeSystem( 1933 _In_ PVOLENTRY VolumeEntry) 1934{ 1935 WCHAR szSystemPartition[MAX_PATH]; 1936 PPARTENTRY PartEntry; 1937 HKEY hKey; 1938 DWORD dwError, dwLength; 1939 1940 DPRINT("IsVolumeSystem()\n"); 1941 1942 VolumeEntry->IsSystem = FALSE; 1943 1944 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1945 L"SYSTEM\\Setup", 1946 0, 1947 KEY_READ, 1948 &hKey); 1949 if (dwError != ERROR_SUCCESS) 1950 { 1951 DPRINT1("\n"); 1952 return; 1953 } 1954 1955 dwLength = sizeof(szSystemPartition); 1956 dwError = RegQueryValueExW(hKey, 1957 L"SystemPartition", 1958 NULL, 1959 NULL, 1960 (PBYTE)szSystemPartition, 1961 &dwLength); 1962 RegCloseKey(hKey); 1963 1964 if (dwError != ERROR_SUCCESS) 1965 { 1966 DPRINT1("\n"); 1967 return; 1968 } 1969 1970 DPRINT("SystemPartition: %S\n", szSystemPartition); 1971 DPRINT("DeviceName: %S\n", VolumeEntry->DeviceName); 1972 1973 if (_wcsnicmp(szSystemPartition, VolumeEntry->DeviceName, wcslen(szSystemPartition)) == 0) 1974 { 1975 VolumeEntry->IsSystem = TRUE; 1976 1977 PartEntry = GetPartitionForVolume(VolumeEntry); 1978 if (PartEntry) 1979 PartEntry->IsSystem = TRUE; 1980 } 1981} 1982 1983 1984static 1985VOID 1986IsVolumeBoot( 1987 _In_ PVOLENTRY VolumeEntry) 1988{ 1989 WCHAR szSystemDir[MAX_PATH]; 1990 PDISKENTRY DiskEntry; 1991 PPARTENTRY PartEntry; 1992 1993 DPRINT("IsVolumeBoot()\n"); 1994 1995 VolumeEntry->IsBoot = FALSE; 1996 1997 if (VolumeEntry->DriveLetter == UNICODE_NULL) 1998 return; 1999 2000 GetSystemDirectoryW(szSystemDir, 2001 ARRAYSIZE(szSystemDir)); 2002 2003 DPRINT("SystemDirectory: %S\n", szSystemDir); 2004 DPRINT("DriveLetter: %C\n", VolumeEntry->DriveLetter); 2005 2006 if (szSystemDir[0] == VolumeEntry->DriveLetter) 2007 { 2008 VolumeEntry->IsBoot = TRUE; 2009 2010 PartEntry = GetPartitionForVolume(VolumeEntry); 2011 if (PartEntry) 2012 PartEntry->IsBoot = TRUE; 2013 2014 DiskEntry = GetDiskForVolume(VolumeEntry); 2015 if (DiskEntry) 2016 DiskEntry->IsBoot = TRUE; 2017 } 2018} 2019 2020 2021static 2022VOID 2023AddVolumeToList( 2024 ULONG ulVolumeNumber, 2025 PWSTR pszVolumeName) 2026{ 2027 PVOLENTRY VolumeEntry; 2028 HANDLE VolumeHandle; 2029 2030 DWORD dwError, dwLength; 2031 WCHAR szPathNames[MAX_PATH + 1]; 2032 WCHAR szVolumeName[MAX_PATH + 1]; 2033 WCHAR szFilesystem[MAX_PATH + 1]; 2034 2035 DWORD CharCount = 0; 2036 size_t Index = 0; 2037 2038 OBJECT_ATTRIBUTES ObjectAttributes; 2039 UNICODE_STRING Name; 2040 IO_STATUS_BLOCK Iosb; 2041 NTSTATUS Status; 2042 2043 DPRINT("AddVolumeToList(%S)\n", pszVolumeName); 2044 2045 VolumeEntry = RtlAllocateHeap(RtlGetProcessHeap(), 2046 HEAP_ZERO_MEMORY, 2047 sizeof(VOLENTRY)); 2048 if (VolumeEntry == NULL) 2049 return; 2050 2051 VolumeEntry->VolumeNumber = ulVolumeNumber; 2052 wcscpy(VolumeEntry->VolumeName, pszVolumeName); 2053 2054 Index = wcslen(pszVolumeName) - 1; 2055 2056 pszVolumeName[Index] = L'\0'; 2057 2058 CharCount = QueryDosDeviceW(&pszVolumeName[4], VolumeEntry->DeviceName, ARRAYSIZE(VolumeEntry->DeviceName)); 2059 2060 pszVolumeName[Index] = L'\\'; 2061 2062 if (CharCount == 0) 2063 { 2064 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 2065 return; 2066 } 2067 2068 DPRINT("DeviceName: %S\n", VolumeEntry->DeviceName); 2069 2070 RtlInitUnicodeString(&Name, VolumeEntry->DeviceName); 2071 2072 InitializeObjectAttributes(&ObjectAttributes, 2073 &Name, 2074 0, 2075 NULL, 2076 NULL); 2077 2078 Status = NtOpenFile(&VolumeHandle, 2079 SYNCHRONIZE, 2080 &ObjectAttributes, 2081 &Iosb, 2082 0, 2083 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); 2084 if (NT_SUCCESS(Status)) 2085 { 2086 GetVolumeType(VolumeHandle, VolumeEntry); 2087 GetVolumeExtents(VolumeHandle, VolumeEntry); 2088 GetVolumeSize(VolumeHandle, VolumeEntry); 2089 NtClose(VolumeHandle); 2090 } 2091 2092 if (GetVolumeInformationW(pszVolumeName, 2093 szVolumeName, 2094 MAX_PATH + 1, 2095 &VolumeEntry->SerialNumber, 2096 NULL, 2097 NULL, 2098 szFilesystem, 2099 MAX_PATH + 1)) 2100 { 2101 VolumeEntry->pszLabel = RtlAllocateHeap(RtlGetProcessHeap(), 2102 0, 2103 (wcslen(szVolumeName) + 1) * sizeof(WCHAR)); 2104 if (VolumeEntry->pszLabel) 2105 wcscpy(VolumeEntry->pszLabel, szVolumeName); 2106 2107 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(), 2108 0, 2109 (wcslen(szFilesystem) + 1) * sizeof(WCHAR)); 2110 if (VolumeEntry->pszFilesystem) 2111 wcscpy(VolumeEntry->pszFilesystem, szFilesystem); 2112 } 2113 else 2114 { 2115 dwError = GetLastError(); 2116 if (dwError == ERROR_UNRECOGNIZED_VOLUME) 2117 { 2118 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(), 2119 0, 2120 (3 + 1) * sizeof(WCHAR)); 2121 if (VolumeEntry->pszFilesystem) 2122 wcscpy(VolumeEntry->pszFilesystem, L"RAW"); 2123 VolumeEntry->SerialNumber = 0; 2124 VolumeEntry->SectorsPerAllocationUnit = 1; 2125 VolumeEntry->BytesPerSector = 512; 2126 VolumeEntry->VolumeType = VOLUME_TYPE_PARTITION; 2127 } 2128 } 2129 2130 if (GetVolumePathNamesForVolumeNameW(pszVolumeName, 2131 szPathNames, 2132 ARRAYSIZE(szPathNames), 2133 &dwLength)) 2134 { 2135 INT nPathLength; 2136 PWSTR pszPath = szPathNames; 2137 while (*pszPath != UNICODE_NULL) 2138 { 2139 DPRINT("PathName: %S\n", pszPath); 2140 nPathLength = wcslen(pszPath); 2141 if ((nPathLength == 3) && (iswalpha(pszPath[0])) && 2142 (pszPath[1] == L':') && (pszPath[2] == L'\\')) 2143 VolumeEntry->DriveLetter = pszPath[0]; 2144 2145 pszPath += (nPathLength + 1); 2146 } 2147 } 2148 2149 IsVolumeSystem(VolumeEntry); 2150 IsVolumeBoot(VolumeEntry); 2151 2152 InsertTailList(&VolumeListHead, 2153 &VolumeEntry->ListEntry); 2154} 2155 2156 2157NTSTATUS 2158CreateVolumeList(VOID) 2159{ 2160 HANDLE hVolume = INVALID_HANDLE_VALUE; 2161 WCHAR szVolumeName[MAX_PATH]; 2162 ULONG ulVolumeNumber = 0; 2163 BOOL Success; 2164 2165 CurrentVolume = NULL; 2166 2167 InitializeListHead(&VolumeListHead); 2168 2169 hVolume = FindFirstVolumeW(szVolumeName, ARRAYSIZE(szVolumeName)); 2170 if (hVolume == INVALID_HANDLE_VALUE) 2171 { 2172 2173 return STATUS_UNSUCCESSFUL; 2174 } 2175 2176 AddVolumeToList(ulVolumeNumber++, szVolumeName); 2177 2178 for (;;) 2179 { 2180 Success = FindNextVolumeW(hVolume, szVolumeName, ARRAYSIZE(szVolumeName)); 2181 if (!Success) 2182 { 2183 break; 2184 } 2185 2186 AddVolumeToList(ulVolumeNumber++, szVolumeName); 2187 } 2188 2189 FindVolumeClose(hVolume); 2190 2191 return STATUS_SUCCESS; 2192} 2193 2194 2195VOID 2196DestroyVolumeList(VOID) 2197{ 2198 PLIST_ENTRY Entry; 2199 PVOLENTRY VolumeEntry; 2200 2201 CurrentVolume = NULL; 2202 2203 /* Release disk and partition info */ 2204 while (!IsListEmpty(&VolumeListHead)) 2205 { 2206 Entry = RemoveHeadList(&VolumeListHead); 2207 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry); 2208 2209 if (VolumeEntry->pszLabel) 2210 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel); 2211 2212 if (VolumeEntry->pszFilesystem) 2213 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem); 2214 2215 if (VolumeEntry->pExtents) 2216 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents); 2217 2218 /* Release disk entry */ 2219 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 2220 } 2221} 2222 2223 2224NTSTATUS 2225WriteMbrPartitions( 2226 _In_ PDISKENTRY DiskEntry) 2227{ 2228 NTSTATUS Status; 2229 OBJECT_ATTRIBUTES ObjectAttributes; 2230 UNICODE_STRING Name; 2231 HANDLE FileHandle; 2232 IO_STATUS_BLOCK Iosb; 2233 ULONG BufferSize; 2234 PPARTITION_INFORMATION_EX PartitionInfo; 2235 ULONG PartitionCount; 2236 PLIST_ENTRY ListEntry; 2237 PPARTENTRY PartEntry; 2238 WCHAR DstPath[MAX_PATH]; 2239 2240 DPRINT("WriteMbrPartitions() Disk: %lu\n", DiskEntry->DiskNumber); 2241 2242 /* If the disk is not dirty, there is nothing to do */ 2243 if (!DiskEntry->Dirty) 2244 return STATUS_SUCCESS; 2245 2246 StringCchPrintfW(DstPath, ARRAYSIZE(DstPath), 2247 L"\\Device\\Harddisk%lu\\Partition0", 2248 DiskEntry->DiskNumber); 2249 RtlInitUnicodeString(&Name, DstPath); 2250 2251 InitializeObjectAttributes(&ObjectAttributes, 2252 &Name, 2253 OBJ_CASE_INSENSITIVE, 2254 NULL, 2255 NULL); 2256 2257 Status = NtOpenFile(&FileHandle, 2258 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2259 &ObjectAttributes, 2260 &Iosb, 2261 0, 2262 FILE_SYNCHRONOUS_IO_NONALERT); 2263 if (!NT_SUCCESS(Status)) 2264 { 2265 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); 2266 return Status; 2267 } 2268 2269 // 2270 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize 2271 // the disk in MBR or GPT format in case the disk was not initialized!! 2272 // For this we must ask the user which format to use. 2273 // 2274 2275 /* Save the original partition count to be restored later (see comment below) */ 2276 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 2277 2278 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */ 2279 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 2280 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX)); 2281 Status = NtDeviceIoControlFile(FileHandle, 2282 NULL, 2283 NULL, 2284 NULL, 2285 &Iosb, 2286 IOCTL_DISK_SET_DRIVE_LAYOUT_EX, 2287 DiskEntry->LayoutBuffer, 2288 BufferSize, 2289 DiskEntry->LayoutBuffer, 2290 BufferSize); 2291 NtClose(FileHandle); 2292 2293 /* 2294 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts 2295 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count, 2296 * where such a table is expected to enumerate up to 4 partitions: 2297 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 . 2298 * Due to this we need to restore the original PartitionCount number. 2299 */ 2300 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount; 2301 2302 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */ 2303 if (!NT_SUCCESS(Status)) 2304 { 2305 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status); 2306 return Status; 2307 } 2308 2309 /* Update the partition numbers */ 2310 2311 /* Update the primary partition table */ 2312 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2313 ListEntry != &DiskEntry->PrimaryPartListHead; 2314 ListEntry = ListEntry->Flink) 2315 { 2316 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2317 2318 if (PartEntry->IsPartitioned) 2319 { 2320 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED); 2321 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 2322 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 2323 } 2324 } 2325 2326 /* Update the logical partition table */ 2327 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2328 ListEntry != &DiskEntry->LogicalPartListHead; 2329 ListEntry = ListEntry->Flink) 2330 { 2331 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2332 2333 if (PartEntry->IsPartitioned) 2334 { 2335 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED); 2336 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 2337 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 2338 } 2339 } 2340 2341 /* The layout has been successfully updated, the disk is not dirty anymore */ 2342 DiskEntry->Dirty = FALSE; 2343 2344 return Status; 2345} 2346 2347 2348NTSTATUS 2349WriteGptPartitions( 2350 _In_ PDISKENTRY DiskEntry) 2351{ 2352 NTSTATUS Status; 2353 OBJECT_ATTRIBUTES ObjectAttributes; 2354 UNICODE_STRING Name; 2355 HANDLE FileHandle; 2356 IO_STATUS_BLOCK Iosb; 2357 ULONG BufferSize; 2358 WCHAR DstPath[MAX_PATH]; 2359 2360 DPRINT("WriteGptPartitions() Disk: %lu\n", DiskEntry->DiskNumber); 2361 2362 /* If the disk is not dirty, there is nothing to do */ 2363 if (!DiskEntry->Dirty) 2364 return STATUS_SUCCESS; 2365 2366 StringCchPrintfW(DstPath, ARRAYSIZE(DstPath), 2367 L"\\Device\\Harddisk%lu\\Partition0", 2368 DiskEntry->DiskNumber); 2369 RtlInitUnicodeString(&Name, DstPath); 2370 2371 InitializeObjectAttributes(&ObjectAttributes, 2372 &Name, 2373 OBJ_CASE_INSENSITIVE, 2374 NULL, 2375 NULL); 2376 2377 Status = NtOpenFile(&FileHandle, 2378 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2379 &ObjectAttributes, 2380 &Iosb, 2381 0, 2382 FILE_SYNCHRONOUS_IO_NONALERT); 2383 if (!NT_SUCCESS(Status)) 2384 { 2385 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); 2386 return Status; 2387 } 2388 2389 // 2390 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize 2391 // the disk in MBR or GPT format in case the disk was not initialized!! 2392 // For this we must ask the user which format to use. 2393 // 2394 2395 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */ 2396 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 2397 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX)); 2398 Status = NtDeviceIoControlFile(FileHandle, 2399 NULL, 2400 NULL, 2401 NULL, 2402 &Iosb, 2403 IOCTL_DISK_SET_DRIVE_LAYOUT_EX, 2404 DiskEntry->LayoutBuffer, 2405 BufferSize, 2406 DiskEntry->LayoutBuffer, 2407 BufferSize); 2408 NtClose(FileHandle); 2409 2410 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT_EX call succeeded */ 2411 if (!NT_SUCCESS(Status)) 2412 { 2413 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed (Status 0x%08lx)\n", Status); 2414 return Status; 2415 } 2416 2417 /* The layout has been successfully updated, the disk is not dirty anymore */ 2418 DiskEntry->Dirty = FALSE; 2419 2420 return Status; 2421} 2422 2423 2424static 2425BOOLEAN 2426IsEmptyLayoutEntry( 2427 IN PPARTITION_INFORMATION_EX PartitionInfo) 2428{ 2429 if (PartitionInfo->StartingOffset.QuadPart == 0 && 2430 PartitionInfo->PartitionLength.QuadPart == 0) 2431 { 2432 return TRUE; 2433 } 2434 2435 return FALSE; 2436} 2437 2438 2439static 2440BOOLEAN 2441IsSamePrimaryLayoutEntry( 2442 IN PPARTITION_INFORMATION_EX PartitionInfo, 2443 IN PDISKENTRY DiskEntry, 2444 IN PPARTENTRY PartEntry) 2445{ 2446 if ((PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector) && 2447 (PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)) 2448 { 2449 return TRUE; 2450 } 2451 2452 return FALSE; 2453} 2454 2455 2456ULONG 2457GetPrimaryPartitionCount( 2458 _In_ PDISKENTRY DiskEntry) 2459{ 2460 PLIST_ENTRY Entry; 2461 PPARTENTRY PartEntry; 2462 ULONG Count = 0; 2463 2464 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 2465 Entry != &DiskEntry->PrimaryPartListHead; 2466 Entry = Entry->Flink) 2467 { 2468 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 2469 if (PartEntry->IsPartitioned) 2470 Count++; 2471 } 2472 2473 return Count; 2474} 2475 2476 2477static 2478ULONG 2479GetLogicalPartitionCount( 2480 _In_ PDISKENTRY DiskEntry) 2481{ 2482 PLIST_ENTRY ListEntry; 2483 PPARTENTRY PartEntry; 2484 ULONG Count = 0; 2485 2486 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2487 ListEntry != &DiskEntry->LogicalPartListHead; 2488 ListEntry = ListEntry->Flink) 2489 { 2490 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2491 if (PartEntry->IsPartitioned) 2492 Count++; 2493 } 2494 2495 return Count; 2496} 2497 2498 2499static 2500BOOLEAN 2501ReAllocateLayoutBuffer( 2502 _In_ PDISKENTRY DiskEntry) 2503{ 2504 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer; 2505 ULONG NewPartitionCount; 2506 ULONG CurrentPartitionCount = 0; 2507 ULONG LayoutBufferSize; 2508 ULONG i; 2509 2510 DPRINT1("ReAllocateLayoutBuffer()\n"); 2511 2512 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4; 2513 2514 if (DiskEntry->LayoutBuffer) 2515 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 2516 2517 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n", 2518 CurrentPartitionCount, NewPartitionCount); 2519 2520 if (CurrentPartitionCount == NewPartitionCount) 2521 return TRUE; 2522 2523 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 2524 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX)); 2525 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 2526 HEAP_ZERO_MEMORY, 2527 DiskEntry->LayoutBuffer, 2528 LayoutBufferSize); 2529 if (NewLayoutBuffer == NULL) 2530 { 2531 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize); 2532 return FALSE; 2533 } 2534 2535 NewLayoutBuffer->PartitionCount = NewPartitionCount; 2536 2537 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */ 2538 if (NewPartitionCount > CurrentPartitionCount) 2539 { 2540 for (i = CurrentPartitionCount; i < NewPartitionCount; i++) 2541 { 2542 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 2543 } 2544 } 2545 2546 DiskEntry->LayoutBuffer = NewLayoutBuffer; 2547 2548 return TRUE; 2549} 2550 2551 2552VOID 2553UpdateMbrDiskLayout( 2554 _In_ PDISKENTRY DiskEntry) 2555{ 2556 PPARTITION_INFORMATION_EX PartitionInfo; 2557 PPARTITION_INFORMATION_EX LinkInfo = NULL; 2558 PLIST_ENTRY ListEntry; 2559 PPARTENTRY PartEntry; 2560 LARGE_INTEGER HiddenSectors64; 2561 ULONG Index; 2562 ULONG PartitionNumber = 1; 2563 2564 DPRINT("UpdateMbrDiskLayout()\n"); 2565 2566 /* Resize the layout buffer if necessary */ 2567 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE) 2568 { 2569 DPRINT("ReAllocateLayoutBuffer() failed.\n"); 2570 return; 2571 } 2572 2573 DiskEntry->LayoutBuffer->PartitionStyle = PARTITION_STYLE_MBR; 2574 2575 /* Update the primary partition table */ 2576 Index = 0; 2577 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2578 ListEntry != &DiskEntry->PrimaryPartListHead; 2579 ListEntry = ListEntry->Flink) 2580 { 2581 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2582 2583 if (PartEntry->IsPartitioned) 2584 { 2585 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED); 2586 2587 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2588 PartEntry->PartitionIndex = Index; 2589 2590 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2591 if (PartEntry->New) 2592 PartEntry->PartitionNumber = 0; 2593 2594 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->Mbr.PartitionType) ? PartitionNumber : 0); 2595 2596 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry)) 2597 { 2598 DPRINT1("Updating primary partition entry %lu\n", Index); 2599 2600 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR; 2601 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 2602 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2603 PartitionInfo->Mbr.HiddenSectors = PartEntry->StartSector.LowPart; 2604 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2605 PartitionInfo->Mbr.PartitionType = PartEntry->Mbr.PartitionType; 2606 PartitionInfo->Mbr.BootIndicator = PartEntry->Mbr.BootIndicator; 2607 PartitionInfo->Mbr.RecognizedPartition = IsRecognizedPartition(PartEntry->Mbr.PartitionType); 2608 PartitionInfo->RewritePartition = TRUE; 2609 } 2610 2611 if (!IsContainerPartition(PartEntry->Mbr.PartitionType)) 2612 PartitionNumber++; 2613 2614 Index++; 2615 } 2616 } 2617 2618 ASSERT(Index <= 4); 2619 2620 /* Update the logical partition table */ 2621 Index = 4; 2622 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 2623 ListEntry != &DiskEntry->LogicalPartListHead; 2624 ListEntry = ListEntry->Flink) 2625 { 2626 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2627 2628 if (PartEntry->IsPartitioned) 2629 { 2630 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED); 2631 2632 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2633 PartEntry->PartitionIndex = Index; 2634 2635 /* Reset the current partition number only for newly-created (unmounted) partitions */ 2636 if (PartEntry->New) 2637 PartEntry->PartitionNumber = 0; 2638 2639 PartEntry->OnDiskPartitionNumber = PartitionNumber; 2640 2641 DPRINT1("Updating logical partition entry %lu\n", Index); 2642 2643 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR; 2644 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 2645 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2646 PartitionInfo->Mbr.HiddenSectors = DiskEntry->SectorAlignment; 2647 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 2648 PartitionInfo->Mbr.PartitionType = PartEntry->Mbr.PartitionType; 2649 PartitionInfo->Mbr.BootIndicator = FALSE; 2650 PartitionInfo->Mbr.RecognizedPartition = IsRecognizedPartition(PartEntry->Mbr.PartitionType); 2651 PartitionInfo->RewritePartition = TRUE; 2652 2653 /* Fill the link entry of the previous partition entry */ 2654 if (LinkInfo != NULL) 2655 { 2656 LinkInfo->PartitionStyle = PARTITION_STYLE_MBR; 2657 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2658 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 2659 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart; 2660 LinkInfo->Mbr.HiddenSectors = HiddenSectors64.LowPart; 2661 LinkInfo->PartitionNumber = 0; 2662 LinkInfo->Mbr.PartitionType = PARTITION_EXTENDED; 2663 LinkInfo->Mbr.BootIndicator = FALSE; 2664 LinkInfo->Mbr.RecognizedPartition = FALSE; 2665 LinkInfo->RewritePartition = TRUE; 2666 } 2667 2668 /* Save a pointer to the link entry of the current partition entry */ 2669 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1]; 2670 2671 PartitionNumber++; 2672 Index += 4; 2673 } 2674 } 2675 2676 /* Wipe unused primary partition entries */ 2677 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++) 2678 { 2679 DPRINT1("Primary partition entry %lu\n", Index); 2680 2681 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2682 2683 if (!IsEmptyLayoutEntry(PartitionInfo)) 2684 { 2685 DPRINT1("Wiping primary partition entry %lu\n", Index); 2686 2687 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR; 2688 PartitionInfo->StartingOffset.QuadPart = 0; 2689 PartitionInfo->PartitionLength.QuadPart = 0; 2690 PartitionInfo->Mbr.HiddenSectors = 0; 2691 PartitionInfo->PartitionNumber = 0; 2692 PartitionInfo->Mbr.PartitionType = PARTITION_ENTRY_UNUSED; 2693 PartitionInfo->Mbr.BootIndicator = FALSE; 2694 PartitionInfo->Mbr.RecognizedPartition = FALSE; 2695 PartitionInfo->RewritePartition = TRUE; 2696 } 2697 } 2698 2699 /* Wipe unused logical partition entries */ 2700 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++) 2701 { 2702 if (Index % 4 >= 2) 2703 { 2704 DPRINT1("Logical partition entry %lu\n", Index); 2705 2706 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2707 2708 if (!IsEmptyLayoutEntry(PartitionInfo)) 2709 { 2710 DPRINT1("Wiping partition entry %lu\n", Index); 2711 2712 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR; 2713 PartitionInfo->StartingOffset.QuadPart = 0; 2714 PartitionInfo->PartitionLength.QuadPart = 0; 2715 PartitionInfo->Mbr.HiddenSectors = 0; 2716 PartitionInfo->PartitionNumber = 0; 2717 PartitionInfo->Mbr.PartitionType = PARTITION_ENTRY_UNUSED; 2718 PartitionInfo->Mbr.BootIndicator = FALSE; 2719 PartitionInfo->Mbr.RecognizedPartition = FALSE; 2720 PartitionInfo->RewritePartition = TRUE; 2721 } 2722 } 2723 } 2724 2725 DiskEntry->Dirty = TRUE; 2726} 2727 2728 2729VOID 2730UpdateGptDiskLayout( 2731 _In_ PDISKENTRY DiskEntry, 2732 _In_ BOOL DeleteEntry) 2733{ 2734 PLIST_ENTRY ListEntry; 2735 PPARTENTRY PartEntry; 2736 PPARTITION_INFORMATION_EX PartitionInfo; 2737 ULONG Count, Index; 2738 2739 DPRINT("UpdateGptDiskLayout()\n"); 2740 2741 /* Count used partition entries */ 2742 Count = 0; 2743 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2744 ListEntry != &DiskEntry->PrimaryPartListHead; 2745 ListEntry = ListEntry->Flink) 2746 { 2747 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2748 2749 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID)) 2750 Count++; 2751 } 2752 2753 DPRINT("Used partition entries: %lu\n", Count); 2754 2755 if (DeleteEntry) 2756 Count++; 2757 2758 /* Reallocate the layout buffer */ 2759 if (Count != DiskEntry->LayoutBuffer->PartitionCount) 2760 { 2761 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer; 2762 ULONG NewLayoutBufferSize; 2763 2764 NewLayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 2765 ((Count - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX)); 2766 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 2767 HEAP_ZERO_MEMORY, 2768 DiskEntry->LayoutBuffer, 2769 NewLayoutBufferSize); 2770 if (NewLayoutBuffer == NULL) 2771 { 2772 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", NewLayoutBufferSize); 2773 return; 2774 } 2775 2776 NewLayoutBuffer->PartitionCount = Count; 2777 DiskEntry->LayoutBuffer = NewLayoutBuffer; 2778 } 2779 2780 /* Fill the new layout buffer */ 2781 Index = 0; 2782 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 2783 ListEntry != &DiskEntry->PrimaryPartListHead; 2784 ListEntry = ListEntry->Flink) 2785 { 2786 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 2787 2788 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID)) 2789 { 2790 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2791 PartEntry->PartitionIndex = Index; 2792 2793 DPRINT("Updating primary partition entry %lu\n", Index); 2794 PartitionInfo->PartitionStyle = PARTITION_STYLE_GPT; 2795 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 2796 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2797 PartitionInfo->PartitionNumber = Index + 1; 2798 PartitionInfo->RewritePartition = TRUE; 2799 CopyMemory(&PartitionInfo->Gpt.PartitionType, &PartEntry->Gpt.PartitionType, sizeof(GUID)); 2800 CopyMemory(&PartitionInfo->Gpt.PartitionId, &PartEntry->Gpt.PartitionId, sizeof(GUID)); 2801 PartitionInfo->Gpt.Attributes = PartEntry->Gpt.Attributes; 2802 ZeroMemory(&PartitionInfo->Gpt.Name, 36 * sizeof(WCHAR)); /* ??? */ 2803 2804 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 2805 2806 Index++; 2807 } 2808 } 2809 2810 if (DeleteEntry) 2811 { 2812 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 2813 ZeroMemory(PartitionInfo, sizeof(PARTITION_INFORMATION_EX)); 2814 PartitionInfo->RewritePartition = TRUE; 2815 } 2816} 2817 2818 2819PPARTENTRY 2820GetPrevUnpartitionedEntry( 2821 _In_ PPARTENTRY PartEntry) 2822{ 2823 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2824 PPARTENTRY PrevPartEntry; 2825 PLIST_ENTRY ListHead; 2826 2827 if (PartEntry->LogicalPartition) 2828 ListHead = &DiskEntry->LogicalPartListHead; 2829 else 2830 ListHead = &DiskEntry->PrimaryPartListHead; 2831 2832 if (PartEntry->ListEntry.Blink != ListHead) 2833 { 2834 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink, 2835 PARTENTRY, 2836 ListEntry); 2837 if (!PrevPartEntry->IsPartitioned) 2838 { 2839 ASSERT(PrevPartEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED); 2840 return PrevPartEntry; 2841 } 2842 } 2843 2844 return NULL; 2845} 2846 2847 2848PPARTENTRY 2849GetNextUnpartitionedEntry( 2850 _In_ PPARTENTRY PartEntry) 2851{ 2852 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2853 PPARTENTRY NextPartEntry; 2854 PLIST_ENTRY ListHead; 2855 2856 if (PartEntry->LogicalPartition) 2857 ListHead = &DiskEntry->LogicalPartListHead; 2858 else 2859 ListHead = &DiskEntry->PrimaryPartListHead; 2860 2861 if (PartEntry->ListEntry.Flink != ListHead) 2862 { 2863 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink, 2864 PARTENTRY, 2865 ListEntry); 2866 if (!NextPartEntry->IsPartitioned) 2867 { 2868 ASSERT(NextPartEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED); 2869 return NextPartEntry; 2870 } 2871 } 2872 2873 return NULL; 2874} 2875 2876 2877NTSTATUS 2878DismountVolume( 2879 _In_ PPARTENTRY PartEntry) 2880{ 2881 NTSTATUS Status; 2882 NTSTATUS LockStatus; 2883 UNICODE_STRING Name; 2884 OBJECT_ATTRIBUTES ObjectAttributes; 2885 IO_STATUS_BLOCK IoStatusBlock; 2886 HANDLE PartitionHandle; 2887 WCHAR Buffer[MAX_PATH]; 2888 2889 /* Check whether the partition is valid and was mounted by the system */ 2890 if (PartEntry->DiskEntry->PartitionStyle == PARTITION_STYLE_MBR) 2891 { 2892 if (!PartEntry->IsPartitioned || 2893 IsContainerPartition(PartEntry->Mbr.PartitionType) || 2894 !IsRecognizedPartition(PartEntry->Mbr.PartitionType) || 2895 PartEntry->FormatState == UnknownFormat || 2896 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means 2897 // it has been usually mounted with RawFS and thus needs to be dismounted. 2898/* !*PartEntry->FileSystem || */ 2899 PartEntry->PartitionNumber == 0) 2900 { 2901 /* The partition is not mounted, so just return success */ 2902 return STATUS_SUCCESS; 2903 } 2904 2905 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED); 2906 } 2907 else if (PartEntry->DiskEntry->PartitionStyle == PARTITION_STYLE_GPT) 2908 { 2909 if (!PartEntry->IsPartitioned || 2910 IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID) || 2911 (PartEntry->FormatState == UnknownFormat)) 2912 { 2913 /* The partition is not mounted, so just return success */ 2914 return STATUS_SUCCESS; 2915 } 2916 } 2917 2918 /* Open the volume */ 2919 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 2920 L"\\Device\\Harddisk%lu\\Partition%lu", 2921 PartEntry->DiskEntry->DiskNumber, 2922 PartEntry->PartitionNumber); 2923 RtlInitUnicodeString(&Name, Buffer); 2924 2925 InitializeObjectAttributes(&ObjectAttributes, 2926 &Name, 2927 OBJ_CASE_INSENSITIVE, 2928 NULL, 2929 NULL); 2930 2931 Status = NtOpenFile(&PartitionHandle, 2932 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2933 &ObjectAttributes, 2934 &IoStatusBlock, 2935 FILE_SHARE_READ | FILE_SHARE_WRITE, 2936 FILE_SYNCHRONOUS_IO_NONALERT); 2937 if (!NT_SUCCESS(Status)) 2938 { 2939 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status); 2940 return Status; 2941 } 2942 2943 /* Lock the volume */ 2944 LockStatus = NtFsControlFile(PartitionHandle, 2945 NULL, 2946 NULL, 2947 NULL, 2948 &IoStatusBlock, 2949 FSCTL_LOCK_VOLUME, 2950 NULL, 2951 0, 2952 NULL, 2953 0); 2954 if (!NT_SUCCESS(LockStatus)) 2955 { 2956 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus); 2957 } 2958 2959 /* Dismount the volume */ 2960 Status = NtFsControlFile(PartitionHandle, 2961 NULL, 2962 NULL, 2963 NULL, 2964 &IoStatusBlock, 2965 FSCTL_DISMOUNT_VOLUME, 2966 NULL, 2967 0, 2968 NULL, 2969 0); 2970 if (!NT_SUCCESS(Status)) 2971 { 2972 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); 2973 } 2974 2975 /* Unlock the volume */ 2976 LockStatus = NtFsControlFile(PartitionHandle, 2977 NULL, 2978 NULL, 2979 NULL, 2980 &IoStatusBlock, 2981 FSCTL_UNLOCK_VOLUME, 2982 NULL, 2983 0, 2984 NULL, 2985 0); 2986 if (!NT_SUCCESS(LockStatus)) 2987 { 2988 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); 2989 } 2990 2991 /* Close the volume */ 2992 NtClose(PartitionHandle); 2993 2994 return Status; 2995} 2996 2997 2998PVOLENTRY 2999GetVolumeFromPartition( 3000 _In_ PPARTENTRY PartEntry) 3001{ 3002 PLIST_ENTRY Entry; 3003 PVOLENTRY VolumeEntry; 3004 ULONG i; 3005 3006 if ((PartEntry == NULL) || 3007 (PartEntry->DiskEntry == NULL)) 3008 return NULL; 3009 3010 Entry = VolumeListHead.Flink; 3011 while (Entry != &VolumeListHead) 3012 { 3013 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry); 3014 3015 if (VolumeEntry->pExtents == NULL) 3016 return NULL; 3017 3018 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++) 3019 { 3020 if (VolumeEntry->pExtents->Extents[i].DiskNumber == PartEntry->DiskEntry->DiskNumber) 3021 { 3022 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) && 3023 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector)) 3024 return VolumeEntry; 3025 } 3026 } 3027 3028 Entry = Entry->Flink; 3029 } 3030 3031 return NULL; 3032} 3033 3034 3035VOID 3036RemoveVolume( 3037 _In_ PVOLENTRY VolumeEntry) 3038{ 3039 if (VolumeEntry == NULL) 3040 return; 3041 3042 if (VolumeEntry == CurrentVolume) 3043 CurrentVolume = NULL; 3044 3045 RemoveEntryList(&VolumeEntry->ListEntry); 3046 3047 if (VolumeEntry->pszLabel) 3048 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel); 3049 3050 if (VolumeEntry->pszFilesystem) 3051 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem); 3052 3053 if (VolumeEntry->pExtents) 3054 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents); 3055 3056 /* Release disk entry */ 3057 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 3058} 3059 3060/* EOF */