765c2f0c7f82555630354e906ded3d32c0b553ec
[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 /*
1155 * Allocate a buffer for 26 logical drives (2 entries each == 52)
1156 * plus the main partiton table (4 entries). Total 56 entries.
1157 */
1158 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1159 ((56 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1160 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1161 HEAP_ZERO_MEMORY,
1162 LayoutBufferSize);
1163 if (DiskEntry->LayoutBuffer == NULL)
1164 {
1165 return;
1166 }
1167
1168 Status = NtDeviceIoControlFile(FileHandle,
1169 NULL,
1170 NULL,
1171 NULL,
1172 &Iosb,
1173 IOCTL_DISK_GET_DRIVE_LAYOUT,
1174 NULL,
1175 0,
1176 DiskEntry->LayoutBuffer,
1177 LayoutBufferSize);
1178 if (NT_SUCCESS(Status))
1179 {
1180 #ifdef DUMP_PARTITION_TABLE
1181 DumpPartitionTable(DiskEntry);
1182 #endif
1183
1184 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1185 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1186 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
1187 {
1188 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1189 {
1190 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1191 }
1192 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1193 {
1194 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1195 }
1196 else
1197 {
1198 DPRINT1("No matching aligment found! Partiton 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1199 }
1200 }
1201 else
1202 {
1203 DPRINT1("No valid partiton table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1204 }
1205
1206
1207 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1208 {
1209 DiskEntry->NewDisk = TRUE;
1210 DiskEntry->LayoutBuffer->PartitionCount = 4;
1211
1212 for (i = 0; i < 4; i++)
1213 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1214 }
1215 else
1216 {
1217 for (i = 0; i < 4; i++)
1218 {
1219 AddPartitionToDisk(DiskNumber,
1220 DiskEntry,
1221 i,
1222 FALSE);
1223 }
1224
1225 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1226 {
1227 AddPartitionToDisk(DiskNumber,
1228 DiskEntry,
1229 i,
1230 TRUE);
1231 }
1232 }
1233 }
1234
1235 ScanForUnpartitionedDiskSpace(DiskEntry);
1236 }
1237
1238
1239 PPARTLIST
1240 CreatePartitionList(
1241 SHORT Left,
1242 SHORT Top,
1243 SHORT Right,
1244 SHORT Bottom)
1245 {
1246 PPARTLIST List;
1247 OBJECT_ATTRIBUTES ObjectAttributes;
1248 SYSTEM_DEVICE_INFORMATION Sdi;
1249 IO_STATUS_BLOCK Iosb;
1250 ULONG ReturnSize;
1251 NTSTATUS Status;
1252 ULONG DiskNumber;
1253 WCHAR Buffer[MAX_PATH];
1254 UNICODE_STRING Name;
1255 HANDLE FileHandle;
1256
1257 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1258 0,
1259 sizeof (PARTLIST));
1260 if (List == NULL)
1261 return NULL;
1262
1263 List->Left = Left;
1264 List->Top = Top;
1265 List->Right = Right;
1266 List->Bottom = Bottom;
1267
1268 List->Line = 0;
1269 List->Offset = 0;
1270
1271 List->TopDisk = (ULONG)-1;
1272 List->TopPartition = (ULONG)-1;
1273
1274 List->CurrentDisk = NULL;
1275 List->CurrentPartition = NULL;
1276
1277 List->BootDisk = NULL;
1278 List->BootPartition = NULL;
1279
1280 List->TempDisk = NULL;
1281 List->TempPartition = NULL;
1282 List->FormatState = Start;
1283
1284 InitializeListHead(&List->DiskListHead);
1285 InitializeListHead(&List->BiosDiskListHead);
1286
1287 EnumerateBiosDiskEntries(List);
1288
1289 Status = NtQuerySystemInformation(SystemDeviceInformation,
1290 &Sdi,
1291 sizeof(SYSTEM_DEVICE_INFORMATION),
1292 &ReturnSize);
1293 if (!NT_SUCCESS(Status))
1294 {
1295 RtlFreeHeap(ProcessHeap, 0, List);
1296 return NULL;
1297 }
1298
1299 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1300 {
1301 swprintf(Buffer,
1302 L"\\Device\\Harddisk%d\\Partition0",
1303 DiskNumber);
1304 RtlInitUnicodeString(&Name,
1305 Buffer);
1306
1307 InitializeObjectAttributes(&ObjectAttributes,
1308 &Name,
1309 0,
1310 NULL,
1311 NULL);
1312
1313 Status = NtOpenFile(&FileHandle,
1314 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1315 &ObjectAttributes,
1316 &Iosb,
1317 FILE_SHARE_READ,
1318 FILE_SYNCHRONOUS_IO_NONALERT);
1319 if (NT_SUCCESS(Status))
1320 {
1321 AddDiskToList(FileHandle,
1322 DiskNumber,
1323 List);
1324
1325 NtClose(FileHandle);
1326 }
1327 }
1328
1329 UpdateDiskSignatures(List);
1330
1331 AssignDriveLetters(List);
1332
1333 List->TopDisk = 0;
1334 List->TopPartition = 0;
1335
1336 /* Search for first usable disk and partition */
1337 if (IsListEmpty(&List->DiskListHead))
1338 {
1339 List->CurrentDisk = NULL;
1340 List->CurrentPartition = NULL;
1341 }
1342 else
1343 {
1344 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1345 DISKENTRY,
1346 ListEntry);
1347
1348 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1349 {
1350 List->CurrentPartition = 0;
1351 }
1352 else
1353 {
1354 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1355 PARTENTRY,
1356 ListEntry);
1357 }
1358 }
1359
1360 return List;
1361 }
1362
1363
1364 VOID
1365 DestroyPartitionList(
1366 PPARTLIST List)
1367 {
1368 PDISKENTRY DiskEntry;
1369 PBIOSDISKENTRY BiosDiskEntry;
1370 PPARTENTRY PartEntry;
1371 PLIST_ENTRY Entry;
1372
1373 /* Release disk and partition info */
1374 while (!IsListEmpty(&List->DiskListHead))
1375 {
1376 Entry = RemoveHeadList(&List->DiskListHead);
1377 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1378
1379 /* Release driver name */
1380 RtlFreeUnicodeString(&DiskEntry->DriverName);
1381
1382 /* Release primary partition list */
1383 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1384 {
1385 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1386 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1387
1388 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1389 }
1390
1391 /* Release logical partition list */
1392 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1393 {
1394 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1395 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1396
1397 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1398 }
1399
1400 /* Release layout buffer */
1401 if (DiskEntry->LayoutBuffer != NULL)
1402 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1403
1404
1405 /* Release disk entry */
1406 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1407 }
1408
1409 /* release the bios disk info */
1410 while(!IsListEmpty(&List->BiosDiskListHead))
1411 {
1412 Entry = RemoveHeadList(&List->BiosDiskListHead);
1413 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1414
1415 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1416 }
1417
1418 /* Release list head */
1419 RtlFreeHeap(ProcessHeap, 0, List);
1420 }
1421
1422
1423 static
1424 VOID
1425 PrintEmptyLine(
1426 PPARTLIST List)
1427 {
1428 COORD coPos;
1429 DWORD Written;
1430 USHORT Width;
1431 USHORT Height;
1432
1433 Width = List->Right - List->Left - 1;
1434 Height = List->Bottom - List->Top - 2;
1435
1436 coPos.X = List->Left + 1;
1437 coPos.Y = List->Top + 1 + List->Line;
1438
1439 if (List->Line >= 0 && List->Line <= Height)
1440 {
1441 FillConsoleOutputAttribute(StdOutput,
1442 FOREGROUND_WHITE | BACKGROUND_BLUE,
1443 Width,
1444 coPos,
1445 &Written);
1446
1447 FillConsoleOutputCharacterA(StdOutput,
1448 ' ',
1449 Width,
1450 coPos,
1451 &Written);
1452 }
1453
1454 List->Line++;
1455 }
1456
1457
1458 static
1459 VOID
1460 PrintPartitionData(
1461 PPARTLIST List,
1462 PDISKENTRY DiskEntry,
1463 PPARTENTRY PartEntry)
1464 {
1465 CHAR LineBuffer[128];
1466 COORD coPos;
1467 DWORD Written;
1468 USHORT Width;
1469 USHORT Height;
1470 LARGE_INTEGER PartSize;
1471 PCHAR Unit;
1472 UCHAR Attribute;
1473 PCHAR PartType;
1474
1475 Width = List->Right - List->Left - 1;
1476 Height = List->Bottom - List->Top - 2;
1477
1478 coPos.X = List->Left + 1;
1479 coPos.Y = List->Top + 1 + List->Line;
1480
1481 if (PartEntry->IsPartitioned == FALSE)
1482 {
1483 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1484 #if 0
1485 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1486 {
1487 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1488 Unit = MUIGetString(STRING_GB);
1489 }
1490 else
1491 #endif
1492 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1493 {
1494 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1495 Unit = MUIGetString(STRING_MB);
1496 }
1497 else
1498 {
1499 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1500 Unit = MUIGetString(STRING_KB);
1501 }
1502
1503 sprintf(LineBuffer,
1504 MUIGetString(STRING_UNPSPACE),
1505 PartEntry->LogicalPartition ? " " : "",
1506 PartEntry->LogicalPartition ? "" : " ",
1507 PartSize.u.LowPart,
1508 Unit);
1509 }
1510 else
1511 {
1512 /* Determine partition type */
1513 PartType = NULL;
1514 if (PartEntry->New == TRUE)
1515 {
1516 PartType = MUIGetString(STRING_UNFORMATTED);
1517 }
1518 else if (PartEntry->IsPartitioned == TRUE)
1519 {
1520 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
1521 (PartEntry->PartitionType == PARTITION_FAT_16) ||
1522 (PartEntry->PartitionType == PARTITION_HUGE) ||
1523 (PartEntry->PartitionType == PARTITION_XINT13))
1524 {
1525 PartType = "FAT";
1526 }
1527 else if ((PartEntry->PartitionType == PARTITION_FAT32) ||
1528 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
1529 {
1530 PartType = "FAT32";
1531 }
1532 else if (PartEntry->PartitionType == PARTITION_EXT2)
1533 {
1534 PartType = "EXT2";
1535 }
1536 else if (PartEntry->PartitionType == PARTITION_IFS)
1537 {
1538 PartType = "NTFS"; /* FIXME: Not quite correct! */
1539 }
1540 else if ((PartEntry->PartitionType == PARTITION_EXTENDED) ||
1541 (PartEntry->PartitionType == PARTITION_XINT13_EXTENDED))
1542 {
1543 PartType = MUIGetString(STRING_EXTENDED_PARTITION);
1544 }
1545 }
1546
1547 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1548 #if 0
1549 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1550 {
1551 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1552 Unit = MUIGetString(STRING_GB);
1553 }
1554 else
1555 #endif
1556 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1557 {
1558 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1559 Unit = MUIGetString(STRING_MB);
1560 }
1561 else
1562 {
1563 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1564 Unit = MUIGetString(STRING_KB);
1565 }
1566
1567 if (PartType == NULL)
1568 {
1569 sprintf(LineBuffer,
1570 MUIGetString(STRING_HDDINFOUNK5),
1571 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1572 (PartEntry->DriveLetter == 0) ? '-' : ':',
1573 PartEntry->BootIndicator ? '*' : ' ',
1574 PartEntry->LogicalPartition ? " " : "",
1575 PartEntry->PartitionType,
1576 PartEntry->LogicalPartition ? "" : " ",
1577 PartSize.u.LowPart,
1578 Unit);
1579 }
1580 else
1581 {
1582 sprintf(LineBuffer,
1583 "%c%c %c %s%-24s%s %6lu %s",
1584 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1585 (PartEntry->DriveLetter == 0) ? '-' : ':',
1586 PartEntry->BootIndicator ? '*' : ' ',
1587 PartEntry->LogicalPartition ? " " : "",
1588 PartType,
1589 PartEntry->LogicalPartition ? "" : " ",
1590 PartSize.u.LowPart,
1591 Unit);
1592 }
1593 }
1594
1595 Attribute = (List->CurrentDisk == DiskEntry &&
1596 List->CurrentPartition == PartEntry) ?
1597 FOREGROUND_BLUE | BACKGROUND_WHITE :
1598 FOREGROUND_WHITE | BACKGROUND_BLUE;
1599
1600 if (List->Line >= 0 && List->Line <= Height)
1601 {
1602 FillConsoleOutputCharacterA(StdOutput,
1603 ' ',
1604 Width,
1605 coPos,
1606 &Written);
1607 }
1608 coPos.X += 4;
1609 Width -= 8;
1610 if (List->Line >= 0 && List->Line <= Height)
1611 {
1612 FillConsoleOutputAttribute(StdOutput,
1613 Attribute,
1614 Width,
1615 coPos,
1616 &Written);
1617 }
1618 coPos.X++;
1619 Width -= 2;
1620 if (List->Line >= 0 && List->Line <= Height)
1621 {
1622 WriteConsoleOutputCharacterA(StdOutput,
1623 LineBuffer,
1624 min(strlen(LineBuffer), Width),
1625 coPos,
1626 &Written);
1627 }
1628
1629 List->Line++;
1630 }
1631
1632
1633 static
1634 VOID
1635 PrintDiskData(
1636 PPARTLIST List,
1637 PDISKENTRY DiskEntry)
1638 {
1639 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1640 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1641 CHAR LineBuffer[128];
1642 COORD coPos;
1643 DWORD Written;
1644 USHORT Width;
1645 USHORT Height;
1646 ULARGE_INTEGER DiskSize;
1647 PCHAR Unit;
1648
1649 Width = List->Right - List->Left - 1;
1650 Height = List->Bottom - List->Top - 2;
1651
1652 coPos.X = List->Left + 1;
1653 coPos.Y = List->Top + 1 + List->Line;
1654
1655 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1656 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1657 {
1658 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1659 Unit = MUIGetString(STRING_GB);
1660 }
1661 else
1662 {
1663 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1664 if (DiskSize.QuadPart == 0)
1665 DiskSize.QuadPart = 1;
1666 Unit = MUIGetString(STRING_MB);
1667 }
1668
1669 if (DiskEntry->DriverName.Length > 0)
1670 {
1671 sprintf(LineBuffer,
1672 MUIGetString(STRING_HDINFOPARTSELECT),
1673 DiskSize.u.LowPart,
1674 Unit,
1675 DiskEntry->DiskNumber,
1676 DiskEntry->Port,
1677 DiskEntry->Bus,
1678 DiskEntry->Id,
1679 DiskEntry->DriverName.Buffer);
1680 }
1681 else
1682 {
1683 sprintf(LineBuffer,
1684 MUIGetString(STRING_HDDINFOUNK6),
1685 DiskSize.u.LowPart,
1686 Unit,
1687 DiskEntry->DiskNumber,
1688 DiskEntry->Port,
1689 DiskEntry->Bus,
1690 DiskEntry->Id);
1691 }
1692
1693 if (List->Line >= 0 && List->Line <= Height)
1694 {
1695 FillConsoleOutputAttribute(StdOutput,
1696 FOREGROUND_WHITE | BACKGROUND_BLUE,
1697 Width,
1698 coPos,
1699 &Written);
1700
1701 FillConsoleOutputCharacterA(StdOutput,
1702 ' ',
1703 Width,
1704 coPos,
1705 &Written);
1706 }
1707
1708 coPos.X++;
1709 if (List->Line >= 0 && List->Line <= Height)
1710 {
1711 WriteConsoleOutputCharacterA(StdOutput,
1712 LineBuffer,
1713 min((USHORT)strlen(LineBuffer), Width - 2),
1714 coPos,
1715 &Written);
1716 }
1717
1718 List->Line++;
1719
1720 /* Print separator line */
1721 PrintEmptyLine(List);
1722
1723 /* Print partition lines*/
1724 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1725 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1726 {
1727 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1728
1729 PrintPartitionData(List,
1730 DiskEntry,
1731 PrimaryPartEntry);
1732
1733 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1734 {
1735 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1736 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1737 {
1738 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1739
1740 PrintPartitionData(List,
1741 DiskEntry,
1742 LogicalPartEntry);
1743
1744 LogicalEntry = LogicalEntry->Flink;
1745 }
1746 }
1747
1748 PrimaryEntry = PrimaryEntry->Flink;
1749 }
1750
1751 /* Print separator line */
1752 PrintEmptyLine(List);
1753 }
1754
1755
1756 VOID
1757 DrawPartitionList(
1758 PPARTLIST List)
1759 {
1760 PLIST_ENTRY Entry, Entry2;
1761 PDISKENTRY DiskEntry;
1762 PPARTENTRY PartEntry = NULL;
1763 COORD coPos;
1764 DWORD Written;
1765 SHORT i;
1766 SHORT CurrentDiskLine;
1767 SHORT CurrentPartLine;
1768 SHORT LastLine;
1769 BOOL CurrentPartLineFound = FALSE;
1770 BOOL CurrentDiskLineFound = FALSE;
1771
1772 /* Calculate the line of the current disk and partition */
1773 CurrentDiskLine = 0;
1774 CurrentPartLine = 0;
1775 LastLine = 0;
1776
1777 Entry = List->DiskListHead.Flink;
1778 while (Entry != &List->DiskListHead)
1779 {
1780 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1781
1782 LastLine += 2;
1783 if (CurrentPartLineFound == FALSE)
1784 {
1785 CurrentPartLine += 2;
1786 }
1787
1788 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1789 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1790 {
1791 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1792 if (PartEntry == List->CurrentPartition)
1793 {
1794 CurrentPartLineFound = TRUE;
1795 }
1796
1797 Entry2 = Entry2->Flink;
1798 if (CurrentPartLineFound == FALSE)
1799 {
1800 CurrentPartLine++;
1801 }
1802
1803 LastLine++;
1804 }
1805
1806 if (DiskEntry == List->CurrentDisk)
1807 {
1808 CurrentDiskLineFound = TRUE;
1809 }
1810
1811 Entry = Entry->Flink;
1812 if (Entry != &List->DiskListHead)
1813 {
1814 if (CurrentDiskLineFound == FALSE)
1815 {
1816 CurrentPartLine ++;
1817 CurrentDiskLine = CurrentPartLine;
1818 }
1819
1820 LastLine++;
1821 }
1822 else
1823 {
1824 LastLine--;
1825 }
1826 }
1827
1828 /* If it possible, make the disk name visible */
1829 if (CurrentPartLine < List->Offset)
1830 {
1831 List->Offset = CurrentPartLine;
1832 }
1833 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1834 {
1835 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1836 }
1837
1838 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1839 {
1840 List->Offset = CurrentDiskLine;
1841 }
1842
1843 /* draw upper left corner */
1844 coPos.X = List->Left;
1845 coPos.Y = List->Top;
1846 FillConsoleOutputCharacterA(StdOutput,
1847 0xDA, // '+',
1848 1,
1849 coPos,
1850 &Written);
1851
1852 /* draw upper edge */
1853 coPos.X = List->Left + 1;
1854 coPos.Y = List->Top;
1855 if (List->Offset == 0)
1856 {
1857 FillConsoleOutputCharacterA(StdOutput,
1858 0xC4, // '-',
1859 List->Right - List->Left - 1,
1860 coPos,
1861 &Written);
1862 }
1863 else
1864 {
1865 FillConsoleOutputCharacterA(StdOutput,
1866 0xC4, // '-',
1867 List->Right - List->Left - 5,
1868 coPos,
1869 &Written);
1870 coPos.X = List->Right - 5;
1871 WriteConsoleOutputCharacterA(StdOutput,
1872 "(\x18)", // "(up)"
1873 3,
1874 coPos,
1875 &Written);
1876 coPos.X = List->Right - 2;
1877 FillConsoleOutputCharacterA(StdOutput,
1878 0xC4, // '-',
1879 2,
1880 coPos,
1881 &Written);
1882 }
1883
1884 /* draw upper right corner */
1885 coPos.X = List->Right;
1886 coPos.Y = List->Top;
1887 FillConsoleOutputCharacterA(StdOutput,
1888 0xBF, // '+',
1889 1,
1890 coPos,
1891 &Written);
1892
1893 /* draw left and right edge */
1894 for (i = List->Top + 1; i < List->Bottom; i++)
1895 {
1896 coPos.X = List->Left;
1897 coPos.Y = i;
1898 FillConsoleOutputCharacterA(StdOutput,
1899 0xB3, // '|',
1900 1,
1901 coPos,
1902 &Written);
1903
1904 coPos.X = List->Right;
1905 FillConsoleOutputCharacterA(StdOutput,
1906 0xB3, //'|',
1907 1,
1908 coPos,
1909 &Written);
1910 }
1911
1912 /* draw lower left corner */
1913 coPos.X = List->Left;
1914 coPos.Y = List->Bottom;
1915 FillConsoleOutputCharacterA(StdOutput,
1916 0xC0, // '+',
1917 1,
1918 coPos,
1919 &Written);
1920
1921 /* draw lower edge */
1922 coPos.X = List->Left + 1;
1923 coPos.Y = List->Bottom;
1924 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1925 {
1926 FillConsoleOutputCharacterA(StdOutput,
1927 0xC4, // '-',
1928 List->Right - List->Left - 1,
1929 coPos,
1930 &Written);
1931 }
1932 else
1933 {
1934 FillConsoleOutputCharacterA(StdOutput,
1935 0xC4, // '-',
1936 List->Right - List->Left - 5,
1937 coPos,
1938 &Written);
1939 coPos.X = List->Right - 5;
1940 WriteConsoleOutputCharacterA(StdOutput,
1941 "(\x19)", // "(down)"
1942 3,
1943 coPos,
1944 &Written);
1945 coPos.X = List->Right - 2;
1946 FillConsoleOutputCharacterA(StdOutput,
1947 0xC4, // '-',
1948 2,
1949 coPos,
1950 &Written);
1951 }
1952
1953 /* draw lower right corner */
1954 coPos.X = List->Right;
1955 coPos.Y = List->Bottom;
1956 FillConsoleOutputCharacterA(StdOutput,
1957 0xD9, // '+',
1958 1,
1959 coPos,
1960 &Written);
1961
1962 /* print list entries */
1963 List->Line = - List->Offset;
1964
1965 Entry = List->DiskListHead.Flink;
1966 while (Entry != &List->DiskListHead)
1967 {
1968 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1969
1970 /* Print disk entry */
1971 PrintDiskData(List,
1972 DiskEntry);
1973
1974 Entry = Entry->Flink;
1975 }
1976 }
1977
1978
1979 DWORD
1980 SelectPartition(
1981 PPARTLIST List,
1982 ULONG DiskNumber,
1983 ULONG PartitionNumber)
1984 {
1985 PDISKENTRY DiskEntry;
1986 PPARTENTRY PartEntry;
1987 PLIST_ENTRY Entry1;
1988 PLIST_ENTRY Entry2;
1989
1990 /* Check for empty disks */
1991 if (IsListEmpty(&List->DiskListHead))
1992 return FALSE;
1993
1994 /* Check for first usable entry on next disk */
1995 Entry1 = List->CurrentDisk->ListEntry.Flink;
1996 while (Entry1 != &List->DiskListHead)
1997 {
1998 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1999
2000 if (DiskEntry->DiskNumber == DiskNumber)
2001 {
2002 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2003 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2004 {
2005 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2006
2007 if (PartEntry->PartitionNumber == PartitionNumber)
2008 {
2009 List->CurrentDisk = DiskEntry;
2010 List->CurrentPartition = PartEntry;
2011 DrawPartitionList(List);
2012 return TRUE;
2013 }
2014
2015 Entry2 = Entry2->Flink;
2016 }
2017
2018 return FALSE;
2019 }
2020
2021 Entry1 = Entry1->Flink;
2022 }
2023
2024 return FALSE;
2025 }
2026
2027
2028 BOOL
2029 ScrollDownPartitionList(
2030 PPARTLIST List)
2031 {
2032 PLIST_ENTRY DiskListEntry;
2033 PLIST_ENTRY PartListEntry;
2034 PDISKENTRY DiskEntry;
2035 PPARTENTRY PartEntry;
2036
2037 /* Fail, if no disks are available */
2038 if (IsListEmpty(&List->DiskListHead))
2039 return FALSE;
2040
2041 /* Check for next usable entry on current disk */
2042 if (List->CurrentPartition != NULL)
2043 {
2044 if (List->CurrentPartition->LogicalPartition)
2045 {
2046 /* Logical partition */
2047
2048 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2049 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2050 {
2051 /* Next logical partition */
2052 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2053
2054 List->CurrentPartition = PartEntry;
2055 return TRUE;
2056 }
2057 else
2058 {
2059 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2060 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2061 {
2062 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2063
2064 List->CurrentPartition = PartEntry;
2065 return TRUE;
2066 }
2067 }
2068 }
2069 else
2070 {
2071 /* Primary or extended partition */
2072
2073 if (List->CurrentPartition->IsPartitioned == TRUE &&
2074 IsContainerPartition(List->CurrentPartition->PartitionType))
2075 {
2076 /* First logical partition */
2077 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2078 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2079 {
2080 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2081
2082 List->CurrentPartition = PartEntry;
2083 return TRUE;
2084 }
2085 }
2086 else
2087 {
2088 /* Next primary partition */
2089 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2090 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2091 {
2092 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2093
2094 List->CurrentPartition = PartEntry;
2095 return TRUE;
2096 }
2097 }
2098 }
2099 }
2100
2101 /* Search for the first partition entry on the next disk */
2102 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2103 while (DiskListEntry != &List->DiskListHead)
2104 {
2105 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2106
2107 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2108 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2109 {
2110 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2111
2112 List->CurrentDisk = DiskEntry;
2113 List->CurrentPartition = PartEntry;
2114 return TRUE;
2115 }
2116
2117 DiskListEntry = DiskListEntry->Flink;
2118 }
2119
2120 return FALSE;
2121 }
2122
2123
2124 BOOL
2125 ScrollUpPartitionList(
2126 PPARTLIST List)
2127 {
2128 PLIST_ENTRY DiskListEntry;
2129 PLIST_ENTRY PartListEntry;
2130 PDISKENTRY DiskEntry;
2131 PPARTENTRY PartEntry;
2132
2133 /* Fail, if no disks are available */
2134 if (IsListEmpty(&List->DiskListHead))
2135 return FALSE;
2136
2137 /* Check for previous usable entry on current disk */
2138 if (List->CurrentPartition != NULL)
2139 {
2140 if (List->CurrentPartition->LogicalPartition)
2141 {
2142 /* Logical partition */
2143 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2144 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2145 {
2146 /* Previous logical partition */
2147 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2148 }
2149 else
2150 {
2151 /* Extended partition*/
2152 PartEntry = List->CurrentDisk->ExtendedPartition;
2153 }
2154
2155 List->CurrentPartition = PartEntry;
2156 return TRUE;
2157 }
2158 else
2159 {
2160 /* Primary or extended partition */
2161
2162 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2163 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2164 {
2165 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2166
2167 if (PartEntry->IsPartitioned == TRUE &&
2168 IsContainerPartition(PartEntry->PartitionType))
2169 {
2170 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2171 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2172 }
2173
2174 List->CurrentPartition = PartEntry;
2175 return TRUE;
2176 }
2177
2178 }
2179 }
2180
2181 /* Search for the last partition entry on the previous disk */
2182 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2183 while (DiskListEntry != &List->DiskListHead)
2184 {
2185 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2186
2187 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2188 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2189 {
2190 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2191
2192 if (PartEntry->IsPartitioned == TRUE &&
2193 IsContainerPartition(PartEntry->PartitionType))
2194 {
2195 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2196 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2197 {
2198 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2199
2200 List->CurrentDisk = DiskEntry;
2201 List->CurrentPartition = PartEntry;
2202 return TRUE;
2203 }
2204 }
2205 else
2206 {
2207 List->CurrentDisk = DiskEntry;
2208 List->CurrentPartition = PartEntry;
2209 return TRUE;
2210 }
2211 }
2212
2213 DiskListEntry = DiskListEntry->Blink;
2214 }
2215
2216 return FALSE;
2217 }
2218
2219
2220 static
2221 BOOLEAN
2222 IsEmptyLayoutEntry(
2223 PPARTITION_INFORMATION PartitionInfo)
2224 {
2225 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2226 PartitionInfo->PartitionLength.QuadPart == 0)
2227 // PartitionInfo->PartitionType == 0)
2228 return TRUE;
2229
2230 return FALSE;
2231 }
2232
2233
2234 static
2235 BOOLEAN
2236 IsSamePrimaryLayoutEntry(
2237 IN PPARTITION_INFORMATION PartitionInfo,
2238 IN PDISKENTRY DiskEntry,
2239 IN PPARTENTRY PartEntry)
2240 {
2241 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2242 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2243 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2244 // PartitionInfo->PartitionType == PartEntry->PartitionType
2245 return TRUE;
2246
2247 return FALSE;
2248 }
2249
2250
2251 static
2252 VOID
2253 UpdateDiskLayout(
2254 IN PDISKENTRY DiskEntry)
2255 {
2256 PPARTITION_INFORMATION PartitionInfo;
2257 PLIST_ENTRY ListEntry;
2258 PPARTENTRY PartEntry;
2259 ULONG Index = 0;
2260 ULONG PartitionNumber = 1;
2261
2262 DPRINT1("UpdateDiskLayout()\n");
2263
2264 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2265 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2266 {
2267 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2268
2269 if (PartEntry->IsPartitioned == TRUE)
2270 {
2271 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2272
2273 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2274 {
2275 DPRINT1("Updating partition entry %lu\n", Index);
2276
2277 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2278 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2279 PartitionInfo->HiddenSectors = 0;
2280 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2281 PartitionInfo->PartitionType = PartEntry->PartitionType;
2282 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2283 PartitionInfo->RecognizedPartition = FALSE;
2284 PartitionInfo->RewritePartition = TRUE;
2285
2286 PartEntry->PartitionNumber = PartitionNumber;
2287 PartEntry->PartitionIndex = Index;
2288
2289 PartitionNumber++;
2290 }
2291 else if (!IsEmptyLayoutEntry(PartitionInfo))
2292 {
2293 PartitionNumber++;
2294 }
2295
2296 Index++;
2297 }
2298
2299 ListEntry = ListEntry->Flink;
2300 }
2301
2302 for (;Index < 4; Index++)
2303 {
2304 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2305
2306 if (!IsEmptyLayoutEntry(PartitionInfo))
2307 {
2308 DPRINT1("Wiping partition entry %lu\n", Index);
2309
2310 PartitionInfo->StartingOffset.QuadPart = 0;
2311 PartitionInfo->PartitionLength.QuadPart = 0;
2312 PartitionInfo->HiddenSectors = 0;
2313 PartitionInfo->PartitionNumber = 0;
2314 PartitionInfo->PartitionType = 0;
2315 PartitionInfo->BootIndicator = FALSE;
2316 PartitionInfo->RecognizedPartition = FALSE;
2317 PartitionInfo->RewritePartition = TRUE;
2318 }
2319 }
2320
2321 #ifdef DUMP_PARTITION_TABLE
2322 DumpPartitionTable(DiskEntry);
2323 #endif
2324 }
2325
2326
2327 static
2328 PPARTENTRY
2329 GetPrevUnpartitionedEntry(
2330 PDISKENTRY DiskEntry,
2331 PPARTENTRY PartEntry)
2332 {
2333 PPARTENTRY PrevPartEntry;
2334
2335 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2336 {
2337 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2338 PARTENTRY,
2339 ListEntry);
2340 if (PrevPartEntry->IsPartitioned == FALSE)
2341 return PrevPartEntry;
2342 }
2343
2344 return NULL;
2345 }
2346
2347
2348 static
2349 PPARTENTRY
2350 GetNextUnpartitionedEntry(
2351 PDISKENTRY DiskEntry,
2352 PPARTENTRY PartEntry)
2353 {
2354 PPARTENTRY NextPartEntry;
2355
2356 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2357 {
2358 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2359 PARTENTRY,
2360 ListEntry);
2361 if (NextPartEntry->IsPartitioned == FALSE)
2362 return NextPartEntry;
2363 }
2364
2365 return NULL;
2366 }
2367
2368
2369 VOID
2370 CreatePrimaryPartition(
2371 PPARTLIST List,
2372 ULONGLONG SectorCount,
2373 BOOLEAN AutoCreate)
2374 {
2375 PDISKENTRY DiskEntry;
2376 PPARTENTRY PartEntry;
2377 PPARTENTRY NewPartEntry;
2378
2379 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2380
2381 if (List == NULL ||
2382 List->CurrentDisk == NULL ||
2383 List->CurrentPartition == NULL ||
2384 List->CurrentPartition->IsPartitioned == TRUE)
2385 {
2386 return;
2387 }
2388
2389 DiskEntry = List->CurrentDisk;
2390 PartEntry = List->CurrentPartition;
2391
2392 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2393
2394 if (AutoCreate == TRUE ||
2395 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2396 {
2397 DPRINT1("Convert existing partition entry\n");
2398
2399 /* Convert current entry to 'new (unformatted)' */
2400 PartEntry->IsPartitioned = TRUE;
2401 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2402 PartEntry->FormatState = Unformatted;
2403 PartEntry->AutoCreate = AutoCreate;
2404 PartEntry->New = TRUE;
2405 PartEntry->BootIndicator = FALSE;
2406
2407 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2408 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2409 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2410 }
2411 else
2412 {
2413 DPRINT1("Add new partition entry\n");
2414
2415 /* Insert and initialize a new partition entry */
2416 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2417 HEAP_ZERO_MEMORY,
2418 sizeof(PARTENTRY));
2419 if (NewPartEntry == NULL)
2420 return;
2421
2422 /* Insert the new entry into the list */
2423 InsertTailList(&PartEntry->ListEntry,
2424 &NewPartEntry->ListEntry);
2425
2426 NewPartEntry->DiskEntry = DiskEntry;
2427
2428 NewPartEntry->IsPartitioned = TRUE;
2429 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2430 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2431 NewPartEntry->StartSector.QuadPart;
2432 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2433
2434 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2435 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2436 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2437
2438 NewPartEntry->New = TRUE;
2439 NewPartEntry->FormatState = Unformatted;
2440 NewPartEntry->BootIndicator = FALSE;
2441
2442 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2443 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2444 }
2445
2446 UpdateDiskLayout(DiskEntry);
2447
2448 DiskEntry->Dirty = TRUE;
2449
2450 UpdatePartitionNumbers(DiskEntry);
2451
2452 AssignDriveLetters(List);
2453 }
2454
2455
2456 static
2457 VOID
2458 AddLogicalDiskSpace(
2459 PDISKENTRY DiskEntry)
2460 {
2461 PPARTENTRY NewPartEntry;
2462
2463 DPRINT1("AddLogicalDiskSpace()\n");
2464
2465 /* Create a partition table entry that represents the empty space in the container partition */
2466 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2467 HEAP_ZERO_MEMORY,
2468 sizeof(PARTENTRY));
2469 if (NewPartEntry == NULL)
2470 return;
2471
2472 NewPartEntry->DiskEntry = DiskEntry;
2473 NewPartEntry->LogicalPartition = TRUE;
2474
2475 NewPartEntry->IsPartitioned = FALSE;
2476 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2477 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2478
2479 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2480 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2481 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2482
2483 NewPartEntry->FormatState = Unformatted;
2484
2485 InsertTailList(&DiskEntry->LogicalPartListHead,
2486 &NewPartEntry->ListEntry);
2487 }
2488
2489
2490 VOID
2491 CreateExtendedPartition(
2492 PPARTLIST List,
2493 ULONGLONG SectorCount)
2494 {
2495 PDISKENTRY DiskEntry;
2496 PPARTENTRY PartEntry;
2497 PPARTENTRY NewPartEntry;
2498
2499 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2500
2501 if (List == NULL ||
2502 List->CurrentDisk == NULL ||
2503 List->CurrentPartition == NULL ||
2504 List->CurrentPartition->IsPartitioned == TRUE)
2505 {
2506 return;
2507 }
2508
2509 DiskEntry = List->CurrentDisk;
2510 PartEntry = List->CurrentPartition;
2511
2512 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2513
2514 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2515 {
2516 DPRINT1("Convert existing partition entry\n");
2517
2518 /* Convert current entry to 'new (unformatted)' */
2519 PartEntry->IsPartitioned = TRUE;
2520 PartEntry->FormatState = Formatted;
2521 PartEntry->AutoCreate = FALSE;
2522 PartEntry->New = FALSE;
2523 PartEntry->BootIndicator = FALSE;
2524
2525 if (PartEntry->StartSector.QuadPart < 1450560)
2526 {
2527 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2528 PartEntry->PartitionType = PARTITION_EXTENDED;
2529 }
2530 else
2531 {
2532 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2533 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2534 }
2535
2536 DiskEntry->ExtendedPartition = PartEntry;
2537
2538 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2539 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2540 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2541 }
2542 else
2543 {
2544 DPRINT1("Add new partition entry\n");
2545
2546 /* Insert and initialize a new partition entry */
2547 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2548 HEAP_ZERO_MEMORY,
2549 sizeof(PARTENTRY));
2550 if (NewPartEntry == NULL)
2551 return;
2552
2553 /* Insert the new entry into the list */
2554 InsertTailList(&PartEntry->ListEntry,
2555 &NewPartEntry->ListEntry);
2556
2557 NewPartEntry->DiskEntry = DiskEntry;
2558
2559 NewPartEntry->IsPartitioned = TRUE;
2560 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2561 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2562 NewPartEntry->StartSector.QuadPart;
2563
2564 NewPartEntry->New = FALSE;
2565 NewPartEntry->FormatState = Formatted;
2566 NewPartEntry->BootIndicator = FALSE;
2567
2568 if (NewPartEntry->StartSector.QuadPart < 1450560)
2569 {
2570 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2571 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2572 }
2573 else
2574 {
2575 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2576 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2577 }
2578
2579 DiskEntry->ExtendedPartition = NewPartEntry;
2580
2581 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2582 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2583
2584 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2585 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2586 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2587 }
2588
2589 AddLogicalDiskSpace(DiskEntry);
2590
2591 UpdateDiskLayout(DiskEntry);
2592
2593 DiskEntry->Dirty = TRUE;
2594
2595 UpdatePartitionNumbers(DiskEntry);
2596
2597 AssignDriveLetters(List);
2598 }
2599
2600
2601 VOID
2602 CreateLogicalPartition(
2603 PPARTLIST List,
2604 ULONGLONG SectorCount)
2605 {
2606 // PDISKENTRY DiskEntry;
2607 PPARTENTRY PartEntry;
2608 // PPARTENTRY NewPartEntry;
2609
2610 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2611
2612 if (List == NULL ||
2613 List->CurrentDisk == NULL ||
2614 List->CurrentPartition == NULL ||
2615 List->CurrentPartition->IsPartitioned == TRUE)
2616 {
2617 return;
2618 }
2619
2620 // DiskEntry = List->CurrentDisk;
2621 PartEntry = List->CurrentPartition;
2622
2623 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2624 }
2625
2626
2627 VOID
2628 DeleteCurrentPartition(
2629 PPARTLIST List)
2630 {
2631 PDISKENTRY DiskEntry;
2632 PPARTENTRY PartEntry;
2633 PPARTENTRY PrevPartEntry;
2634 PPARTENTRY NextPartEntry;
2635 PPARTENTRY LogicalPartEntry;
2636 PLIST_ENTRY Entry;
2637
2638 if (List == NULL ||
2639 List->CurrentDisk == NULL ||
2640 List->CurrentPartition == NULL ||
2641 List->CurrentPartition->IsPartitioned == FALSE)
2642 {
2643 return;
2644 }
2645
2646 DiskEntry = List->CurrentDisk;
2647 PartEntry = List->CurrentPartition;
2648
2649 /* Delete all logical partiton entries if an extended partition will be deleted */
2650 if (DiskEntry->ExtendedPartition == PartEntry)
2651 {
2652 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2653 {
2654 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2655 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2656
2657 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2658 }
2659
2660 DiskEntry->ExtendedPartition = NULL;
2661 }
2662
2663 /* Adjust unpartitioned disk space entries */
2664
2665 /* Get pointer to previous and next unpartitioned entries */
2666 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2667 PartEntry);
2668
2669 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2670 PartEntry);
2671
2672 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2673 {
2674 /* Merge previous, current and next unpartitioned entry */
2675
2676 /* Adjust the previous entries length */
2677 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2678
2679 /* Remove the current entry */
2680 RemoveEntryList(&PartEntry->ListEntry);
2681 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2682
2683 /* Remove the next entry */
2684 RemoveEntryList (&NextPartEntry->ListEntry);
2685 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2686
2687 /* Update current partition */
2688 List->CurrentPartition = PrevPartEntry;
2689 }
2690 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2691 {
2692 /* Merge current and previous unpartitioned entry */
2693
2694 /* Adjust the previous entries length */
2695 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2696
2697 /* Remove the current entry */
2698 RemoveEntryList(&PartEntry->ListEntry);
2699 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2700
2701 /* Update current partition */
2702 List->CurrentPartition = PrevPartEntry;
2703 }
2704 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2705 {
2706 /* Merge current and next unpartitioned entry */
2707
2708 /* Adjust the next entries offset and length */
2709 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2710 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2711
2712 /* Remove the current entry */
2713 RemoveEntryList(&PartEntry->ListEntry);
2714 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2715
2716 /* Update current partition */
2717 List->CurrentPartition = NextPartEntry;
2718 }
2719 else
2720 {
2721 /* Nothing to merge but change current entry */
2722 PartEntry->IsPartitioned = FALSE;
2723 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2724 PartEntry->FormatState = Unformatted;
2725 PartEntry->DriveLetter = 0;
2726 }
2727
2728 UpdateDiskLayout(DiskEntry);
2729
2730 DiskEntry->Dirty = TRUE;
2731
2732 UpdatePartitionNumbers(DiskEntry);
2733
2734 AssignDriveLetters(List);
2735 }
2736
2737
2738 VOID
2739 CheckActiveBootPartition(
2740 PPARTLIST List)
2741 {
2742 PDISKENTRY DiskEntry;
2743 PPARTENTRY PartEntry;
2744 PLIST_ENTRY ListEntry;
2745
2746 /* Check for empty disk list */
2747 if (IsListEmpty (&List->DiskListHead))
2748 {
2749 List->BootDisk = NULL;
2750 List->BootPartition = NULL;
2751 return;
2752 }
2753
2754 #if 0
2755 if (List->BootDisk != NULL &&
2756 List->BootPartition != NULL)
2757 {
2758 /* We already have an active boot partition */
2759 return;
2760 }
2761 #endif
2762
2763 /* Choose the currently selected disk */
2764 DiskEntry = List->CurrentDisk;
2765
2766 /* Check for empty partition list */
2767 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2768 {
2769 List->BootDisk = NULL;
2770 List->BootPartition = NULL;
2771 return;
2772 }
2773
2774 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2775 PARTENTRY,
2776 ListEntry);
2777
2778 /* Set active boot partition */
2779 if ((DiskEntry->NewDisk == TRUE) ||
2780 (PartEntry->BootIndicator == FALSE))
2781 {
2782 PartEntry->BootIndicator = TRUE;
2783 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2784 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2785 DiskEntry->Dirty = TRUE;
2786
2787 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2788 List->BootDisk = DiskEntry;
2789 List->BootPartition = PartEntry;
2790
2791 return;
2792 }
2793
2794 /* Disk is not new, scan all partitions to find a bootable one */
2795 List->BootDisk = NULL;
2796 List->BootPartition = NULL;
2797
2798 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2799 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2800 {
2801 PartEntry = CONTAINING_RECORD(ListEntry,
2802 PARTENTRY,
2803 ListEntry);
2804
2805 /* Check if it is partitioned */
2806 if (PartEntry->IsPartitioned)
2807 {
2808 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2809 PartEntry->BootIndicator)
2810 {
2811 /* Yes, we found it */
2812 List->BootDisk = DiskEntry;
2813 List->BootPartition = PartEntry;
2814
2815 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2816 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2817 break;
2818 }
2819 }
2820
2821 /* Go to the next one */
2822 ListEntry = ListEntry->Flink;
2823 }
2824 }
2825
2826
2827 BOOLEAN
2828 CheckForLinuxFdiskPartitions(
2829 PPARTLIST List)
2830 {
2831 #if 0
2832 PDISKENTRY DiskEntry;
2833 PPARTENTRY PartEntry;
2834 PLIST_ENTRY Entry1;
2835 PLIST_ENTRY Entry2;
2836 ULONG PartitionCount;
2837 ULONG i;
2838
2839 Entry1 = List->DiskListHead.Flink;
2840 while (Entry1 != &List->DiskListHead)
2841 {
2842 DiskEntry = CONTAINING_RECORD(Entry1,
2843 DISKENTRY,
2844 ListEntry);
2845
2846 Entry2 = DiskEntry->PartListHead.Flink;
2847 while (Entry2 != &DiskEntry->PartListHead)
2848 {
2849 PartEntry = CONTAINING_RECORD(Entry2,
2850 PARTENTRY,
2851 ListEntry);
2852
2853 if (PartEntry->Unpartitioned == FALSE)
2854 {
2855 PartitionCount = 0;
2856
2857 for (i = 0; i < 4; i++)
2858 {
2859 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2860 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2861 {
2862 PartitionCount++;
2863 }
2864 }
2865
2866 if (PartitionCount > 1)
2867 {
2868 return TRUE;
2869 }
2870 }
2871
2872 Entry2 = Entry2->Flink;
2873 }
2874
2875 Entry1 = Entry1->Flink;
2876 }
2877 #endif
2878
2879 return FALSE;
2880 }
2881
2882
2883 static
2884 NTSTATUS
2885 WritePartitons(
2886 IN PPARTLIST List,
2887 IN PDISKENTRY DiskEntry)
2888 {
2889 WCHAR DstPath[MAX_PATH];
2890 OBJECT_ATTRIBUTES ObjectAttributes;
2891 IO_STATUS_BLOCK Iosb;
2892 UNICODE_STRING Name;
2893 ULONG BufferSize;
2894 HANDLE FileHandle = NULL;
2895 NTSTATUS Status;
2896
2897 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2898
2899 swprintf(DstPath,
2900 L"\\Device\\Harddisk%d\\Partition0",
2901 DiskEntry->DiskNumber);
2902 RtlInitUnicodeString(&Name,
2903 DstPath);
2904 InitializeObjectAttributes(&ObjectAttributes,
2905 &Name,
2906 0,
2907 NULL,
2908 NULL);
2909
2910 Status = NtOpenFile(&FileHandle,
2911 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2912 &ObjectAttributes,
2913 &Iosb,
2914 0,
2915 FILE_SYNCHRONOUS_IO_NONALERT);
2916 if (!NT_SUCCESS(Status))
2917 {
2918 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2919 return Status;
2920 }
2921
2922 #ifdef DUMP_PARTITION_TABLE
2923 DumpPartitionTable(DiskEntry);
2924 #endif
2925
2926 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2927 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2928 Status = NtDeviceIoControlFile(FileHandle,
2929 NULL,
2930 NULL,
2931 NULL,
2932 &Iosb,
2933 IOCTL_DISK_SET_DRIVE_LAYOUT,
2934 DiskEntry->LayoutBuffer,
2935 BufferSize,
2936 NULL,
2937 0);
2938 if (!NT_SUCCESS(Status))
2939 {
2940 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2941 }
2942
2943 if (FileHandle != NULL)
2944 NtClose(FileHandle);
2945
2946 return Status;
2947 }
2948
2949
2950 BOOLEAN
2951 WritePartitionsToDisk(
2952 PPARTLIST List)
2953 {
2954 PLIST_ENTRY Entry;
2955 PDISKENTRY DiskEntry;
2956
2957 if (List == NULL)
2958 return TRUE;
2959
2960 Entry = List->DiskListHead.Flink;
2961 while (Entry != &List->DiskListHead)
2962 {
2963 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2964
2965 if (DiskEntry->Dirty == TRUE)
2966 {
2967 WritePartitons(List, DiskEntry);
2968 DiskEntry->Dirty = FALSE;
2969 }
2970
2971 Entry = Entry->Flink;
2972 }
2973
2974 return TRUE;
2975 }
2976
2977
2978 BOOL
2979 SetMountedDeviceValues(
2980 PPARTLIST List)
2981 {
2982 PLIST_ENTRY Entry1, Entry2;
2983 PDISKENTRY DiskEntry;
2984 PPARTENTRY PartEntry;
2985 LARGE_INTEGER StartingOffset;
2986
2987 if (List == NULL)
2988 {
2989 return FALSE;
2990 }
2991
2992 Entry1 = List->DiskListHead.Flink;
2993 while (Entry1 != &List->DiskListHead)
2994 {
2995 DiskEntry = CONTAINING_RECORD(Entry1,
2996 DISKENTRY,
2997 ListEntry);
2998
2999 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3000 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3001 {
3002 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3003 if (PartEntry->IsPartitioned)
3004 {
3005 if (PartEntry->DriveLetter)
3006 {
3007 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3008 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3009 DiskEntry->LayoutBuffer->Signature,
3010 StartingOffset))
3011 {
3012 return FALSE;
3013 }
3014 }
3015 }
3016
3017 Entry2 = Entry2->Flink;
3018 }
3019
3020 Entry1 = Entry1->Flink;
3021 }
3022
3023 return TRUE;
3024 }
3025
3026
3027 static
3028 ULONG
3029 GetPrimaryPartitionCount(
3030 IN PDISKENTRY DiskEntry)
3031 {
3032 PLIST_ENTRY Entry;
3033 PPARTENTRY PartEntry;
3034 UINT nCount = 0;
3035
3036 Entry = DiskEntry->PrimaryPartListHead.Flink;
3037 while (Entry != &DiskEntry->PrimaryPartListHead)
3038 {
3039 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3040 if (PartEntry->IsPartitioned == TRUE)
3041 nCount++;
3042
3043 Entry = Entry->Flink;
3044 }
3045
3046 return nCount;
3047 }
3048
3049
3050 ULONG
3051 PrimaryPartitionCreationChecks(
3052 IN PPARTLIST List)
3053 {
3054 PDISKENTRY DiskEntry;
3055 PPARTENTRY PartEntry;
3056
3057 DiskEntry = List->CurrentDisk;
3058 PartEntry = List->CurrentPartition;
3059
3060 /* Fail if partition is already in use */
3061 if (PartEntry->IsPartitioned == TRUE)
3062 return ERROR_NEW_PARTITION;
3063
3064 /* Fail if there are more than 4 partitions in the list */
3065 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3066 return ERROR_PARTITION_TABLE_FULL;
3067
3068 return ERROR_SUCCESS;
3069 }
3070
3071
3072 ULONG
3073 ExtendedPartitionCreationChecks(
3074 IN PPARTLIST List)
3075 {
3076 PDISKENTRY DiskEntry;
3077 PPARTENTRY PartEntry;
3078
3079 DiskEntry = List->CurrentDisk;
3080 PartEntry = List->CurrentPartition;
3081
3082 /* Fail if partition is already in use */
3083 if (PartEntry->IsPartitioned == TRUE)
3084 return ERROR_NEW_PARTITION;
3085
3086 /* Fail if there are more than 4 partitions in the list */
3087 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3088 return ERROR_PARTITION_TABLE_FULL;
3089
3090 /* Fail if there is another extended partition in the list */
3091 if (DiskEntry->ExtendedPartition != NULL)
3092 return ERROR_ONLY_ONE_EXTENDED;
3093
3094 return ERROR_SUCCESS;
3095 }
3096
3097
3098 ULONG
3099 LogicalPartitionCreationChecks(
3100 IN PPARTLIST List)
3101 {
3102 // PDISKENTRY DiskEntry;
3103 PPARTENTRY PartEntry;
3104
3105 // DiskEntry = List->CurrentDisk;
3106 PartEntry = List->CurrentPartition;
3107
3108 /* Fail if partition is already in use */
3109 if (PartEntry->IsPartitioned == TRUE)
3110 return ERROR_NEW_PARTITION;
3111
3112 return ERROR_SUCCESS;
3113 }
3114
3115
3116 BOOL
3117 GetNextUnformattedPartition(
3118 IN PPARTLIST List,
3119 OUT PDISKENTRY *pDiskEntry,
3120 OUT PPARTENTRY *pPartEntry)
3121 {
3122 PLIST_ENTRY Entry1, Entry2;
3123 PDISKENTRY DiskEntry;
3124 PPARTENTRY PartEntry;
3125
3126 Entry1 = List->DiskListHead.Flink;
3127 while (Entry1 != &List->DiskListHead)
3128 {
3129 DiskEntry = CONTAINING_RECORD(Entry1,
3130 DISKENTRY,
3131 ListEntry);
3132
3133 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3134 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3135 {
3136 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3137 if (PartEntry->IsPartitioned && PartEntry->New)
3138 {
3139 *pDiskEntry = DiskEntry;
3140 *pPartEntry = PartEntry;
3141 return TRUE;
3142 }
3143
3144 Entry2 = Entry2->Flink;
3145 }
3146
3147 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3148 while (Entry2 != &DiskEntry->LogicalPartListHead)
3149 {
3150 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3151 if (PartEntry->IsPartitioned && PartEntry->New)
3152 {
3153 *pDiskEntry = DiskEntry;
3154 *pPartEntry = PartEntry;
3155 return TRUE;
3156 }
3157
3158 Entry2 = Entry2->Flink;
3159 }
3160
3161 Entry1 = Entry1->Flink;
3162 }
3163
3164 *pDiskEntry = NULL;
3165 *pPartEntry = NULL;
3166
3167 return FALSE;
3168 }
3169
3170
3171 BOOL
3172 GetNextUncheckedPartition(
3173 IN PPARTLIST List,
3174 OUT PDISKENTRY *pDiskEntry,
3175 OUT PPARTENTRY *pPartEntry)
3176 {
3177 PLIST_ENTRY Entry1, Entry2;
3178 PDISKENTRY DiskEntry;
3179 PPARTENTRY PartEntry;
3180
3181 Entry1 = List->DiskListHead.Flink;
3182 while (Entry1 != &List->DiskListHead)
3183 {
3184 DiskEntry = CONTAINING_RECORD(Entry1,
3185 DISKENTRY,
3186 ListEntry);
3187
3188 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3189 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3190 {
3191 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3192 if (PartEntry->NeedsCheck == TRUE)
3193 {
3194 *pDiskEntry = DiskEntry;
3195 *pPartEntry = PartEntry;
3196 return TRUE;
3197 }
3198
3199 Entry2 = Entry2->Flink;
3200 }
3201
3202 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3203 while (Entry2 != &DiskEntry->LogicalPartListHead)
3204 {
3205 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3206 if (PartEntry->NeedsCheck == TRUE)
3207 {
3208 *pDiskEntry = DiskEntry;
3209 *pPartEntry = PartEntry;
3210 return TRUE;
3211 }
3212
3213 Entry2 = Entry2->Flink;
3214 }
3215
3216 Entry1 = Entry1->Flink;
3217 }
3218
3219 *pDiskEntry = NULL;
3220 *pPartEntry = NULL;
3221
3222 return FALSE;
3223 }
3224
3225 /* EOF */