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