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