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 #include <ntddscsi.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 #define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\ 18 {\ 19 PLIST_ENTRY current;\ 20 \ 21 current = (ListHead)->Flink;\ 22 while (current != (ListHead))\ 23 {\ 24 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\ 25 (NewEntry)->SortField)\ 26 {\ 27 break;\ 28 }\ 29 current = current->Flink;\ 30 }\ 31 \ 32 InsertTailList(current, &((NewEntry)->ListEntryField));\ 33 } 34 35 /* We have to define it there, because it is not in the MS DDK */ 36 #define PARTITION_LINUX 0x83 37 38 #define PARTITION_TBL_SIZE 4 39 40 #include <pshpack1.h> 41 42 typedef struct _PARTITION 43 { 44 unsigned char BootFlags; /* bootable? 0=no, 128=yes */ 45 unsigned char StartingHead; /* beginning head number */ 46 unsigned char StartingSector; /* beginning sector number */ 47 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */ 48 unsigned char PartitionType; /* Operating System type indicator code */ 49 unsigned char EndingHead; /* ending head number */ 50 unsigned char EndingSector; /* ending sector number */ 51 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */ 52 unsigned int StartingBlock; /* first sector relative to start of disk */ 53 unsigned int SectorCount; /* number of sectors in partition */ 54 } PARTITION, *PPARTITION; 55 56 typedef struct _PARTITION_SECTOR 57 { 58 UCHAR BootCode[440]; /* 0x000 */ 59 ULONG Signature; /* 0x1B8 */ 60 UCHAR Reserved[2]; /* 0x1BC */ 61 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */ 62 USHORT Magic; /* 0x1FE */ 63 } PARTITION_SECTOR, *PPARTITION_SECTOR; 64 65 #include <poppack.h> 66 67 68 /* GLOBALS ********************************************************************/ 69 70 LIST_ENTRY DiskListHead; 71 LIST_ENTRY BiosDiskListHead; 72 LIST_ENTRY VolumeListHead; 73 74 PDISKENTRY CurrentDisk = NULL; 75 PPARTENTRY CurrentPartition = NULL; 76 PVOLENTRY CurrentVolume = NULL; 77 78 79 /* FUNCTIONS ******************************************************************/ 80 81 ULONGLONG 82 AlignDown( 83 _In_ ULONGLONG Value, 84 _In_ ULONG Alignment) 85 { 86 ULONGLONG Temp; 87 88 Temp = Value / Alignment; 89 90 return Temp * Alignment; 91 } 92 93 static 94 VOID 95 GetDriverName( 96 PDISKENTRY DiskEntry) 97 { 98 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 99 WCHAR KeyName[32]; 100 NTSTATUS Status; 101 102 RtlInitUnicodeString(&DiskEntry->DriverName, 103 NULL); 104 105 StringCchPrintfW(KeyName, ARRAYSIZE(KeyName), 106 L"\\Scsi\\Scsi Port %lu", 107 DiskEntry->Port); 108 109 RtlZeroMemory(&QueryTable, 110 sizeof(QueryTable)); 111 112 QueryTable[0].Name = L"Driver"; 113 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 114 QueryTable[0].EntryContext = &DiskEntry->DriverName; 115 116 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP, 117 KeyName, 118 QueryTable, 119 NULL, 120 NULL); 121 if (!NT_SUCCESS(Status)) 122 { 123 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 124 } 125 } 126 127 static 128 NTSTATUS 129 NTAPI 130 DiskIdentifierQueryRoutine( 131 PWSTR ValueName, 132 ULONG ValueType, 133 PVOID ValueData, 134 ULONG ValueLength, 135 PVOID Context, 136 PVOID EntryContext) 137 { 138 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 139 UNICODE_STRING NameU; 140 141 if (ValueType == REG_SZ && 142 ValueLength == 20 * sizeof(WCHAR)) 143 { 144 NameU.Buffer = (PWCHAR)ValueData; 145 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR); 146 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum); 147 148 NameU.Buffer = (PWCHAR)ValueData + 9; 149 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature); 150 151 return STATUS_SUCCESS; 152 } 153 154 return STATUS_UNSUCCESSFUL; 155 } 156 157 static 158 NTSTATUS 159 NTAPI 160 DiskConfigurationDataQueryRoutine( 161 PWSTR ValueName, 162 ULONG ValueType, 163 PVOID ValueData, 164 ULONG ValueLength, 165 PVOID Context, 166 PVOID EntryContext) 167 { 168 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context; 169 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 170 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; 171 ULONG i; 172 173 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 174 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 175 return STATUS_UNSUCCESSFUL; 176 177 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 178 179 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 180 #if 0 181 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 182 FullResourceDescriptor->PartialResourceList.Revision != 1) 183 return STATUS_UNSUCCESSFUL; 184 #endif 185 186 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 187 { 188 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 189 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)) 190 continue; 191 192 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1]; 193 BiosDiskEntry->DiskGeometry = *DiskGeometry; 194 195 return STATUS_SUCCESS; 196 } 197 198 return STATUS_UNSUCCESSFUL; 199 } 200 201 static 202 NTSTATUS 203 NTAPI 204 SystemConfigurationDataQueryRoutine( 205 PWSTR ValueName, 206 ULONG ValueType, 207 PVOID ValueData, 208 ULONG ValueLength, 209 PVOID Context, 210 PVOID EntryContext) 211 { 212 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; 213 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context; 214 ULONG i; 215 216 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR || 217 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR)) 218 return STATUS_UNSUCCESSFUL; 219 220 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; 221 222 /* Hm. Version and Revision are not set on Microsoft Windows XP... */ 223 #if 0 224 if (FullResourceDescriptor->PartialResourceList.Version != 1 || 225 FullResourceDescriptor->PartialResourceList.Revision != 1) 226 return STATUS_UNSUCCESSFUL; 227 #endif 228 229 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++) 230 { 231 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific || 232 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0) 233 continue; 234 235 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0, 236 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 237 if (*Int13Drives == NULL) 238 return STATUS_NO_MEMORY; 239 240 memcpy(*Int13Drives, 241 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1], 242 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize); 243 return STATUS_SUCCESS; 244 } 245 246 return STATUS_UNSUCCESSFUL; 247 } 248 249 250 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter" 251 252 static 253 VOID 254 EnumerateBiosDiskEntries(VOID) 255 { 256 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 257 WCHAR Name[120]; 258 ULONG AdapterCount; 259 ULONG DiskCount; 260 NTSTATUS Status; 261 PCM_INT13_DRIVE_PARAMETER Int13Drives; 262 PBIOSDISKENTRY BiosDiskEntry; 263 264 memset(QueryTable, 0, sizeof(QueryTable)); 265 266 QueryTable[1].Name = L"Configuration Data"; 267 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine; 268 Int13Drives = NULL; 269 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 270 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System", 271 &QueryTable[1], 272 (PVOID)&Int13Drives, 273 NULL); 274 if (!NT_SUCCESS(Status)) 275 { 276 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status); 277 return; 278 } 279 280 AdapterCount = 0; 281 while (1) 282 { 283 StringCchPrintfW(Name, ARRAYSIZE(Name), 284 L"%s\\%lu", ROOT_NAME, AdapterCount); 285 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 286 Name, 287 &QueryTable[2], 288 NULL, 289 NULL); 290 if (!NT_SUCCESS(Status)) 291 { 292 break; 293 } 294 295 StringCchPrintfW(Name, ARRAYSIZE(Name), 296 L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount); 297 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 298 Name, 299 &QueryTable[2], 300 NULL, 301 NULL); 302 if (NT_SUCCESS(Status)) 303 { 304 while (1) 305 { 306 StringCchPrintfW(Name, ARRAYSIZE(Name), 307 L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount); 308 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 309 Name, 310 &QueryTable[2], 311 NULL, 312 NULL); 313 if (!NT_SUCCESS(Status)) 314 { 315 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 316 return; 317 } 318 319 StringCchPrintfW(Name, ARRAYSIZE(Name), 320 L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount); 321 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 322 Name, 323 &QueryTable[2], 324 NULL, 325 NULL); 326 if (NT_SUCCESS(Status)) 327 { 328 QueryTable[0].Name = L"Identifier"; 329 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine; 330 QueryTable[1].Name = L"Configuration Data"; 331 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine; 332 333 DiskCount = 0; 334 while (1) 335 { 336 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY)); 337 if (BiosDiskEntry == NULL) 338 { 339 break; 340 } 341 342 StringCchPrintfW(Name, ARRAYSIZE(Name), 343 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount); 344 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 345 Name, 346 QueryTable, 347 (PVOID)BiosDiskEntry, 348 NULL); 349 if (!NT_SUCCESS(Status)) 350 { 351 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 352 break; 353 } 354 355 BiosDiskEntry->DiskNumber = DiskCount; 356 BiosDiskEntry->Recognized = FALSE; 357 358 if (DiskCount < Int13Drives[0].NumberDrives) 359 { 360 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount]; 361 } 362 else 363 { 364 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount); 365 } 366 367 InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry); 368 369 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber); 370 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature); 371 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum); 372 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector); 373 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders); 374 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads); 375 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect); 376 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders); 377 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack); 378 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads); 379 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives); 380 381 DiskCount++; 382 } 383 } 384 385 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 386 return; 387 } 388 } 389 390 AdapterCount++; 391 } 392 393 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives); 394 } 395 396 397 static 398 VOID 399 AddPartitionToDisk( 400 ULONG DiskNumber, 401 PDISKENTRY DiskEntry, 402 ULONG PartitionIndex, 403 BOOLEAN LogicalPartition) 404 { 405 PPARTITION_INFORMATION PartitionInfo; 406 PPARTENTRY PartEntry; 407 408 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex]; 409 if (PartitionInfo->PartitionType == 0 || 410 (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->PartitionType))) 411 return; 412 413 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 414 HEAP_ZERO_MEMORY, 415 sizeof(PARTENTRY)); 416 if (PartEntry == NULL) 417 { 418 return; 419 } 420 421 PartEntry->DiskEntry = DiskEntry; 422 423 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector; 424 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector; 425 426 PartEntry->BootIndicator = PartitionInfo->BootIndicator; 427 PartEntry->PartitionType = PartitionInfo->PartitionType; 428 429 PartEntry->LogicalPartition = LogicalPartition; 430 PartEntry->IsPartitioned = TRUE; 431 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 432 PartEntry->PartitionIndex = PartitionIndex; 433 434 if (IsContainerPartition(PartEntry->PartitionType)) 435 { 436 PartEntry->FormatState = Unformatted; 437 438 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL) 439 DiskEntry->ExtendedPartition = PartEntry; 440 } 441 else if ((PartEntry->PartitionType == PARTITION_FAT_12) || 442 (PartEntry->PartitionType == PARTITION_FAT_16) || 443 (PartEntry->PartitionType == PARTITION_HUGE) || 444 (PartEntry->PartitionType == PARTITION_XINT13) || 445 (PartEntry->PartitionType == PARTITION_FAT32) || 446 (PartEntry->PartitionType == PARTITION_FAT32_XINT13)) 447 { 448 #if 0 449 if (CheckFatFormat()) 450 { 451 PartEntry->FormatState = Preformatted; 452 } 453 else 454 { 455 PartEntry->FormatState = Unformatted; 456 } 457 #endif 458 PartEntry->FormatState = Preformatted; 459 } 460 else if (PartEntry->PartitionType == PARTITION_LINUX) 461 { 462 #if 0 463 if (CheckExt2Format()) 464 { 465 PartEntry->FormatState = Preformatted; 466 } 467 else 468 { 469 PartEntry->FormatState = Unformatted; 470 } 471 #endif 472 PartEntry->FormatState = Preformatted; 473 } 474 else if (PartEntry->PartitionType == PARTITION_IFS) 475 { 476 #if 0 477 if (CheckNtfsFormat()) 478 { 479 PartEntry->FormatState = Preformatted; 480 } 481 else if (CheckHpfsFormat()) 482 { 483 PartEntry->FormatState = Preformatted; 484 } 485 else 486 { 487 PartEntry->FormatState = Unformatted; 488 } 489 #endif 490 PartEntry->FormatState = Preformatted; 491 } 492 else 493 { 494 PartEntry->FormatState = UnknownFormat; 495 } 496 497 if (LogicalPartition) 498 InsertTailList(&DiskEntry->LogicalPartListHead, 499 &PartEntry->ListEntry); 500 else 501 InsertTailList(&DiskEntry->PrimaryPartListHead, 502 &PartEntry->ListEntry); 503 } 504 505 506 static 507 VOID 508 ScanForUnpartitionedDiskSpace( 509 PDISKENTRY DiskEntry) 510 { 511 ULONGLONG LastStartSector; 512 ULONGLONG LastSectorCount; 513 ULONGLONG LastUnusedSectorCount; 514 PPARTENTRY PartEntry; 515 PPARTENTRY NewPartEntry; 516 PLIST_ENTRY Entry; 517 518 DPRINT("ScanForUnpartitionedDiskSpace()\n"); 519 520 if (IsListEmpty(&DiskEntry->PrimaryPartListHead)) 521 { 522 DPRINT1("No primary partition!\n"); 523 524 /* Create a partition table that represents the empty disk */ 525 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 526 HEAP_ZERO_MEMORY, 527 sizeof(PARTENTRY)); 528 if (NewPartEntry == NULL) 529 return; 530 531 NewPartEntry->DiskEntry = DiskEntry; 532 533 NewPartEntry->IsPartitioned = FALSE; 534 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment; 535 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - 536 NewPartEntry->StartSector.QuadPart; 537 538 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 539 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 540 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 541 542 NewPartEntry->FormatState = Unformatted; 543 544 InsertTailList(&DiskEntry->PrimaryPartListHead, 545 &NewPartEntry->ListEntry); 546 547 return; 548 } 549 550 /* Start partition at head 1, cylinder 0 */ 551 LastStartSector = DiskEntry->SectorAlignment; 552 LastSectorCount = 0ULL; 553 LastUnusedSectorCount = 0ULL; 554 555 Entry = DiskEntry->PrimaryPartListHead.Flink; 556 while (Entry != &DiskEntry->PrimaryPartListHead) 557 { 558 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 559 560 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 561 PartEntry->SectorCount.QuadPart != 0ULL) 562 { 563 LastUnusedSectorCount = 564 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount); 565 566 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) && 567 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 568 { 569 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 570 571 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 572 HEAP_ZERO_MEMORY, 573 sizeof(PARTENTRY)); 574 if (NewPartEntry == NULL) 575 return; 576 577 NewPartEntry->DiskEntry = DiskEntry; 578 579 NewPartEntry->IsPartitioned = FALSE; 580 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 581 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 582 NewPartEntry->StartSector.QuadPart; 583 584 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 585 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 586 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 587 588 NewPartEntry->FormatState = Unformatted; 589 590 /* Insert the table into the list */ 591 InsertTailList(&PartEntry->ListEntry, 592 &NewPartEntry->ListEntry); 593 } 594 595 LastStartSector = PartEntry->StartSector.QuadPart; 596 LastSectorCount = PartEntry->SectorCount.QuadPart; 597 } 598 599 Entry = Entry->Flink; 600 } 601 602 /* Check for trailing unpartitioned disk space */ 603 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart) 604 { 605 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment); 606 607 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 608 { 609 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 610 611 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 612 HEAP_ZERO_MEMORY, 613 sizeof(PARTENTRY)); 614 if (NewPartEntry == NULL) 615 return; 616 617 NewPartEntry->DiskEntry = DiskEntry; 618 619 NewPartEntry->IsPartitioned = FALSE; 620 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 621 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 622 NewPartEntry->StartSector.QuadPart; 623 624 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 625 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 626 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 627 628 NewPartEntry->FormatState = Unformatted; 629 630 /* Append the table to the list */ 631 InsertTailList(&DiskEntry->PrimaryPartListHead, 632 &NewPartEntry->ListEntry); 633 } 634 } 635 636 if (DiskEntry->ExtendedPartition != NULL) 637 { 638 if (IsListEmpty(&DiskEntry->LogicalPartListHead)) 639 { 640 DPRINT1("No logical partition!\n"); 641 642 /* Create a partition table entry that represents the empty extended partition */ 643 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 644 HEAP_ZERO_MEMORY, 645 sizeof(PARTENTRY)); 646 if (NewPartEntry == NULL) 647 return; 648 649 NewPartEntry->DiskEntry = DiskEntry; 650 NewPartEntry->LogicalPartition = TRUE; 651 652 NewPartEntry->IsPartitioned = FALSE; 653 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 654 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment; 655 656 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 657 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 658 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 659 660 NewPartEntry->FormatState = Unformatted; 661 662 InsertTailList(&DiskEntry->LogicalPartListHead, 663 &NewPartEntry->ListEntry); 664 665 return; 666 } 667 668 /* Start partition at head 1, cylinder 0 */ 669 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment; 670 LastSectorCount = 0ULL; 671 LastUnusedSectorCount = 0ULL; 672 673 Entry = DiskEntry->LogicalPartListHead.Flink; 674 while (Entry != &DiskEntry->LogicalPartListHead) 675 { 676 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 677 678 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || 679 PartEntry->SectorCount.QuadPart != 0ULL) 680 { 681 LastUnusedSectorCount = 682 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount); 683 684 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) && 685 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 686 { 687 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount); 688 689 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 690 HEAP_ZERO_MEMORY, 691 sizeof(PARTENTRY)); 692 if (NewPartEntry == NULL) 693 return; 694 695 NewPartEntry->DiskEntry = DiskEntry; 696 NewPartEntry->LogicalPartition = TRUE; 697 698 NewPartEntry->IsPartitioned = FALSE; 699 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 700 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 701 NewPartEntry->StartSector.QuadPart; 702 703 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 704 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 705 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 706 707 NewPartEntry->FormatState = Unformatted; 708 709 /* Insert the table into the list */ 710 InsertTailList(&PartEntry->ListEntry, 711 &NewPartEntry->ListEntry); 712 } 713 714 LastStartSector = PartEntry->StartSector.QuadPart; 715 LastSectorCount = PartEntry->SectorCount.QuadPart; 716 } 717 718 Entry = Entry->Flink; 719 } 720 721 /* Check for trailing unpartitioned disk space */ 722 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart) 723 { 724 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), 725 DiskEntry->SectorAlignment); 726 727 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment) 728 { 729 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount); 730 731 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), 732 HEAP_ZERO_MEMORY, 733 sizeof(PARTENTRY)); 734 if (NewPartEntry == NULL) 735 return; 736 737 NewPartEntry->DiskEntry = DiskEntry; 738 NewPartEntry->LogicalPartition = TRUE; 739 740 NewPartEntry->IsPartitioned = FALSE; 741 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount; 742 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) - 743 NewPartEntry->StartSector.QuadPart; 744 745 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart); 746 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1); 747 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart); 748 749 NewPartEntry->FormatState = Unformatted; 750 751 /* Append the table to the list */ 752 InsertTailList(&DiskEntry->LogicalPartListHead, 753 &NewPartEntry->ListEntry); 754 } 755 } 756 } 757 758 DPRINT("ScanForUnpartitionedDiskSpace() done\n"); 759 } 760 761 762 static 763 VOID 764 AddDiskToList( 765 HANDLE FileHandle, 766 ULONG DiskNumber) 767 { 768 DISK_GEOMETRY DiskGeometry; 769 SCSI_ADDRESS ScsiAddress; 770 PDISKENTRY DiskEntry; 771 IO_STATUS_BLOCK Iosb; 772 NTSTATUS Status; 773 PPARTITION_SECTOR Mbr; 774 PULONG Buffer; 775 LARGE_INTEGER FileOffset; 776 WCHAR Identifier[20]; 777 ULONG Checksum; 778 ULONG Signature; 779 ULONG i; 780 PLIST_ENTRY ListEntry; 781 PBIOSDISKENTRY BiosDiskEntry; 782 ULONG LayoutBufferSize; 783 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 784 785 Status = NtDeviceIoControlFile(FileHandle, 786 NULL, 787 NULL, 788 NULL, 789 &Iosb, 790 IOCTL_DISK_GET_DRIVE_GEOMETRY, 791 NULL, 792 0, 793 &DiskGeometry, 794 sizeof(DISK_GEOMETRY)); 795 if (!NT_SUCCESS(Status)) 796 { 797 return; 798 } 799 800 if (DiskGeometry.MediaType != FixedMedia && 801 DiskGeometry.MediaType != RemovableMedia) 802 { 803 return; 804 } 805 806 Status = NtDeviceIoControlFile(FileHandle, 807 NULL, 808 NULL, 809 NULL, 810 &Iosb, 811 IOCTL_SCSI_GET_ADDRESS, 812 NULL, 813 0, 814 &ScsiAddress, 815 sizeof(SCSI_ADDRESS)); 816 if (!NT_SUCCESS(Status)) 817 { 818 return; 819 } 820 821 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(), 822 0, 823 DiskGeometry.BytesPerSector); 824 if (Mbr == NULL) 825 { 826 return; 827 } 828 829 FileOffset.QuadPart = 0; 830 Status = NtReadFile(FileHandle, 831 NULL, 832 NULL, 833 NULL, 834 &Iosb, 835 (PVOID)Mbr, 836 DiskGeometry.BytesPerSector, 837 &FileOffset, 838 NULL); 839 if (!NT_SUCCESS(Status)) 840 { 841 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 842 DPRINT1("NtReadFile failed, status=%x\n", Status); 843 return; 844 } 845 Signature = Mbr->Signature; 846 847 /* Calculate the MBR checksum */ 848 Checksum = 0; 849 Buffer = (PULONG)Mbr; 850 for (i = 0; i < 128; i++) 851 { 852 Checksum += Buffer[i]; 853 } 854 Checksum = ~Checksum + 1; 855 856 StringCchPrintfW(Identifier, ARRAYSIZE(Identifier), 857 L"%08x-%08x-A", Checksum, Signature); 858 DPRINT("Identifier: %S\n", Identifier); 859 860 DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(), 861 HEAP_ZERO_MEMORY, 862 sizeof(DISKENTRY)); 863 if (DiskEntry == NULL) 864 { 865 return; 866 } 867 868 // DiskEntry->Checksum = Checksum; 869 // DiskEntry->Signature = Signature; 870 DiskEntry->BiosFound = FALSE; 871 872 /* Check if this disk has a valid MBR */ 873 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0) 874 DiskEntry->NoMbr = TRUE; 875 else 876 DiskEntry->NoMbr = FALSE; 877 878 /* Free Mbr sector buffer */ 879 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr); 880 881 ListEntry = BiosDiskListHead.Flink; 882 while (ListEntry != &BiosDiskListHead) 883 { 884 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry); 885 /* FIXME: 886 * Compare the size from bios and the reported size from driver. 887 * If we have more than one disk with a zero or with the same signatur 888 * we must create new signatures and reboot. After the reboot, 889 * it is possible to identify the disks. 890 */ 891 if (BiosDiskEntry->Signature == Signature && 892 BiosDiskEntry->Checksum == Checksum && 893 !BiosDiskEntry->Recognized) 894 { 895 if (!DiskEntry->BiosFound) 896 { 897 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber; 898 DiskEntry->BiosFound = TRUE; 899 BiosDiskEntry->Recognized = TRUE; 900 } 901 else 902 { 903 } 904 } 905 ListEntry = ListEntry->Flink; 906 } 907 908 if (!DiskEntry->BiosFound) 909 { 910 #if 0 911 RtlFreeHeap(ProcessHeap, 0, DiskEntry); 912 return; 913 #else 914 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber); 915 #endif 916 } 917 918 InitializeListHead(&DiskEntry->PrimaryPartListHead); 919 InitializeListHead(&DiskEntry->LogicalPartListHead); 920 921 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart; 922 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder; 923 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack; 924 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector; 925 926 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders); 927 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder); 928 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack); 929 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector); 930 931 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 932 (ULONGLONG)DiskGeometry.TracksPerCylinder * 933 (ULONGLONG)DiskGeometry.SectorsPerTrack; 934 935 // DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack; 936 // DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder; 937 DiskEntry->SectorAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector; 938 DiskEntry->CylinderAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector; 939 940 DPRINT1("SectorCount: %I64u\n", DiskEntry->SectorCount); 941 DPRINT1("SectorAlignment: %lu\n", DiskEntry->SectorAlignment); 942 DPRINT1("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment); 943 944 DiskEntry->DiskNumber = DiskNumber; 945 DiskEntry->Port = ScsiAddress.PortNumber; 946 DiskEntry->PathId = ScsiAddress.PathId; 947 DiskEntry->TargetId = ScsiAddress.TargetId; 948 DiskEntry->Lun = ScsiAddress.Lun; 949 950 GetDriverName(DiskEntry); 951 952 InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber); 953 954 /* Allocate a layout buffer with 4 partition entries first */ 955 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 956 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 957 DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 958 HEAP_ZERO_MEMORY, 959 LayoutBufferSize); 960 if (DiskEntry->LayoutBuffer == NULL) 961 { 962 DPRINT1("Failed to allocate the disk layout buffer!\n"); 963 return; 964 } 965 966 for (;;) 967 { 968 DPRINT1("Buffer size: %lu\n", LayoutBufferSize); 969 Status = NtDeviceIoControlFile(FileHandle, 970 NULL, 971 NULL, 972 NULL, 973 &Iosb, 974 IOCTL_DISK_GET_DRIVE_LAYOUT, 975 NULL, 976 0, 977 DiskEntry->LayoutBuffer, 978 LayoutBufferSize); 979 if (NT_SUCCESS(Status)) 980 break; 981 982 if (Status != STATUS_BUFFER_TOO_SMALL) 983 { 984 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status); 985 return; 986 } 987 988 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION); 989 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 990 HEAP_ZERO_MEMORY, 991 DiskEntry->LayoutBuffer, 992 LayoutBufferSize); 993 if (NewLayoutBuffer == NULL) 994 { 995 DPRINT1("Failed to reallocate the disk layout buffer!\n"); 996 return; 997 } 998 999 DiskEntry->LayoutBuffer = NewLayoutBuffer; 1000 } 1001 1002 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount); 1003 1004 #ifdef DUMP_PARTITION_TABLE 1005 DumpPartitionTable(DiskEntry); 1006 #endif 1007 1008 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 && 1009 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 && 1010 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0) 1011 { 1012 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0) 1013 { 1014 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack); 1015 } 1016 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0) 1017 { 1018 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1019 } 1020 else 1021 { 1022 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart); 1023 } 1024 } 1025 else 1026 { 1027 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector); 1028 } 1029 1030 1031 if (DiskEntry->LayoutBuffer->PartitionCount == 0) 1032 { 1033 DiskEntry->NewDisk = TRUE; 1034 DiskEntry->LayoutBuffer->PartitionCount = 4; 1035 1036 for (i = 0; i < 4; i++) 1037 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1038 } 1039 else 1040 { 1041 for (i = 0; i < 4; i++) 1042 { 1043 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE); 1044 } 1045 1046 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4) 1047 { 1048 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE); 1049 } 1050 } 1051 1052 ScanForUnpartitionedDiskSpace(DiskEntry); 1053 } 1054 1055 1056 NTSTATUS 1057 CreatePartitionList(VOID) 1058 { 1059 OBJECT_ATTRIBUTES ObjectAttributes; 1060 SYSTEM_DEVICE_INFORMATION Sdi; 1061 IO_STATUS_BLOCK Iosb; 1062 ULONG ReturnSize; 1063 NTSTATUS Status; 1064 ULONG DiskNumber; 1065 WCHAR Buffer[MAX_PATH]; 1066 UNICODE_STRING Name; 1067 HANDLE FileHandle; 1068 1069 CurrentDisk = NULL; 1070 CurrentPartition = NULL; 1071 1072 // BootDisk = NULL; 1073 // BootPartition = NULL; 1074 1075 // TempDisk = NULL; 1076 // TempPartition = NULL; 1077 // FormatState = Start; 1078 1079 InitializeListHead(&DiskListHead); 1080 InitializeListHead(&BiosDiskListHead); 1081 1082 EnumerateBiosDiskEntries(); 1083 1084 Status = NtQuerySystemInformation(SystemDeviceInformation, 1085 &Sdi, 1086 sizeof(SYSTEM_DEVICE_INFORMATION), 1087 &ReturnSize); 1088 if (!NT_SUCCESS(Status)) 1089 { 1090 return Status; 1091 } 1092 1093 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) 1094 { 1095 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 1096 L"\\Device\\Harddisk%d\\Partition0", 1097 DiskNumber); 1098 1099 RtlInitUnicodeString(&Name, 1100 Buffer); 1101 1102 InitializeObjectAttributes(&ObjectAttributes, 1103 &Name, 1104 0, 1105 NULL, 1106 NULL); 1107 1108 Status = NtOpenFile(&FileHandle, 1109 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 1110 &ObjectAttributes, 1111 &Iosb, 1112 FILE_SHARE_READ, 1113 FILE_SYNCHRONOUS_IO_NONALERT); 1114 if (NT_SUCCESS(Status)) 1115 { 1116 AddDiskToList(FileHandle, DiskNumber); 1117 1118 NtClose(FileHandle); 1119 } 1120 } 1121 1122 // UpdateDiskSignatures(List); 1123 1124 // AssignDriveLetters(List); 1125 1126 return STATUS_SUCCESS; 1127 } 1128 1129 1130 VOID 1131 DestroyPartitionList(VOID) 1132 { 1133 PDISKENTRY DiskEntry; 1134 PBIOSDISKENTRY BiosDiskEntry; 1135 PPARTENTRY PartEntry; 1136 PLIST_ENTRY Entry; 1137 1138 CurrentDisk = NULL; 1139 CurrentPartition = NULL; 1140 1141 /* Release disk and partition info */ 1142 while (!IsListEmpty(&DiskListHead)) 1143 { 1144 Entry = RemoveHeadList(&DiskListHead); 1145 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 1146 1147 /* Release driver name */ 1148 RtlFreeUnicodeString(&DiskEntry->DriverName); 1149 1150 /* Release primary partition list */ 1151 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead)) 1152 { 1153 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead); 1154 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1155 1156 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1157 } 1158 1159 /* Release logical partition list */ 1160 while (!IsListEmpty(&DiskEntry->LogicalPartListHead)) 1161 { 1162 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead); 1163 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1164 1165 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry); 1166 } 1167 1168 /* Release layout buffer */ 1169 if (DiskEntry->LayoutBuffer != NULL) 1170 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer); 1171 1172 1173 /* Release disk entry */ 1174 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry); 1175 } 1176 1177 /* Release the bios disk info */ 1178 while (!IsListEmpty(&BiosDiskListHead)) 1179 { 1180 Entry = RemoveHeadList(&BiosDiskListHead); 1181 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry); 1182 1183 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry); 1184 } 1185 } 1186 1187 1188 static 1189 VOID 1190 GetVolumeExtents( 1191 _In_ HANDLE VolumeHandle, 1192 _In_ PVOLENTRY VolumeEntry) 1193 { 1194 DWORD dwBytesReturned = 0, dwLength, i; 1195 PVOLUME_DISK_EXTENTS pExtents; 1196 BOOL bResult; 1197 DWORD dwError; 1198 1199 dwLength = sizeof(VOLUME_DISK_EXTENTS); 1200 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); 1201 if (pExtents == NULL) 1202 return; 1203 1204 bResult = DeviceIoControl(VolumeHandle, 1205 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 1206 NULL, 1207 0, 1208 pExtents, 1209 dwLength, 1210 &dwBytesReturned, 1211 NULL); 1212 if (!bResult) 1213 { 1214 dwError = GetLastError(); 1215 1216 if (dwError != ERROR_MORE_DATA) 1217 { 1218 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1219 return; 1220 } 1221 else 1222 { 1223 dwLength = sizeof(VOLUME_DISK_EXTENTS) + ((pExtents->NumberOfDiskExtents - 1) * sizeof(DISK_EXTENT)); 1224 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1225 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); 1226 if (pExtents == NULL) 1227 { 1228 return; 1229 } 1230 1231 bResult = DeviceIoControl(VolumeHandle, 1232 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 1233 NULL, 1234 0, 1235 pExtents, 1236 dwLength, 1237 &dwBytesReturned, 1238 NULL); 1239 if (!bResult) 1240 { 1241 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents); 1242 return; 1243 } 1244 } 1245 } 1246 1247 for (i = 0; i < pExtents->NumberOfDiskExtents; i++) 1248 VolumeEntry->Size.QuadPart += pExtents->Extents[i].ExtentLength.QuadPart; 1249 1250 VolumeEntry->pExtents = pExtents; 1251 } 1252 1253 1254 static 1255 VOID 1256 GetVolumeType( 1257 _In_ HANDLE VolumeHandle, 1258 _In_ PVOLENTRY VolumeEntry) 1259 { 1260 FILE_FS_DEVICE_INFORMATION DeviceInfo; 1261 IO_STATUS_BLOCK IoStatusBlock; 1262 NTSTATUS Status; 1263 1264 Status = NtQueryVolumeInformationFile(VolumeHandle, 1265 &IoStatusBlock, 1266 &DeviceInfo, 1267 sizeof(FILE_FS_DEVICE_INFORMATION), 1268 FileFsDeviceInformation); 1269 if (!NT_SUCCESS(Status)) 1270 return; 1271 1272 switch (DeviceInfo.DeviceType) 1273 { 1274 case FILE_DEVICE_CD_ROM: 1275 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 1276 VolumeEntry->VolumeType = VOLUME_TYPE_CDROM; 1277 break; 1278 1279 case FILE_DEVICE_DISK: 1280 case FILE_DEVICE_DISK_FILE_SYSTEM: 1281 if (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA) 1282 VolumeEntry->VolumeType = VOLUME_TYPE_REMOVABLE; 1283 else 1284 VolumeEntry->VolumeType = VOLUME_TYPE_PARTITION; 1285 break; 1286 1287 default: 1288 VolumeEntry->VolumeType = VOLUME_TYPE_UNKNOWN; 1289 break; 1290 } 1291 } 1292 1293 1294 static 1295 VOID 1296 AddVolumeToList( 1297 ULONG ulVolumeNumber, 1298 PWSTR pszVolumeName) 1299 { 1300 PVOLENTRY VolumeEntry; 1301 HANDLE VolumeHandle; 1302 1303 DWORD dwError, dwLength; 1304 WCHAR szPathNames[MAX_PATH + 1]; 1305 WCHAR szVolumeName[MAX_PATH + 1]; 1306 WCHAR szFilesystem[MAX_PATH + 1]; 1307 1308 DWORD CharCount = 0; 1309 size_t Index = 0; 1310 1311 OBJECT_ATTRIBUTES ObjectAttributes; 1312 UNICODE_STRING Name; 1313 IO_STATUS_BLOCK Iosb; 1314 NTSTATUS Status; 1315 1316 DPRINT("AddVolumeToList(%S)\n", pszVolumeName); 1317 1318 VolumeEntry = RtlAllocateHeap(RtlGetProcessHeap(), 1319 HEAP_ZERO_MEMORY, 1320 sizeof(VOLENTRY)); 1321 if (VolumeEntry == NULL) 1322 return; 1323 1324 VolumeEntry->VolumeNumber = ulVolumeNumber; 1325 wcscpy(VolumeEntry->VolumeName, pszVolumeName); 1326 1327 Index = wcslen(pszVolumeName) - 1; 1328 1329 pszVolumeName[Index] = L'\0'; 1330 1331 CharCount = QueryDosDeviceW(&pszVolumeName[4], VolumeEntry->DeviceName, ARRAYSIZE(VolumeEntry->DeviceName)); 1332 1333 pszVolumeName[Index] = L'\\'; 1334 1335 if (CharCount == 0) 1336 { 1337 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 1338 return; 1339 } 1340 1341 DPRINT("DeviceName: %S\n", VolumeEntry->DeviceName); 1342 1343 RtlInitUnicodeString(&Name, VolumeEntry->DeviceName); 1344 1345 InitializeObjectAttributes(&ObjectAttributes, 1346 &Name, 1347 0, 1348 NULL, 1349 NULL); 1350 1351 Status = NtOpenFile(&VolumeHandle, 1352 SYNCHRONIZE, 1353 &ObjectAttributes, 1354 &Iosb, 1355 0, 1356 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); 1357 if (NT_SUCCESS(Status)) 1358 { 1359 GetVolumeType(VolumeHandle, VolumeEntry); 1360 GetVolumeExtents(VolumeHandle, VolumeEntry); 1361 NtClose(VolumeHandle); 1362 } 1363 1364 if (GetVolumeInformationW(pszVolumeName, 1365 szVolumeName, 1366 MAX_PATH + 1, 1367 NULL, // [out, optional] LPDWORD lpVolumeSerialNumber, 1368 NULL, // [out, optional] LPDWORD lpMaximumComponentLength, 1369 NULL, // [out, optional] LPDWORD lpFileSystemFlags, 1370 szFilesystem, 1371 MAX_PATH + 1)) 1372 { 1373 VolumeEntry->pszLabel = RtlAllocateHeap(RtlGetProcessHeap(), 1374 0, 1375 (wcslen(szVolumeName) + 1) * sizeof(WCHAR)); 1376 if (VolumeEntry->pszLabel) 1377 wcscpy(VolumeEntry->pszLabel, szVolumeName); 1378 1379 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(), 1380 0, 1381 (wcslen(szFilesystem) + 1) * sizeof(WCHAR)); 1382 if (VolumeEntry->pszFilesystem) 1383 wcscpy(VolumeEntry->pszFilesystem, szFilesystem); 1384 } 1385 else 1386 { 1387 dwError = GetLastError(); 1388 if (dwError == ERROR_UNRECOGNIZED_VOLUME) 1389 { 1390 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(), 1391 0, 1392 (3 + 1) * sizeof(WCHAR)); 1393 if (VolumeEntry->pszFilesystem) 1394 wcscpy(VolumeEntry->pszFilesystem, L"RAW"); 1395 } 1396 } 1397 1398 if (GetVolumePathNamesForVolumeNameW(pszVolumeName, 1399 szPathNames, 1400 ARRAYSIZE(szPathNames), 1401 &dwLength)) 1402 { 1403 VolumeEntry->DriveLetter = szPathNames[0]; 1404 } 1405 1406 InsertTailList(&VolumeListHead, 1407 &VolumeEntry->ListEntry); 1408 } 1409 1410 1411 NTSTATUS 1412 CreateVolumeList(VOID) 1413 { 1414 HANDLE hVolume = INVALID_HANDLE_VALUE; 1415 WCHAR szVolumeName[MAX_PATH]; 1416 ULONG ulVolumeNumber = 0; 1417 BOOL Success; 1418 1419 CurrentVolume = NULL; 1420 1421 InitializeListHead(&VolumeListHead); 1422 1423 hVolume = FindFirstVolumeW(szVolumeName, ARRAYSIZE(szVolumeName)); 1424 if (hVolume == INVALID_HANDLE_VALUE) 1425 { 1426 1427 return STATUS_UNSUCCESSFUL; 1428 } 1429 1430 AddVolumeToList(ulVolumeNumber++, szVolumeName); 1431 1432 for (;;) 1433 { 1434 Success = FindNextVolumeW(hVolume, szVolumeName, ARRAYSIZE(szVolumeName)); 1435 if (!Success) 1436 { 1437 break; 1438 } 1439 1440 AddVolumeToList(ulVolumeNumber++, szVolumeName); 1441 } 1442 1443 FindVolumeClose(hVolume); 1444 1445 return STATUS_SUCCESS; 1446 } 1447 1448 1449 VOID 1450 DestroyVolumeList(VOID) 1451 { 1452 PLIST_ENTRY Entry; 1453 PVOLENTRY VolumeEntry; 1454 1455 CurrentVolume = NULL; 1456 1457 /* Release disk and partition info */ 1458 while (!IsListEmpty(&VolumeListHead)) 1459 { 1460 Entry = RemoveHeadList(&VolumeListHead); 1461 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry); 1462 1463 if (VolumeEntry->pszLabel) 1464 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel); 1465 1466 if (VolumeEntry->pszFilesystem) 1467 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem); 1468 1469 if (VolumeEntry->pExtents) 1470 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents); 1471 1472 /* Release disk entry */ 1473 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 1474 } 1475 } 1476 1477 1478 NTSTATUS 1479 WritePartitions( 1480 _In_ PDISKENTRY DiskEntry) 1481 { 1482 NTSTATUS Status; 1483 OBJECT_ATTRIBUTES ObjectAttributes; 1484 UNICODE_STRING Name; 1485 HANDLE FileHandle; 1486 IO_STATUS_BLOCK Iosb; 1487 ULONG BufferSize; 1488 PPARTITION_INFORMATION PartitionInfo; 1489 ULONG PartitionCount; 1490 PLIST_ENTRY ListEntry; 1491 PPARTENTRY PartEntry; 1492 WCHAR DstPath[MAX_PATH]; 1493 1494 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber); 1495 1496 /* If the disk is not dirty, there is nothing to do */ 1497 if (!DiskEntry->Dirty) 1498 return STATUS_SUCCESS; 1499 1500 StringCchPrintfW(DstPath, ARRAYSIZE(DstPath), 1501 L"\\Device\\Harddisk%lu\\Partition0", 1502 DiskEntry->DiskNumber); 1503 RtlInitUnicodeString(&Name, DstPath); 1504 1505 InitializeObjectAttributes(&ObjectAttributes, 1506 &Name, 1507 OBJ_CASE_INSENSITIVE, 1508 NULL, 1509 NULL); 1510 1511 Status = NtOpenFile(&FileHandle, 1512 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1513 &ObjectAttributes, 1514 &Iosb, 1515 0, 1516 FILE_SYNCHRONOUS_IO_NONALERT); 1517 if (!NT_SUCCESS(Status)) 1518 { 1519 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); 1520 return Status; 1521 } 1522 1523 // 1524 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize 1525 // the disk in MBR or GPT format in case the disk was not initialized!! 1526 // For this we must ask the user which format to use. 1527 // 1528 1529 /* Save the original partition count to be restored later (see comment below) */ 1530 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 1531 1532 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */ 1533 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 1534 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION)); 1535 Status = NtDeviceIoControlFile(FileHandle, 1536 NULL, 1537 NULL, 1538 NULL, 1539 &Iosb, 1540 IOCTL_DISK_SET_DRIVE_LAYOUT, 1541 DiskEntry->LayoutBuffer, 1542 BufferSize, 1543 DiskEntry->LayoutBuffer, 1544 BufferSize); 1545 NtClose(FileHandle); 1546 1547 /* 1548 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts 1549 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count, 1550 * where such a table is expected to enumerate up to 4 partitions: 1551 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 . 1552 * Due to this we need to restore the original PartitionCount number. 1553 */ 1554 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount; 1555 1556 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */ 1557 if (!NT_SUCCESS(Status)) 1558 { 1559 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status); 1560 return Status; 1561 } 1562 1563 /* Update the partition numbers */ 1564 1565 /* Update the primary partition table */ 1566 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 1567 ListEntry != &DiskEntry->PrimaryPartListHead; 1568 ListEntry = ListEntry->Flink) 1569 { 1570 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1571 1572 if (PartEntry->IsPartitioned) 1573 { 1574 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1575 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 1576 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 1577 } 1578 } 1579 1580 /* Update the logical partition table */ 1581 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 1582 ListEntry != &DiskEntry->LogicalPartListHead; 1583 ListEntry = ListEntry->Flink) 1584 { 1585 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1586 1587 if (PartEntry->IsPartitioned) 1588 { 1589 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1590 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex]; 1591 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber; 1592 } 1593 } 1594 1595 /* The layout has been successfully updated, the disk is not dirty anymore */ 1596 DiskEntry->Dirty = FALSE; 1597 1598 return Status; 1599 } 1600 1601 1602 static 1603 BOOLEAN 1604 IsEmptyLayoutEntry( 1605 IN PPARTITION_INFORMATION PartitionInfo) 1606 { 1607 if (PartitionInfo->StartingOffset.QuadPart == 0 && 1608 PartitionInfo->PartitionLength.QuadPart == 0) 1609 { 1610 return TRUE; 1611 } 1612 1613 return FALSE; 1614 } 1615 1616 1617 static 1618 BOOLEAN 1619 IsSamePrimaryLayoutEntry( 1620 IN PPARTITION_INFORMATION PartitionInfo, 1621 IN PDISKENTRY DiskEntry, 1622 IN PPARTENTRY PartEntry) 1623 { 1624 if ((PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector) && 1625 (PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)) 1626 { 1627 return TRUE; 1628 } 1629 1630 return FALSE; 1631 } 1632 1633 1634 ULONG 1635 GetPrimaryPartitionCount( 1636 _In_ PDISKENTRY DiskEntry) 1637 { 1638 PLIST_ENTRY Entry; 1639 PPARTENTRY PartEntry; 1640 ULONG Count = 0; 1641 1642 for (Entry = DiskEntry->PrimaryPartListHead.Flink; 1643 Entry != &DiskEntry->PrimaryPartListHead; 1644 Entry = Entry->Flink) 1645 { 1646 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry); 1647 if (PartEntry->IsPartitioned) 1648 Count++; 1649 } 1650 1651 return Count; 1652 } 1653 1654 1655 static 1656 ULONG 1657 GetLogicalPartitionCount( 1658 _In_ PDISKENTRY DiskEntry) 1659 { 1660 PLIST_ENTRY ListEntry; 1661 PPARTENTRY PartEntry; 1662 ULONG Count = 0; 1663 1664 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 1665 ListEntry != &DiskEntry->LogicalPartListHead; 1666 ListEntry = ListEntry->Flink) 1667 { 1668 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1669 if (PartEntry->IsPartitioned) 1670 Count++; 1671 } 1672 1673 return Count; 1674 } 1675 1676 1677 static 1678 BOOLEAN 1679 ReAllocateLayoutBuffer( 1680 _In_ PDISKENTRY DiskEntry) 1681 { 1682 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer; 1683 ULONG NewPartitionCount; 1684 ULONG CurrentPartitionCount = 0; 1685 ULONG LayoutBufferSize; 1686 ULONG i; 1687 1688 DPRINT1("ReAllocateLayoutBuffer()\n"); 1689 1690 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4; 1691 1692 if (DiskEntry->LayoutBuffer) 1693 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount; 1694 1695 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n", 1696 CurrentPartitionCount, NewPartitionCount); 1697 1698 if (CurrentPartitionCount == NewPartitionCount) 1699 return TRUE; 1700 1701 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + 1702 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION)); 1703 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 1704 HEAP_ZERO_MEMORY, 1705 DiskEntry->LayoutBuffer, 1706 LayoutBufferSize); 1707 if (NewLayoutBuffer == NULL) 1708 { 1709 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize); 1710 return FALSE; 1711 } 1712 1713 NewLayoutBuffer->PartitionCount = NewPartitionCount; 1714 1715 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */ 1716 if (NewPartitionCount > CurrentPartitionCount) 1717 { 1718 for (i = CurrentPartitionCount; i < NewPartitionCount; i++) 1719 { 1720 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE; 1721 } 1722 } 1723 1724 DiskEntry->LayoutBuffer = NewLayoutBuffer; 1725 1726 return TRUE; 1727 } 1728 1729 1730 VOID 1731 UpdateDiskLayout( 1732 _In_ PDISKENTRY DiskEntry) 1733 { 1734 PPARTITION_INFORMATION PartitionInfo; 1735 PPARTITION_INFORMATION LinkInfo = NULL; 1736 PLIST_ENTRY ListEntry; 1737 PPARTENTRY PartEntry; 1738 LARGE_INTEGER HiddenSectors64; 1739 ULONG Index; 1740 ULONG PartitionNumber = 1; 1741 1742 DPRINT1("UpdateDiskLayout()\n"); 1743 1744 /* Resize the layout buffer if necessary */ 1745 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE) 1746 { 1747 DPRINT("ReAllocateLayoutBuffer() failed.\n"); 1748 return; 1749 } 1750 1751 /* Update the primary partition table */ 1752 Index = 0; 1753 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink; 1754 ListEntry != &DiskEntry->PrimaryPartListHead; 1755 ListEntry = ListEntry->Flink) 1756 { 1757 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1758 1759 if (PartEntry->IsPartitioned) 1760 { 1761 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1762 1763 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 1764 PartEntry->PartitionIndex = Index; 1765 1766 /* Reset the current partition number only for newly-created (unmounted) partitions */ 1767 if (PartEntry->New) 1768 PartEntry->PartitionNumber = 0; 1769 1770 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0); 1771 1772 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry)) 1773 { 1774 DPRINT1("Updating primary partition entry %lu\n", Index); 1775 1776 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 1777 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 1778 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart; 1779 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 1780 PartitionInfo->PartitionType = PartEntry->PartitionType; 1781 PartitionInfo->BootIndicator = PartEntry->BootIndicator; 1782 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 1783 PartitionInfo->RewritePartition = TRUE; 1784 } 1785 1786 if (!IsContainerPartition(PartEntry->PartitionType)) 1787 PartitionNumber++; 1788 1789 Index++; 1790 } 1791 } 1792 1793 ASSERT(Index <= 4); 1794 1795 /* Update the logical partition table */ 1796 Index = 4; 1797 for (ListEntry = DiskEntry->LogicalPartListHead.Flink; 1798 ListEntry != &DiskEntry->LogicalPartListHead; 1799 ListEntry = ListEntry->Flink) 1800 { 1801 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); 1802 1803 if (PartEntry->IsPartitioned) 1804 { 1805 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1806 1807 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 1808 PartEntry->PartitionIndex = Index; 1809 1810 /* Reset the current partition number only for newly-created (unmounted) partitions */ 1811 if (PartEntry->New) 1812 PartEntry->PartitionNumber = 0; 1813 1814 PartEntry->OnDiskPartitionNumber = PartitionNumber; 1815 1816 DPRINT1("Updating logical partition entry %lu\n", Index); 1817 1818 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector; 1819 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 1820 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment; 1821 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber; 1822 PartitionInfo->PartitionType = PartEntry->PartitionType; 1823 PartitionInfo->BootIndicator = FALSE; 1824 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType); 1825 PartitionInfo->RewritePartition = TRUE; 1826 1827 /* Fill the link entry of the previous partition entry */ 1828 if (LinkInfo != NULL) 1829 { 1830 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 1831 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector; 1832 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart; 1833 LinkInfo->HiddenSectors = HiddenSectors64.LowPart; 1834 LinkInfo->PartitionNumber = 0; 1835 LinkInfo->PartitionType = PARTITION_EXTENDED; 1836 LinkInfo->BootIndicator = FALSE; 1837 LinkInfo->RecognizedPartition = FALSE; 1838 LinkInfo->RewritePartition = TRUE; 1839 } 1840 1841 /* Save a pointer to the link entry of the current partition entry */ 1842 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1]; 1843 1844 PartitionNumber++; 1845 Index += 4; 1846 } 1847 } 1848 1849 /* Wipe unused primary partition entries */ 1850 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++) 1851 { 1852 DPRINT1("Primary partition entry %lu\n", Index); 1853 1854 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 1855 1856 if (!IsEmptyLayoutEntry(PartitionInfo)) 1857 { 1858 DPRINT1("Wiping primary partition entry %lu\n", Index); 1859 1860 PartitionInfo->StartingOffset.QuadPart = 0; 1861 PartitionInfo->PartitionLength.QuadPart = 0; 1862 PartitionInfo->HiddenSectors = 0; 1863 PartitionInfo->PartitionNumber = 0; 1864 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 1865 PartitionInfo->BootIndicator = FALSE; 1866 PartitionInfo->RecognizedPartition = FALSE; 1867 PartitionInfo->RewritePartition = TRUE; 1868 } 1869 } 1870 1871 /* Wipe unused logical partition entries */ 1872 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++) 1873 { 1874 if (Index % 4 >= 2) 1875 { 1876 DPRINT1("Logical partition entry %lu\n", Index); 1877 1878 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index]; 1879 1880 if (!IsEmptyLayoutEntry(PartitionInfo)) 1881 { 1882 DPRINT1("Wiping partition entry %lu\n", Index); 1883 1884 PartitionInfo->StartingOffset.QuadPart = 0; 1885 PartitionInfo->PartitionLength.QuadPart = 0; 1886 PartitionInfo->HiddenSectors = 0; 1887 PartitionInfo->PartitionNumber = 0; 1888 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; 1889 PartitionInfo->BootIndicator = FALSE; 1890 PartitionInfo->RecognizedPartition = FALSE; 1891 PartitionInfo->RewritePartition = TRUE; 1892 } 1893 } 1894 } 1895 1896 DiskEntry->Dirty = TRUE; 1897 } 1898 1899 1900 PPARTENTRY 1901 GetPrevUnpartitionedEntry( 1902 _In_ PPARTENTRY PartEntry) 1903 { 1904 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 1905 PPARTENTRY PrevPartEntry; 1906 PLIST_ENTRY ListHead; 1907 1908 if (PartEntry->LogicalPartition) 1909 ListHead = &DiskEntry->LogicalPartListHead; 1910 else 1911 ListHead = &DiskEntry->PrimaryPartListHead; 1912 1913 if (PartEntry->ListEntry.Blink != ListHead) 1914 { 1915 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink, 1916 PARTENTRY, 1917 ListEntry); 1918 if (!PrevPartEntry->IsPartitioned) 1919 { 1920 ASSERT(PrevPartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 1921 return PrevPartEntry; 1922 } 1923 } 1924 1925 return NULL; 1926 } 1927 1928 1929 PPARTENTRY 1930 GetNextUnpartitionedEntry( 1931 _In_ PPARTENTRY PartEntry) 1932 { 1933 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 1934 PPARTENTRY NextPartEntry; 1935 PLIST_ENTRY ListHead; 1936 1937 if (PartEntry->LogicalPartition) 1938 ListHead = &DiskEntry->LogicalPartListHead; 1939 else 1940 ListHead = &DiskEntry->PrimaryPartListHead; 1941 1942 if (PartEntry->ListEntry.Flink != ListHead) 1943 { 1944 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink, 1945 PARTENTRY, 1946 ListEntry); 1947 if (!NextPartEntry->IsPartitioned) 1948 { 1949 ASSERT(NextPartEntry->PartitionType == PARTITION_ENTRY_UNUSED); 1950 return NextPartEntry; 1951 } 1952 } 1953 1954 return NULL; 1955 } 1956 1957 NTSTATUS 1958 DismountVolume( 1959 _In_ PPARTENTRY PartEntry) 1960 { 1961 NTSTATUS Status; 1962 NTSTATUS LockStatus; 1963 UNICODE_STRING Name; 1964 OBJECT_ATTRIBUTES ObjectAttributes; 1965 IO_STATUS_BLOCK IoStatusBlock; 1966 HANDLE PartitionHandle; 1967 WCHAR Buffer[MAX_PATH]; 1968 1969 /* Check whether the partition is valid and was mounted by the system */ 1970 if (!PartEntry->IsPartitioned || 1971 IsContainerPartition(PartEntry->PartitionType) || 1972 !IsRecognizedPartition(PartEntry->PartitionType) || 1973 PartEntry->FormatState == UnknownFormat || 1974 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means 1975 // it has been usually mounted with RawFS and thus needs to be dismounted. 1976 /* !*PartEntry->FileSystem || */ 1977 PartEntry->PartitionNumber == 0) 1978 { 1979 /* The partition is not mounted, so just return success */ 1980 return STATUS_SUCCESS; 1981 } 1982 1983 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED); 1984 1985 /* Open the volume */ 1986 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer), 1987 L"\\Device\\Harddisk%lu\\Partition%lu", 1988 PartEntry->DiskEntry->DiskNumber, 1989 PartEntry->PartitionNumber); 1990 RtlInitUnicodeString(&Name, Buffer); 1991 1992 InitializeObjectAttributes(&ObjectAttributes, 1993 &Name, 1994 OBJ_CASE_INSENSITIVE, 1995 NULL, 1996 NULL); 1997 1998 Status = NtOpenFile(&PartitionHandle, 1999 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 2000 &ObjectAttributes, 2001 &IoStatusBlock, 2002 FILE_SHARE_READ | FILE_SHARE_WRITE, 2003 FILE_SYNCHRONOUS_IO_NONALERT); 2004 if (!NT_SUCCESS(Status)) 2005 { 2006 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status); 2007 return Status; 2008 } 2009 2010 /* Lock the volume */ 2011 LockStatus = NtFsControlFile(PartitionHandle, 2012 NULL, 2013 NULL, 2014 NULL, 2015 &IoStatusBlock, 2016 FSCTL_LOCK_VOLUME, 2017 NULL, 2018 0, 2019 NULL, 2020 0); 2021 if (!NT_SUCCESS(LockStatus)) 2022 { 2023 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus); 2024 } 2025 2026 /* Dismount the volume */ 2027 Status = NtFsControlFile(PartitionHandle, 2028 NULL, 2029 NULL, 2030 NULL, 2031 &IoStatusBlock, 2032 FSCTL_DISMOUNT_VOLUME, 2033 NULL, 2034 0, 2035 NULL, 2036 0); 2037 if (!NT_SUCCESS(Status)) 2038 { 2039 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); 2040 } 2041 2042 /* Unlock the volume */ 2043 LockStatus = NtFsControlFile(PartitionHandle, 2044 NULL, 2045 NULL, 2046 NULL, 2047 &IoStatusBlock, 2048 FSCTL_UNLOCK_VOLUME, 2049 NULL, 2050 0, 2051 NULL, 2052 0); 2053 if (!NT_SUCCESS(LockStatus)) 2054 { 2055 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); 2056 } 2057 2058 /* Close the volume */ 2059 NtClose(PartitionHandle); 2060 2061 return Status; 2062 } 2063 2064 2065 PVOLENTRY 2066 GetVolumeFromPartition( 2067 _In_ PPARTENTRY PartEntry) 2068 { 2069 PLIST_ENTRY Entry; 2070 PVOLENTRY VolumeEntry; 2071 ULONG i; 2072 2073 if ((PartEntry == NULL) || 2074 (PartEntry->DiskEntry == NULL)) 2075 return NULL; 2076 2077 Entry = VolumeListHead.Flink; 2078 while (Entry != &VolumeListHead) 2079 { 2080 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry); 2081 2082 if (VolumeEntry->pExtents == NULL) 2083 return NULL; 2084 2085 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++) 2086 { 2087 if (VolumeEntry->pExtents->Extents[i].DiskNumber == PartEntry->DiskEntry->DiskNumber) 2088 { 2089 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) && 2090 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector)) 2091 return VolumeEntry; 2092 } 2093 } 2094 2095 Entry = Entry->Flink; 2096 } 2097 2098 return NULL; 2099 } 2100 2101 2102 VOID 2103 RemoveVolume( 2104 _In_ PVOLENTRY VolumeEntry) 2105 { 2106 if (VolumeEntry == NULL) 2107 return; 2108 2109 if (VolumeEntry == CurrentVolume) 2110 CurrentVolume = NULL; 2111 2112 RemoveEntryList(&VolumeEntry->ListEntry); 2113 2114 if (VolumeEntry->pszLabel) 2115 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel); 2116 2117 if (VolumeEntry->pszFilesystem) 2118 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem); 2119 2120 if (VolumeEntry->pExtents) 2121 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents); 2122 2123 /* Release disk entry */ 2124 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry); 2125 } 2126 2127 /* EOF */ 2128