70c606027b93148b33ca95c468efb5646c575011
[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 DbgPrint("%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 AddPrimaryPartitionToDisk(
524 ULONG DiskNumber,
525 PDISKENTRY DiskEntry,
526 ULONG PartitionIndex)
527 {
528 PPARTITION_INFORMATION PartitionInfo;
529 PPARTENTRY PartEntry;
530
531 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
532
533 PartEntry = RtlAllocateHeap(ProcessHeap,
534 HEAP_ZERO_MEMORY,
535 sizeof(PARTENTRY));
536 if (PartEntry == NULL)
537 {
538 return;
539 }
540
541 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
542 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
543
544 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
545 PartEntry->PartitionType = PartitionInfo->PartitionType;
546 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
547
548 PartEntry->IsPartitioned = TRUE;
549 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
550 PartEntry->PartitionIndex = PartitionIndex;
551
552 if (IsContainerPartition(PartEntry->PartitionType))
553 {
554 PartEntry->FormatState = Unformatted;
555 }
556 else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
557 (PartEntry->PartitionType == PARTITION_FAT_16) ||
558 (PartEntry->PartitionType == PARTITION_HUGE) ||
559 (PartEntry->PartitionType == PARTITION_XINT13) ||
560 (PartEntry->PartitionType == PARTITION_FAT32) ||
561 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
562 {
563 #if 0
564 if (CheckFatFormat())
565 {
566 PartEntry->FormatState = Preformatted;
567 }
568 else
569 {
570 PartEntry->FormatState = Unformatted;
571 }
572 #endif
573 PartEntry->FormatState = Preformatted;
574 }
575 else if (PartEntry->PartitionType == PARTITION_EXT2)
576 {
577 #if 0
578 if (CheckExt2Format())
579 {
580 PartEntry->FormatState = Preformatted;
581 }
582 else
583 {
584 PartEntry->FormatState = Unformatted;
585 }
586 #endif
587 PartEntry->FormatState = Preformatted;
588 }
589 else if (PartEntry->PartitionType == PARTITION_IFS)
590 {
591 #if 0
592 if (CheckNtfsFormat())
593 {
594 PartEntry->FormatState = Preformatted;
595 }
596 else if (CheckHpfsFormat())
597 {
598 PartEntry->FormatState = Preformatted;
599 }
600 else
601 {
602 PartEntry->FormatState = Unformatted;
603 }
604 #endif
605 PartEntry->FormatState = Preformatted;
606 }
607 else
608 {
609 PartEntry->FormatState = UnknownFormat;
610 }
611
612 InsertTailList(&DiskEntry->PrimaryPartListHead,
613 &PartEntry->ListEntry);
614 }
615
616
617 static
618 VOID
619 ScanForUnpartitionedDiskSpace(
620 PDISKENTRY DiskEntry)
621 {
622 ULONGLONG LastStartSector;
623 ULONGLONG LastSectorCount;
624 ULONGLONG LastUnusedSectorCount;
625 PPARTENTRY PartEntry;
626 PPARTENTRY NewPartEntry;
627 PLIST_ENTRY Entry;
628
629 DPRINT1("ScanForUnpartitionedDiskSpace()\n");
630
631 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
632 {
633 DPRINT1("No primary partition!\n");
634
635 /* Create a partition table that represents the empty disk */
636 NewPartEntry = RtlAllocateHeap(ProcessHeap,
637 HEAP_ZERO_MEMORY,
638 sizeof(PARTENTRY));
639 if (NewPartEntry == NULL)
640 return;
641
642 NewPartEntry->DiskEntry = DiskEntry;
643
644 NewPartEntry->IsPartitioned = FALSE;
645 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorsPerTrack;
646 NewPartEntry->SectorCount.QuadPart = Align(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
647 DiskEntry->SectorsPerTrack;
648 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
649 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
650 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
651
652 NewPartEntry->FormatState = Unformatted;
653
654 InsertTailList(&DiskEntry->PrimaryPartListHead,
655 &NewPartEntry->ListEntry);
656
657 return;
658 }
659
660 /* Start partition at head 1, cylinder 0 */
661 LastStartSector = DiskEntry->SectorsPerTrack;
662 LastSectorCount = 0ULL;
663 LastUnusedSectorCount = 0ULL;
664
665 Entry = DiskEntry->PrimaryPartListHead.Flink;
666 while (Entry != &DiskEntry->PrimaryPartListHead)
667 {
668 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
669
670 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
671 PartEntry->SectorCount.QuadPart != 0ULL)
672 {
673 LastUnusedSectorCount =
674 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
675
676 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
677 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
678 {
679 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
680
681 NewPartEntry = RtlAllocateHeap(ProcessHeap,
682 HEAP_ZERO_MEMORY,
683 sizeof(PARTENTRY));
684 if (NewPartEntry == NULL)
685 return;
686
687 NewPartEntry->DiskEntry = DiskEntry;
688
689 NewPartEntry->IsPartitioned = FALSE;
690 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
691 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
692 NewPartEntry->StartSector.QuadPart;
693 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
694 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
695 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
696
697 NewPartEntry->FormatState = Unformatted;
698
699 /* Insert the table into the list */
700 InsertTailList(&PartEntry->ListEntry,
701 &NewPartEntry->ListEntry);
702 }
703
704 LastStartSector = PartEntry->StartSector.QuadPart;
705 LastSectorCount = PartEntry->SectorCount.QuadPart;
706 }
707
708 Entry = Entry->Flink;
709 }
710
711 /* Check for trailing unpartitioned disk space */
712 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
713 {
714 LastUnusedSectorCount = Align(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
715
716 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
717 {
718 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
719
720 NewPartEntry = RtlAllocateHeap(ProcessHeap,
721 HEAP_ZERO_MEMORY,
722 sizeof(PARTENTRY));
723 if (NewPartEntry == NULL)
724 return;
725
726 NewPartEntry->DiskEntry = DiskEntry;
727
728 NewPartEntry->IsPartitioned = FALSE;
729 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
730 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
731 NewPartEntry->StartSector.QuadPart;
732 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
733 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
734 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
735
736 NewPartEntry->FormatState = Unformatted;
737
738 /* Append the table to the list */
739 InsertTailList(&DiskEntry->PrimaryPartListHead,
740 &NewPartEntry->ListEntry);
741 }
742 }
743
744 DPRINT1("ScanForUnpartitionedDiskSpace() done\n");
745 }
746
747
748 static
749 VOID
750 SetDiskSignature(
751 IN PPARTLIST List,
752 IN PDISKENTRY DiskEntry)
753 {
754 LARGE_INTEGER SystemTime;
755 TIME_FIELDS TimeFields;
756 PLIST_ENTRY Entry2;
757 PDISKENTRY DiskEntry2;
758 PUCHAR Buffer;
759
760 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
761
762 while (1)
763 {
764 NtQuerySystemTime(&SystemTime);
765 RtlTimeToTimeFields(&SystemTime, &TimeFields);
766
767 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
768 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
769 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
770 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
771
772 if (DiskEntry->LayoutBuffer->Signature == 0)
773 {
774 continue;
775 }
776
777 /* check if the signature already exist */
778 /* FIXME:
779 * Check also signatures from disks, which are
780 * not visible (bootable) by the bios.
781 */
782 Entry2 = List->DiskListHead.Flink;
783 while (Entry2 != &List->DiskListHead)
784 {
785 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
786
787 if (DiskEntry != DiskEntry2 &&
788 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
789 break;
790
791 Entry2 = Entry2->Flink;
792 }
793
794 if (Entry2 == &List->DiskListHead)
795 break;
796 }
797 }
798
799
800 static
801 VOID
802 UpdateDiskSignatures(
803 PPARTLIST List)
804 {
805 PLIST_ENTRY Entry;
806 PDISKENTRY DiskEntry;
807
808 /* Print partition lines*/
809 Entry = List->DiskListHead.Flink;
810 while (Entry != &List->DiskListHead)
811 {
812 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
813
814 if (DiskEntry->LayoutBuffer &&
815 DiskEntry->LayoutBuffer->Signature == 0)
816 {
817 SetDiskSignature(List, DiskEntry);
818 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
819 }
820
821 Entry = Entry->Flink;
822 }
823 }
824
825
826 static
827 VOID
828 AddDiskToList(
829 HANDLE FileHandle,
830 ULONG DiskNumber,
831 PPARTLIST List)
832 {
833 DISK_GEOMETRY DiskGeometry;
834 SCSI_ADDRESS ScsiAddress;
835 PDISKENTRY DiskEntry;
836 IO_STATUS_BLOCK Iosb;
837 NTSTATUS Status;
838 PPARTITION_SECTOR Mbr;
839 PULONG Buffer;
840 LARGE_INTEGER FileOffset;
841 WCHAR Identifier[20];
842 ULONG Checksum;
843 ULONG Signature;
844 ULONG i;
845 PLIST_ENTRY ListEntry;
846 PBIOSDISKENTRY BiosDiskEntry;
847 ULONG LayoutBufferSize;
848
849 Status = NtDeviceIoControlFile(FileHandle,
850 NULL,
851 NULL,
852 NULL,
853 &Iosb,
854 IOCTL_DISK_GET_DRIVE_GEOMETRY,
855 NULL,
856 0,
857 &DiskGeometry,
858 sizeof(DISK_GEOMETRY));
859 if (!NT_SUCCESS(Status))
860 {
861 return;
862 }
863
864 if (DiskGeometry.MediaType != FixedMedia &&
865 DiskGeometry.MediaType != RemovableMedia)
866 {
867 return;
868 }
869
870 Status = NtDeviceIoControlFile(FileHandle,
871 NULL,
872 NULL,
873 NULL,
874 &Iosb,
875 IOCTL_SCSI_GET_ADDRESS,
876 NULL,
877 0,
878 &ScsiAddress,
879 sizeof(SCSI_ADDRESS));
880 if (!NT_SUCCESS(Status))
881 {
882 return;
883 }
884
885 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
886 0,
887 DiskGeometry.BytesPerSector);
888 if (Mbr == NULL)
889 {
890 return;
891 }
892
893 FileOffset.QuadPart = 0;
894 Status = NtReadFile(FileHandle,
895 NULL,
896 NULL,
897 NULL,
898 &Iosb,
899 (PVOID)Mbr,
900 DiskGeometry.BytesPerSector,
901 &FileOffset,
902 NULL);
903 if (!NT_SUCCESS(Status))
904 {
905 RtlFreeHeap(ProcessHeap,
906 0,
907 Mbr);
908 DPRINT1("NtReadFile failed, status=%x\n", Status);
909 return;
910 }
911 Signature = Mbr->Signature;
912
913 /* Calculate the MBR checksum */
914 Checksum = 0;
915 Buffer = (PULONG)Mbr;
916 for (i = 0; i < 128; i++)
917 {
918 Checksum += Buffer[i];
919 }
920 Checksum = ~Checksum + 1;
921
922 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
923 DPRINT("Identifier: %S\n", Identifier);
924
925 DiskEntry = RtlAllocateHeap(ProcessHeap,
926 HEAP_ZERO_MEMORY,
927 sizeof(DISKENTRY));
928 if (DiskEntry == NULL)
929 {
930 return;
931 }
932
933 // DiskEntry->Checksum = Checksum;
934 // DiskEntry->Signature = Signature;
935 DiskEntry->BiosFound = FALSE;
936
937 /* Check if this disk has a valid MBR */
938 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
939 DiskEntry->NoMbr = TRUE;
940 else
941 DiskEntry->NoMbr = FALSE;
942
943 /* Free Mbr sector buffer */
944 RtlFreeHeap(ProcessHeap,
945 0,
946 Mbr);
947
948 ListEntry = List->BiosDiskListHead.Flink;
949 while(ListEntry != &List->BiosDiskListHead)
950 {
951 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
952 /* FIXME:
953 * Compare the size from bios and the reported size from driver.
954 * If we have more than one disk with a zero or with the same signatur
955 * we must create new signatures and reboot. After the reboot,
956 * it is possible to identify the disks.
957 */
958 if (BiosDiskEntry->Signature == Signature &&
959 BiosDiskEntry->Checksum == Checksum &&
960 !BiosDiskEntry->Recognized)
961 {
962 if (!DiskEntry->BiosFound)
963 {
964 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
965 DiskEntry->BiosFound = TRUE;
966 BiosDiskEntry->Recognized = TRUE;
967 }
968 else
969 {
970 }
971 }
972 ListEntry = ListEntry->Flink;
973 }
974
975 if (!DiskEntry->BiosFound)
976 {
977 #if 0
978 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
979 return;
980 #else
981 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
982 #endif
983 }
984
985 InitializeListHead(&DiskEntry->PrimaryPartListHead);
986 InitializeListHead(&DiskEntry->ExtendedPartListHead);
987
988 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
989 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
990 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
991 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
992
993 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
994 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
995 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
996 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
997
998 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
999 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1000 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1001
1002 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1003
1004 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount);
1005 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1006
1007 DiskEntry->DiskNumber = DiskNumber;
1008 DiskEntry->Port = ScsiAddress.PortNumber;
1009 DiskEntry->Bus = ScsiAddress.PathId;
1010 DiskEntry->Id = ScsiAddress.TargetId;
1011
1012 GetDriverName(DiskEntry);
1013
1014 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1015
1016 /*
1017 * Allocate a buffer for 26 logical drives (2 entries each == 52)
1018 * plus the main partiton table (4 entries). Total 56 entries.
1019 */
1020 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1021 ((56 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1022 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1023 HEAP_ZERO_MEMORY,
1024 LayoutBufferSize);
1025 if (DiskEntry->LayoutBuffer == NULL)
1026 {
1027 return;
1028 }
1029
1030 Status = NtDeviceIoControlFile(FileHandle,
1031 NULL,
1032 NULL,
1033 NULL,
1034 &Iosb,
1035 IOCTL_DISK_GET_DRIVE_LAYOUT,
1036 NULL,
1037 0,
1038 DiskEntry->LayoutBuffer,
1039 LayoutBufferSize);
1040 if (NT_SUCCESS(Status))
1041 {
1042 #ifdef DUMP_PARTITION_TABLE
1043 DumpPartitionTable(DiskEntry);
1044 #endif
1045
1046 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1047 {
1048 DiskEntry->NewDisk = TRUE;
1049 DiskEntry->LayoutBuffer->PartitionCount = 4;
1050
1051 for (i = 0; i < 4; i++)
1052 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1053 }
1054 else
1055 {
1056 for (i = 0; i < 4; i++)
1057 {
1058 if (DiskEntry->LayoutBuffer->PartitionEntry[i].PartitionType != 0)
1059 {
1060 AddPrimaryPartitionToDisk(DiskNumber,
1061 DiskEntry,
1062 i);
1063 }
1064 }
1065
1066 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
1067 {
1068 if (DiskEntry->LayoutBuffer->PartitionEntry[i].PartitionType != 0)
1069 {
1070 #if 0
1071 AddExtendedPartitionToDisk(DiskNumber,
1072 DiskEntry,
1073 i);
1074 #endif
1075 }
1076 }
1077 }
1078 }
1079
1080 ScanForUnpartitionedDiskSpace(DiskEntry);
1081 }
1082
1083
1084 PPARTLIST
1085 CreatePartitionList(
1086 SHORT Left,
1087 SHORT Top,
1088 SHORT Right,
1089 SHORT Bottom)
1090 {
1091 PPARTLIST List;
1092 OBJECT_ATTRIBUTES ObjectAttributes;
1093 SYSTEM_DEVICE_INFORMATION Sdi;
1094 IO_STATUS_BLOCK Iosb;
1095 ULONG ReturnSize;
1096 NTSTATUS Status;
1097 ULONG DiskNumber;
1098 WCHAR Buffer[MAX_PATH];
1099 UNICODE_STRING Name;
1100 HANDLE FileHandle;
1101
1102 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1103 0,
1104 sizeof (PARTLIST));
1105 if (List == NULL)
1106 return NULL;
1107
1108 List->Left = Left;
1109 List->Top = Top;
1110 List->Right = Right;
1111 List->Bottom = Bottom;
1112
1113 List->Line = 0;
1114 List->Offset = 0;
1115
1116 List->TopDisk = (ULONG)-1;
1117 List->TopPartition = (ULONG)-1;
1118
1119 List->CurrentDisk = NULL;
1120 List->CurrentPartition = NULL;
1121
1122 InitializeListHead(&List->DiskListHead);
1123 InitializeListHead(&List->BiosDiskListHead);
1124
1125 EnumerateBiosDiskEntries(List);
1126
1127 Status = NtQuerySystemInformation(SystemDeviceInformation,
1128 &Sdi,
1129 sizeof(SYSTEM_DEVICE_INFORMATION),
1130 &ReturnSize);
1131 if (!NT_SUCCESS(Status))
1132 {
1133 RtlFreeHeap(ProcessHeap, 0, List);
1134 return NULL;
1135 }
1136
1137 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1138 {
1139 swprintf(Buffer,
1140 L"\\Device\\Harddisk%d\\Partition0",
1141 DiskNumber);
1142 RtlInitUnicodeString(&Name,
1143 Buffer);
1144
1145 InitializeObjectAttributes(&ObjectAttributes,
1146 &Name,
1147 0,
1148 NULL,
1149 NULL);
1150
1151 Status = NtOpenFile(&FileHandle,
1152 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1153 &ObjectAttributes,
1154 &Iosb,
1155 FILE_SHARE_READ,
1156 FILE_SYNCHRONOUS_IO_NONALERT);
1157 if (NT_SUCCESS(Status))
1158 {
1159 AddDiskToList(FileHandle,
1160 DiskNumber,
1161 List);
1162
1163 NtClose(FileHandle);
1164 }
1165 }
1166
1167 UpdateDiskSignatures(List);
1168
1169 AssignDriveLetters(List);
1170
1171 List->TopDisk = 0;
1172 List->TopPartition = 0;
1173
1174 /* Search for first usable disk and partition */
1175 if (IsListEmpty(&List->DiskListHead))
1176 {
1177 List->CurrentDisk = NULL;
1178 List->CurrentPartition = NULL;
1179 }
1180 else
1181 {
1182 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1183 DISKENTRY,
1184 ListEntry);
1185
1186 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1187 {
1188 List->CurrentPartition = 0;
1189 }
1190 else
1191 {
1192 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1193 PARTENTRY,
1194 ListEntry);
1195 }
1196 }
1197
1198 return List;
1199 }
1200
1201
1202 VOID
1203 DestroyPartitionList(
1204 PPARTLIST List)
1205 {
1206 PDISKENTRY DiskEntry;
1207 PBIOSDISKENTRY BiosDiskEntry;
1208 PPARTENTRY PartEntry;
1209 PLIST_ENTRY Entry;
1210
1211 /* Release disk and partition info */
1212 while (!IsListEmpty(&List->DiskListHead))
1213 {
1214 Entry = RemoveHeadList(&List->DiskListHead);
1215 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1216
1217 /* Release driver name */
1218 RtlFreeUnicodeString(&DiskEntry->DriverName);
1219
1220 /* Release primary partition list */
1221 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1222 {
1223 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1224 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1225
1226 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1227 }
1228
1229 /* Release extended partition list */
1230 while (!IsListEmpty(&DiskEntry->ExtendedPartListHead))
1231 {
1232 Entry = RemoveHeadList(&DiskEntry->ExtendedPartListHead);
1233 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1234
1235 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1236 }
1237
1238 /* Release layout buffer */
1239 if (DiskEntry->LayoutBuffer != NULL)
1240 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1241
1242
1243 /* Release disk entry */
1244 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1245 }
1246
1247 /* release the bios disk info */
1248 while(!IsListEmpty(&List->BiosDiskListHead))
1249 {
1250 Entry = RemoveHeadList(&List->BiosDiskListHead);
1251 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1252
1253 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1254 }
1255
1256 /* Release list head */
1257 RtlFreeHeap(ProcessHeap, 0, List);
1258 }
1259
1260
1261 static
1262 VOID
1263 PrintEmptyLine(
1264 PPARTLIST List)
1265 {
1266 COORD coPos;
1267 DWORD Written;
1268 USHORT Width;
1269 USHORT Height;
1270
1271 Width = List->Right - List->Left - 1;
1272 Height = List->Bottom - List->Top - 2;
1273
1274 coPos.X = List->Left + 1;
1275 coPos.Y = List->Top + 1 + List->Line;
1276
1277 if (List->Line >= 0 && List->Line <= Height)
1278 {
1279 FillConsoleOutputAttribute(StdOutput,
1280 FOREGROUND_WHITE | BACKGROUND_BLUE,
1281 Width,
1282 coPos,
1283 &Written);
1284
1285 FillConsoleOutputCharacterA(StdOutput,
1286 ' ',
1287 Width,
1288 coPos,
1289 &Written);
1290 }
1291
1292 List->Line++;
1293 }
1294
1295
1296 static
1297 VOID
1298 PrintPartitionData(
1299 PPARTLIST List,
1300 PDISKENTRY DiskEntry,
1301 PPARTENTRY PartEntry)
1302 {
1303 CHAR LineBuffer[128];
1304 COORD coPos;
1305 DWORD Written;
1306 USHORT Width;
1307 USHORT Height;
1308 LARGE_INTEGER PartSize;
1309 PCHAR Unit;
1310 UCHAR Attribute;
1311 PCHAR PartType;
1312
1313 Width = List->Right - List->Left - 1;
1314 Height = List->Bottom - List->Top - 2;
1315
1316 coPos.X = List->Left + 1;
1317 coPos.Y = List->Top + 1 + List->Line;
1318
1319 if (PartEntry->IsPartitioned == FALSE)
1320 {
1321 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1322 #if 0
1323 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1324 {
1325 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1326 Unit = MUIGetString(STRING_GB);
1327 }
1328 else
1329 #endif
1330 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1331 {
1332 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1333 Unit = MUIGetString(STRING_MB);
1334 }
1335 else
1336 {
1337 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1338 Unit = MUIGetString(STRING_KB);
1339 }
1340
1341 sprintf(LineBuffer,
1342 MUIGetString(STRING_UNPSPACE),
1343 PartSize.u.LowPart,
1344 Unit);
1345 }
1346 else
1347 {
1348 /* Determine partition type */
1349 PartType = NULL;
1350 if (PartEntry->New == TRUE)
1351 {
1352 PartType = MUIGetString(STRING_UNFORMATTED);
1353 }
1354 else if (PartEntry->IsPartitioned == TRUE)
1355 {
1356 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
1357 (PartEntry->PartitionType == PARTITION_FAT_16) ||
1358 (PartEntry->PartitionType == PARTITION_HUGE) ||
1359 (PartEntry->PartitionType == PARTITION_XINT13))
1360 {
1361 PartType = "FAT";
1362 }
1363 else if ((PartEntry->PartitionType == PARTITION_FAT32) ||
1364 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
1365 {
1366 PartType = "FAT32";
1367 }
1368 else if (PartEntry->PartitionType == PARTITION_EXT2)
1369 {
1370 PartType = "EXT2";
1371 }
1372 else if (PartEntry->PartitionType == PARTITION_IFS)
1373 {
1374 PartType = "NTFS"; /* FIXME: Not quite correct! */
1375 }
1376 else if ((PartEntry->PartitionType == PARTITION_EXTENDED) ||
1377 (PartEntry->PartitionType == PARTITION_XINT13_EXTENDED))
1378 {
1379 PartType = MUIGetString(STRING_EXTENDED_PARTITION);
1380 }
1381 }
1382
1383 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1384 #if 0
1385 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1386 {
1387 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1388 Unit = MUIGetString(STRING_GB);
1389 }
1390 else
1391 #endif
1392 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1393 {
1394 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1395 Unit = MUIGetString(STRING_MB);
1396 }
1397 else
1398 {
1399 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1400 Unit = MUIGetString(STRING_KB);
1401 }
1402
1403 if (PartType == NULL)
1404 {
1405 sprintf(LineBuffer,
1406 MUIGetString(STRING_HDDINFOUNK5),
1407 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1408 (PartEntry->DriveLetter == 0) ? '-' : ':',
1409 PartEntry->PartitionType,
1410 PartSize.u.LowPart,
1411 Unit);
1412 }
1413 else
1414 {
1415 sprintf(LineBuffer,
1416 "%c%c %-24s %6lu %s",
1417 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1418 (PartEntry->DriveLetter == 0) ? '-' : ':',
1419 PartType,
1420 PartSize.u.LowPart,
1421 Unit);
1422 }
1423 }
1424
1425 Attribute = (List->CurrentDisk == DiskEntry &&
1426 List->CurrentPartition == PartEntry) ?
1427 FOREGROUND_BLUE | BACKGROUND_WHITE :
1428 FOREGROUND_WHITE | BACKGROUND_BLUE;
1429
1430 if (List->Line >= 0 && List->Line <= Height)
1431 {
1432 FillConsoleOutputCharacterA(StdOutput,
1433 ' ',
1434 Width,
1435 coPos,
1436 &Written);
1437 }
1438 coPos.X += 4;
1439 Width -= 8;
1440 if (List->Line >= 0 && List->Line <= Height)
1441 {
1442 FillConsoleOutputAttribute(StdOutput,
1443 Attribute,
1444 Width,
1445 coPos,
1446 &Written);
1447 }
1448 coPos.X++;
1449 Width -= 2;
1450 if (List->Line >= 0 && List->Line <= Height)
1451 {
1452 WriteConsoleOutputCharacterA(StdOutput,
1453 LineBuffer,
1454 min(strlen(LineBuffer), Width),
1455 coPos,
1456 &Written);
1457 }
1458
1459 List->Line++;
1460 }
1461
1462
1463 static
1464 VOID
1465 PrintDiskData(
1466 PPARTLIST List,
1467 PDISKENTRY DiskEntry)
1468 {
1469 PPARTENTRY PartEntry;
1470 PLIST_ENTRY Entry;
1471 CHAR LineBuffer[128];
1472 COORD coPos;
1473 DWORD Written;
1474 USHORT Width;
1475 USHORT Height;
1476 ULARGE_INTEGER DiskSize;
1477 PCHAR Unit;
1478
1479 Width = List->Right - List->Left - 1;
1480 Height = List->Bottom - List->Top - 2;
1481
1482 coPos.X = List->Left + 1;
1483 coPos.Y = List->Top + 1 + List->Line;
1484
1485 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1486 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1487 {
1488 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1489 Unit = MUIGetString(STRING_GB);
1490 }
1491 else
1492 {
1493 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1494 if (DiskSize.QuadPart == 0)
1495 DiskSize.QuadPart = 1;
1496 Unit = MUIGetString(STRING_MB);
1497 }
1498
1499 if (DiskEntry->DriverName.Length > 0)
1500 {
1501 sprintf(LineBuffer,
1502 MUIGetString(STRING_HDINFOPARTSELECT),
1503 DiskSize.u.LowPart,
1504 Unit,
1505 DiskEntry->DiskNumber,
1506 DiskEntry->Port,
1507 DiskEntry->Bus,
1508 DiskEntry->Id,
1509 DiskEntry->DriverName.Buffer);
1510 }
1511 else
1512 {
1513 sprintf(LineBuffer,
1514 MUIGetString(STRING_HDDINFOUNK6),
1515 DiskSize.u.LowPart,
1516 Unit,
1517 DiskEntry->DiskNumber,
1518 DiskEntry->Port,
1519 DiskEntry->Bus,
1520 DiskEntry->Id);
1521 }
1522
1523 if (List->Line >= 0 && List->Line <= Height)
1524 {
1525 FillConsoleOutputAttribute(StdOutput,
1526 FOREGROUND_WHITE | BACKGROUND_BLUE,
1527 Width,
1528 coPos,
1529 &Written);
1530
1531 FillConsoleOutputCharacterA(StdOutput,
1532 ' ',
1533 Width,
1534 coPos,
1535 &Written);
1536 }
1537
1538 coPos.X++;
1539 if (List->Line >= 0 && List->Line <= Height)
1540 {
1541 WriteConsoleOutputCharacterA(StdOutput,
1542 LineBuffer,
1543 min((USHORT)strlen(LineBuffer), Width - 2),
1544 coPos,
1545 &Written);
1546 }
1547
1548 List->Line++;
1549
1550 /* Print separator line */
1551 PrintEmptyLine(List);
1552
1553 /* Print partition lines*/
1554 Entry = DiskEntry->PrimaryPartListHead.Flink;
1555 while (Entry != &DiskEntry->PrimaryPartListHead)
1556 {
1557 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1558
1559 PrintPartitionData(List,
1560 DiskEntry,
1561 PartEntry);
1562
1563 Entry = Entry->Flink;
1564 }
1565
1566 /* Print separator line */
1567 PrintEmptyLine(List);
1568 }
1569
1570
1571 VOID
1572 DrawPartitionList(
1573 PPARTLIST List)
1574 {
1575 PLIST_ENTRY Entry, Entry2;
1576 PDISKENTRY DiskEntry;
1577 PPARTENTRY PartEntry = NULL;
1578 COORD coPos;
1579 DWORD Written;
1580 SHORT i;
1581 SHORT CurrentDiskLine;
1582 SHORT CurrentPartLine;
1583 SHORT LastLine;
1584 BOOL CurrentPartLineFound = FALSE;
1585 BOOL CurrentDiskLineFound = FALSE;
1586
1587 /* Calculate the line of the current disk and partition */
1588 CurrentDiskLine = 0;
1589 CurrentPartLine = 0;
1590 LastLine = 0;
1591
1592 Entry = List->DiskListHead.Flink;
1593 while (Entry != &List->DiskListHead)
1594 {
1595 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1596
1597 LastLine += 2;
1598 if (CurrentPartLineFound == FALSE)
1599 {
1600 CurrentPartLine += 2;
1601 }
1602
1603 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1604 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1605 {
1606 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1607 if (PartEntry == List->CurrentPartition)
1608 {
1609 CurrentPartLineFound = TRUE;
1610 }
1611
1612 Entry2 = Entry2->Flink;
1613 if (CurrentPartLineFound == FALSE)
1614 {
1615 CurrentPartLine++;
1616 }
1617
1618 LastLine++;
1619 }
1620
1621 if (DiskEntry == List->CurrentDisk)
1622 {
1623 CurrentDiskLineFound = TRUE;
1624 }
1625
1626 Entry = Entry->Flink;
1627 if (Entry != &List->DiskListHead)
1628 {
1629 if (CurrentDiskLineFound == FALSE)
1630 {
1631 CurrentPartLine ++;
1632 CurrentDiskLine = CurrentPartLine;
1633 }
1634
1635 LastLine++;
1636 }
1637 else
1638 {
1639 LastLine--;
1640 }
1641 }
1642
1643 /* If it possible, make the disk name visible */
1644 if (CurrentPartLine < List->Offset)
1645 {
1646 List->Offset = CurrentPartLine;
1647 }
1648 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1649 {
1650 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1651 }
1652
1653 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1654 {
1655 List->Offset = CurrentDiskLine;
1656 }
1657
1658 /* draw upper left corner */
1659 coPos.X = List->Left;
1660 coPos.Y = List->Top;
1661 FillConsoleOutputCharacterA(StdOutput,
1662 0xDA, // '+',
1663 1,
1664 coPos,
1665 &Written);
1666
1667 /* draw upper edge */
1668 coPos.X = List->Left + 1;
1669 coPos.Y = List->Top;
1670 if (List->Offset == 0)
1671 {
1672 FillConsoleOutputCharacterA(StdOutput,
1673 0xC4, // '-',
1674 List->Right - List->Left - 1,
1675 coPos,
1676 &Written);
1677 }
1678 else
1679 {
1680 FillConsoleOutputCharacterA(StdOutput,
1681 0xC4, // '-',
1682 List->Right - List->Left - 5,
1683 coPos,
1684 &Written);
1685 coPos.X = List->Right - 5;
1686 WriteConsoleOutputCharacterA(StdOutput,
1687 "(\x18)", // "(up)"
1688 3,
1689 coPos,
1690 &Written);
1691 coPos.X = List->Right - 2;
1692 FillConsoleOutputCharacterA(StdOutput,
1693 0xC4, // '-',
1694 2,
1695 coPos,
1696 &Written);
1697 }
1698
1699 /* draw upper right corner */
1700 coPos.X = List->Right;
1701 coPos.Y = List->Top;
1702 FillConsoleOutputCharacterA(StdOutput,
1703 0xBF, // '+',
1704 1,
1705 coPos,
1706 &Written);
1707
1708 /* draw left and right edge */
1709 for (i = List->Top + 1; i < List->Bottom; i++)
1710 {
1711 coPos.X = List->Left;
1712 coPos.Y = i;
1713 FillConsoleOutputCharacterA(StdOutput,
1714 0xB3, // '|',
1715 1,
1716 coPos,
1717 &Written);
1718
1719 coPos.X = List->Right;
1720 FillConsoleOutputCharacterA(StdOutput,
1721 0xB3, //'|',
1722 1,
1723 coPos,
1724 &Written);
1725 }
1726
1727 /* draw lower left corner */
1728 coPos.X = List->Left;
1729 coPos.Y = List->Bottom;
1730 FillConsoleOutputCharacterA(StdOutput,
1731 0xC0, // '+',
1732 1,
1733 coPos,
1734 &Written);
1735
1736 /* draw lower edge */
1737 coPos.X = List->Left + 1;
1738 coPos.Y = List->Bottom;
1739 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1740 {
1741 FillConsoleOutputCharacterA(StdOutput,
1742 0xC4, // '-',
1743 List->Right - List->Left - 1,
1744 coPos,
1745 &Written);
1746 }
1747 else
1748 {
1749 FillConsoleOutputCharacterA(StdOutput,
1750 0xC4, // '-',
1751 List->Right - List->Left - 5,
1752 coPos,
1753 &Written);
1754 coPos.X = List->Right - 5;
1755 WriteConsoleOutputCharacterA(StdOutput,
1756 "(\x19)", // "(down)"
1757 3,
1758 coPos,
1759 &Written);
1760 coPos.X = List->Right - 2;
1761 FillConsoleOutputCharacterA(StdOutput,
1762 0xC4, // '-',
1763 2,
1764 coPos,
1765 &Written);
1766 }
1767
1768 /* draw lower right corner */
1769 coPos.X = List->Right;
1770 coPos.Y = List->Bottom;
1771 FillConsoleOutputCharacterA(StdOutput,
1772 0xD9, // '+',
1773 1,
1774 coPos,
1775 &Written);
1776
1777 /* print list entries */
1778 List->Line = - List->Offset;
1779
1780 Entry = List->DiskListHead.Flink;
1781 while (Entry != &List->DiskListHead)
1782 {
1783 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1784
1785 /* Print disk entry */
1786 PrintDiskData(List,
1787 DiskEntry);
1788
1789 Entry = Entry->Flink;
1790 }
1791 }
1792
1793
1794 DWORD
1795 SelectPartition(
1796 PPARTLIST List,
1797 ULONG DiskNumber,
1798 ULONG PartitionNumber)
1799 {
1800 PDISKENTRY DiskEntry;
1801 PPARTENTRY PartEntry;
1802 PLIST_ENTRY Entry1;
1803 PLIST_ENTRY Entry2;
1804
1805 /* Check for empty disks */
1806 if (IsListEmpty(&List->DiskListHead))
1807 return FALSE;
1808
1809 /* Check for first usable entry on next disk */
1810 Entry1 = List->CurrentDisk->ListEntry.Flink;
1811 while (Entry1 != &List->DiskListHead)
1812 {
1813 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1814
1815 if (DiskEntry->DiskNumber == DiskNumber)
1816 {
1817 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1818 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1819 {
1820 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1821
1822 if (PartEntry->PartitionNumber == PartitionNumber)
1823 {
1824 List->CurrentDisk = DiskEntry;
1825 List->CurrentPartition = PartEntry;
1826 DrawPartitionList(List);
1827 return TRUE;
1828 }
1829
1830 Entry2 = Entry2->Flink;
1831 }
1832
1833 return FALSE;
1834 }
1835
1836 Entry1 = Entry1->Flink;
1837 }
1838
1839 return FALSE;
1840 }
1841
1842
1843 VOID
1844 ScrollDownPartitionList(
1845 PPARTLIST List)
1846 {
1847 // PDISKENTRY DiskEntry;
1848 PPARTENTRY PartEntry;
1849 // PLIST_ENTRY Entry1;
1850 PLIST_ENTRY Entry2;
1851
1852 /* Check for empty disks */
1853 if (IsListEmpty(&List->DiskListHead))
1854 return;
1855
1856 /* Check for next usable entry on current disk */
1857 if (List->CurrentPartition != NULL)
1858 {
1859 Entry2 = List->CurrentPartition->ListEntry.Flink;
1860 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
1861 {
1862 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1863
1864 List->CurrentPartition = PartEntry;
1865 DrawPartitionList(List);
1866 return;
1867 }
1868 }
1869
1870 #if 0
1871 /* Check for first usable entry on next disk */
1872 if (List->CurrentDisk != NULL)
1873 {
1874 Entry1 = List->CurrentDisk->ListEntry.Flink;
1875 while (Entry1 != &List->DiskListHead)
1876 {
1877 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1878
1879 Entry2 = DiskEntry->PartListHead.Flink;
1880 if (Entry2 != &DiskEntry->PartListHead)
1881 {
1882 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1883
1884 List->CurrentDisk = DiskEntry;
1885 List->CurrentPartition = PartEntry;
1886 DrawPartitionList(List);
1887 return;
1888 }
1889
1890 Entry1 = Entry1->Flink;
1891 }
1892 }
1893 #endif
1894 }
1895
1896
1897 VOID
1898 ScrollUpPartitionList(
1899 PPARTLIST List)
1900 {
1901 // PDISKENTRY DiskEntry;
1902 PPARTENTRY PartEntry;
1903 // PLIST_ENTRY Entry1;
1904 PLIST_ENTRY Entry2;
1905
1906 /* Check for empty disks */
1907 if (IsListEmpty(&List->DiskListHead))
1908 return;
1909
1910 /* check for previous usable entry on current disk */
1911 if (List->CurrentPartition != NULL)
1912 {
1913 Entry2 = List->CurrentPartition->ListEntry.Blink;
1914 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
1915 {
1916 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1917
1918 List->CurrentPartition = PartEntry;
1919
1920 /* Draw partition list and return */
1921 DrawPartitionList(List);
1922 return;
1923 }
1924 }
1925
1926 #if 0
1927 /* check for last usable entry on previous disk */
1928 if (List->CurrentDisk != NULL)
1929 {
1930 Entry1 = List->CurrentDisk->ListEntry.Blink;
1931 while (Entry1 != &List->DiskListHead)
1932 {
1933 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1934
1935 Entry2 = DiskEntry->PrimaryPartListHead.Blink;
1936 if (Entry2 != &DiskEntry->PrimaryPartListHead)
1937 {
1938 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1939
1940 List->CurrentDisk = DiskEntry;
1941 List->CurrentPartition = PartEntry;
1942
1943 /* Draw partition list and return */
1944 DrawPartitionList(List);
1945 return;
1946 }
1947
1948 Entry1 = Entry1->Blink;
1949 }
1950 }
1951 #endif
1952 }
1953
1954
1955 static
1956 BOOLEAN
1957 IsEmptyLayoutEntry(
1958 PPARTITION_INFORMATION PartitionInfo)
1959 {
1960 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
1961 PartitionInfo->PartitionLength.QuadPart == 0)
1962 // PartitionInfo->PartitionType == 0)
1963 return TRUE;
1964
1965 return FALSE;
1966 }
1967
1968
1969 static
1970 BOOLEAN
1971 IsSamePrimaryLayoutEntry(
1972 IN PPARTITION_INFORMATION PartitionInfo,
1973 IN PDISKENTRY DiskEntry,
1974 IN PPARTENTRY PartEntry)
1975 {
1976 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
1977 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
1978 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
1979 // PartitionInfo->PartitionType == PartEntry->PartitionType
1980 return TRUE;
1981
1982 return FALSE;
1983 }
1984
1985
1986 static
1987 VOID
1988 UpdateDiskLayout(
1989 IN PDISKENTRY DiskEntry)
1990 {
1991 PPARTITION_INFORMATION PartitionInfo;
1992 PLIST_ENTRY ListEntry;
1993 PPARTENTRY PartEntry;
1994 ULONG Index = 0;
1995 ULONG PartitionNumber = 1;
1996
1997 DPRINT1("UpdateDiskLayout()\n");
1998
1999 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2000 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2001 {
2002 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2003
2004 if (PartEntry->IsPartitioned == TRUE)
2005 {
2006 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2007
2008 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2009 {
2010 DPRINT1("Updating partition entry %lu\n", Index);
2011 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2012 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2013 PartitionInfo->HiddenSectors = 0;
2014 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2015 PartitionInfo->PartitionType = PartEntry->PartitionType;
2016 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2017 PartitionInfo->RecognizedPartition = FALSE;
2018 PartitionInfo->RewritePartition = TRUE;
2019
2020 PartEntry->PartitionNumber = PartitionNumber;
2021 PartEntry->PartitionIndex = Index;
2022
2023 PartitionNumber++;
2024 }
2025 else if (!IsEmptyLayoutEntry(PartitionInfo))
2026 {
2027 PartitionNumber++;
2028 }
2029
2030 Index++;
2031 }
2032
2033 ListEntry = ListEntry->Flink;
2034 }
2035
2036 for (;Index < 4; Index++)
2037 {
2038 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2039
2040 if (!IsEmptyLayoutEntry(PartitionInfo))
2041 {
2042 DPRINT1("Wiping partition entry %lu\n", Index);
2043 PartitionInfo->StartingOffset.QuadPart = 0;
2044 PartitionInfo->PartitionLength.QuadPart = 0;
2045 PartitionInfo->HiddenSectors = 0;
2046 PartitionInfo->PartitionNumber = 0;
2047 PartitionInfo->PartitionType = 0;
2048 PartitionInfo->BootIndicator = FALSE;
2049 PartitionInfo->RecognizedPartition = FALSE;
2050 PartitionInfo->RewritePartition = TRUE;
2051 }
2052 }
2053
2054 #ifdef DUMP_PARTITION_TABLE
2055 DumpPartitionTable(DiskEntry);
2056 #endif
2057 }
2058
2059
2060 static
2061 PPARTENTRY
2062 GetPrevUnpartitionedEntry(
2063 PDISKENTRY DiskEntry,
2064 PPARTENTRY PartEntry)
2065 {
2066 PPARTENTRY PrevPartEntry;
2067
2068 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2069 {
2070 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2071 PARTENTRY,
2072 ListEntry);
2073 if (PrevPartEntry->IsPartitioned == FALSE)
2074 return PrevPartEntry;
2075 }
2076
2077 return NULL;
2078 }
2079
2080
2081 static
2082 PPARTENTRY
2083 GetNextUnpartitionedEntry(
2084 PDISKENTRY DiskEntry,
2085 PPARTENTRY PartEntry)
2086 {
2087 PPARTENTRY NextPartEntry;
2088
2089 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2090 {
2091 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2092 PARTENTRY,
2093 ListEntry);
2094 if (NextPartEntry->IsPartitioned == FALSE)
2095 return NextPartEntry;
2096 }
2097
2098 return NULL;
2099 }
2100
2101
2102 VOID
2103 CreatePrimaryPartition(
2104 PPARTLIST List,
2105 ULONGLONG SectorCount,
2106 BOOLEAN AutoCreate)
2107 {
2108 PDISKENTRY DiskEntry;
2109 PPARTENTRY PartEntry;
2110 PPARTENTRY NewPartEntry;
2111
2112 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2113
2114 if (List == NULL ||
2115 List->CurrentDisk == NULL ||
2116 List->CurrentPartition == NULL ||
2117 List->CurrentPartition->IsPartitioned == TRUE)
2118 {
2119 return;
2120 }
2121
2122 DiskEntry = List->CurrentDisk;
2123 PartEntry = List->CurrentPartition;
2124
2125 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2126
2127 if (AutoCreate == TRUE ||
2128 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2129 {
2130 DPRINT1("Convert existing partition entry\n");
2131 /* Convert current entry to 'new (unformatted)' */
2132 PartEntry->IsPartitioned = TRUE;
2133 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2134 PartEntry->FormatState = Unformatted;
2135 PartEntry->AutoCreate = AutoCreate;
2136 PartEntry->New = TRUE;
2137 PartEntry->BootIndicator = FALSE; /* FIXME */
2138
2139 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2140 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2141 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2142 }
2143 else
2144 {
2145 DPRINT1("Add new partition entry\n");
2146
2147 /* Insert and initialize a new partition entry */
2148 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2149 HEAP_ZERO_MEMORY,
2150 sizeof(PARTENTRY));
2151 if (NewPartEntry == NULL)
2152 return;
2153
2154 /* Insert the new entry into the list */
2155 InsertTailList(&PartEntry->ListEntry,
2156 &NewPartEntry->ListEntry);
2157
2158 NewPartEntry->DiskEntry = DiskEntry;
2159
2160 NewPartEntry->IsPartitioned = TRUE;
2161 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2162 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2163 NewPartEntry->StartSector.QuadPart;
2164 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2165
2166 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2167 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2168 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2169
2170 NewPartEntry->New = TRUE;
2171 NewPartEntry->FormatState = Unformatted;
2172 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2173
2174 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2175 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2176 }
2177
2178 UpdateDiskLayout(DiskEntry);
2179
2180 DiskEntry->Dirty = TRUE;
2181
2182 UpdatePartitionNumbers(DiskEntry);
2183
2184 AssignDriveLetters(List);
2185 }
2186
2187
2188 VOID
2189 CreateExtendedPartition(
2190 PPARTLIST List,
2191 ULONGLONG SectorCount)
2192 {
2193 PDISKENTRY DiskEntry;
2194 PPARTENTRY PartEntry;
2195 PPARTENTRY NewPartEntry;
2196
2197 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2198
2199 if (List == NULL ||
2200 List->CurrentDisk == NULL ||
2201 List->CurrentPartition == NULL ||
2202 List->CurrentPartition->IsPartitioned == TRUE)
2203 {
2204 return;
2205 }
2206
2207 DiskEntry = List->CurrentDisk;
2208 PartEntry = List->CurrentPartition;
2209
2210 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2211
2212 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2213 {
2214 DPRINT1("Convert existing partition entry\n");
2215 /* Convert current entry to 'new (unformatted)' */
2216 PartEntry->IsPartitioned = TRUE;
2217 // PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2218 PartEntry->FormatState = Formatted;
2219 PartEntry->AutoCreate = FALSE;
2220 PartEntry->New = FALSE;
2221 PartEntry->BootIndicator = FALSE; /* FIXME */
2222
2223 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2224 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2225 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2226 }
2227 else
2228 {
2229 DPRINT1("Add new partition entry\n");
2230
2231 /* Insert and initialize a new partition entry */
2232 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2233 HEAP_ZERO_MEMORY,
2234 sizeof(PARTENTRY));
2235 if (NewPartEntry == NULL)
2236 return;
2237
2238 /* Insert the new entry into the list */
2239 InsertTailList(&PartEntry->ListEntry,
2240 &NewPartEntry->ListEntry);
2241
2242 NewPartEntry->DiskEntry = DiskEntry;
2243
2244 NewPartEntry->IsPartitioned = TRUE;
2245 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2246 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2247 NewPartEntry->StartSector.QuadPart;
2248
2249 // NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2250
2251 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2252 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2253 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2254
2255 NewPartEntry->New = FALSE;
2256 NewPartEntry->FormatState = Formatted;
2257 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2258
2259 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2260 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2261 }
2262
2263 if (NewPartEntry->StartSector.QuadPart < 1450560)
2264 {
2265 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2266 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2267 }
2268 else
2269 {
2270 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2271 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2272 }
2273
2274 UpdateDiskLayout(DiskEntry);
2275
2276 DiskEntry->Dirty = TRUE;
2277
2278 UpdatePartitionNumbers(DiskEntry);
2279
2280 AssignDriveLetters(List);
2281 }
2282
2283
2284 VOID
2285 DeleteCurrentPartition(
2286 PPARTLIST List)
2287 {
2288 PDISKENTRY DiskEntry;
2289 PPARTENTRY PartEntry;
2290 PPARTENTRY PrevPartEntry;
2291 PPARTENTRY NextPartEntry;
2292
2293 if (List == NULL ||
2294 List->CurrentDisk == NULL ||
2295 List->CurrentPartition == NULL ||
2296 List->CurrentPartition->IsPartitioned == FALSE)
2297 {
2298 return;
2299 }
2300
2301 DiskEntry = List->CurrentDisk;
2302 PartEntry = List->CurrentPartition;
2303
2304 /* Adjust unpartitioned disk space entries */
2305
2306 /* Get pointer to previous and next unpartitioned entries */
2307 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2308 PartEntry);
2309
2310 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2311 PartEntry);
2312
2313 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2314 {
2315 /* Merge previous, current and next unpartitioned entry */
2316
2317 /* Adjust the previous entries length */
2318 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2319
2320 /* Remove the current entry */
2321 RemoveEntryList(&PartEntry->ListEntry);
2322 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2323
2324 /* Remove the next entry */
2325 RemoveEntryList (&NextPartEntry->ListEntry);
2326 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2327
2328 /* Update current partition */
2329 List->CurrentPartition = PrevPartEntry;
2330 }
2331 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2332 {
2333 /* Merge current and previous unpartitioned entry */
2334
2335 /* Adjust the previous entries length */
2336 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2337
2338 /* Remove the current entry */
2339 RemoveEntryList(&PartEntry->ListEntry);
2340 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2341
2342 /* Update current partition */
2343 List->CurrentPartition = PrevPartEntry;
2344 }
2345 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2346 {
2347 /* Merge current and next unpartitioned entry */
2348
2349 /* Adjust the next entries offset and length */
2350 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2351 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2352
2353 /* Remove the current entry */
2354 RemoveEntryList(&PartEntry->ListEntry);
2355 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2356
2357 /* Update current partition */
2358 List->CurrentPartition = NextPartEntry;
2359 }
2360 else
2361 {
2362 /* Nothing to merge but change current entry */
2363 PartEntry->IsPartitioned = FALSE;
2364 PartEntry->FormatState = Unformatted;
2365 PartEntry->DriveLetter = 0;
2366 }
2367
2368 UpdateDiskLayout(DiskEntry);
2369
2370 DiskEntry->Dirty = TRUE;
2371
2372 UpdatePartitionNumbers(DiskEntry);
2373
2374 AssignDriveLetters(List);
2375 }
2376
2377
2378 VOID
2379 CheckActiveBootPartition(
2380 PPARTLIST List)
2381 {
2382 PDISKENTRY DiskEntry;
2383 PPARTENTRY PartEntry;
2384 PLIST_ENTRY ListEntry;
2385
2386 /* Check for empty disk list */
2387 if (IsListEmpty (&List->DiskListHead))
2388 {
2389 List->ActiveBootDisk = NULL;
2390 List->ActiveBootPartition = NULL;
2391 return;
2392 }
2393
2394 #if 0
2395 if (List->ActiveBootDisk != NULL &&
2396 List->ActiveBootPartition != NULL)
2397 {
2398 /* We already have an active boot partition */
2399 return;
2400 }
2401 #endif
2402
2403 /* Choose the currently selected disk */
2404 DiskEntry = List->CurrentDisk;
2405
2406 /* Check for empty partition list */
2407 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2408 {
2409 List->ActiveBootDisk = NULL;
2410 List->ActiveBootPartition = NULL;
2411 return;
2412 }
2413
2414 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2415 PARTENTRY,
2416 ListEntry);
2417
2418 /* Set active boot partition */
2419 if ((DiskEntry->NewDisk == TRUE) ||
2420 (PartEntry->BootIndicator == FALSE))
2421 {
2422 PartEntry->BootIndicator = TRUE;
2423 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2424 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2425 DiskEntry->Dirty = TRUE;
2426
2427 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2428 List->ActiveBootDisk = DiskEntry;
2429 List->ActiveBootPartition = PartEntry;
2430
2431 return;
2432 }
2433
2434 /* Disk is not new, scan all partitions to find a bootable one */
2435 List->ActiveBootDisk = NULL;
2436 List->ActiveBootPartition = NULL;
2437
2438 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2439 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2440 {
2441 PartEntry = CONTAINING_RECORD(ListEntry,
2442 PARTENTRY,
2443 ListEntry);
2444
2445 /* Check if it is partitioned */
2446 if (PartEntry->IsPartitioned)
2447 {
2448 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2449 PartEntry->BootIndicator)
2450 {
2451 /* Yes, we found it */
2452 List->ActiveBootDisk = DiskEntry;
2453 List->ActiveBootPartition = PartEntry;
2454
2455 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2456 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2457 break;
2458 }
2459 }
2460
2461 /* Go to the next one */
2462 ListEntry = ListEntry->Flink;
2463 }
2464 }
2465
2466
2467 BOOLEAN
2468 CheckForLinuxFdiskPartitions(
2469 PPARTLIST List)
2470 {
2471 #if 0
2472 PDISKENTRY DiskEntry;
2473 PPARTENTRY PartEntry;
2474 PLIST_ENTRY Entry1;
2475 PLIST_ENTRY Entry2;
2476 ULONG PartitionCount;
2477 ULONG i;
2478
2479 Entry1 = List->DiskListHead.Flink;
2480 while (Entry1 != &List->DiskListHead)
2481 {
2482 DiskEntry = CONTAINING_RECORD(Entry1,
2483 DISKENTRY,
2484 ListEntry);
2485
2486 Entry2 = DiskEntry->PartListHead.Flink;
2487 while (Entry2 != &DiskEntry->PartListHead)
2488 {
2489 PartEntry = CONTAINING_RECORD(Entry2,
2490 PARTENTRY,
2491 ListEntry);
2492
2493 if (PartEntry->Unpartitioned == FALSE)
2494 {
2495 PartitionCount = 0;
2496
2497 for (i = 0; i < 4; i++)
2498 {
2499 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2500 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2501 {
2502 PartitionCount++;
2503 }
2504 }
2505
2506 if (PartitionCount > 1)
2507 {
2508 return TRUE;
2509 }
2510 }
2511
2512 Entry2 = Entry2->Flink;
2513 }
2514
2515 Entry1 = Entry1->Flink;
2516 }
2517 #endif
2518
2519 return FALSE;
2520 }
2521
2522
2523 static
2524 NTSTATUS
2525 WritePartitons(
2526 IN PPARTLIST List,
2527 IN PDISKENTRY DiskEntry)
2528 {
2529 WCHAR DstPath[MAX_PATH];
2530 OBJECT_ATTRIBUTES ObjectAttributes;
2531 IO_STATUS_BLOCK Iosb;
2532 UNICODE_STRING Name;
2533 ULONG BufferSize;
2534 HANDLE FileHandle = NULL;
2535 NTSTATUS Status;
2536
2537 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2538
2539 swprintf(DstPath,
2540 L"\\Device\\Harddisk%d\\Partition0",
2541 DiskEntry->DiskNumber);
2542 RtlInitUnicodeString(&Name,
2543 DstPath);
2544 InitializeObjectAttributes(&ObjectAttributes,
2545 &Name,
2546 0,
2547 NULL,
2548 NULL);
2549
2550 Status = NtOpenFile(&FileHandle,
2551 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2552 &ObjectAttributes,
2553 &Iosb,
2554 0,
2555 FILE_SYNCHRONOUS_IO_NONALERT);
2556 if (!NT_SUCCESS(Status))
2557 {
2558 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2559 return Status;
2560 }
2561
2562 #ifdef DUMP_PARTITION_TABLE
2563 DumpPartitionTable(DiskEntry);
2564 #endif
2565
2566 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2567 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2568 Status = NtDeviceIoControlFile(FileHandle,
2569 NULL,
2570 NULL,
2571 NULL,
2572 &Iosb,
2573 IOCTL_DISK_SET_DRIVE_LAYOUT,
2574 DiskEntry->LayoutBuffer,
2575 BufferSize,
2576 NULL,
2577 0);
2578 if (!NT_SUCCESS(Status))
2579 {
2580 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2581 }
2582
2583 if (FileHandle != NULL)
2584 NtClose(FileHandle);
2585
2586 return Status;
2587 }
2588
2589
2590 BOOLEAN
2591 WritePartitionsToDisk(
2592 PPARTLIST List)
2593 {
2594 PLIST_ENTRY Entry;
2595 PDISKENTRY DiskEntry;
2596
2597 if (List == NULL)
2598 return TRUE;
2599
2600 Entry = List->DiskListHead.Flink;
2601 while (Entry != &List->DiskListHead)
2602 {
2603 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2604
2605 if (DiskEntry->Dirty == TRUE)
2606 {
2607 WritePartitons(List, DiskEntry);
2608 }
2609
2610 Entry = Entry->Flink;
2611 }
2612
2613 return TRUE;
2614 }
2615
2616
2617 BOOL
2618 SetMountedDeviceValues(
2619 PPARTLIST List)
2620 {
2621 PLIST_ENTRY Entry1, Entry2;
2622 PDISKENTRY DiskEntry;
2623 PPARTENTRY PartEntry;
2624 LARGE_INTEGER StartingOffset;
2625
2626 if (List == NULL)
2627 {
2628 return FALSE;
2629 }
2630
2631 Entry1 = List->DiskListHead.Flink;
2632 while (Entry1 != &List->DiskListHead)
2633 {
2634 DiskEntry = CONTAINING_RECORD(Entry1,
2635 DISKENTRY,
2636 ListEntry);
2637
2638 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2639 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2640 {
2641 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2642 if (PartEntry->IsPartitioned)
2643 {
2644 if (PartEntry->DriveLetter)
2645 {
2646 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2647 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
2648 DiskEntry->LayoutBuffer->Signature,
2649 StartingOffset))
2650 {
2651 return FALSE;
2652 }
2653 }
2654 }
2655
2656 Entry2 = Entry2->Flink;
2657 }
2658
2659 Entry1 = Entry1->Flink;
2660 }
2661
2662 return TRUE;
2663 }
2664
2665
2666 static
2667 BOOLEAN
2668 IsLastPrimaryPartiton(
2669 IN PPARTENTRY PartEntry)
2670 {
2671 return (PartEntry->ListEntry.Flink == &PartEntry->DiskEntry->PrimaryPartListHead);
2672 }
2673
2674
2675 static
2676 BOOLEAN
2677 IsPreviousPartitionExtended(
2678 IN PPARTENTRY PartEntry,
2679 IN PDISKENTRY DiskEntry)
2680 {
2681 PPARTENTRY PrevPartEntry;
2682 PLIST_ENTRY Entry;
2683
2684 Entry = PartEntry->ListEntry.Blink;
2685
2686 while (Entry != &DiskEntry->PrimaryPartListHead)
2687 {
2688 PrevPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2689
2690 if (IsContainerPartition(PrevPartEntry->PartitionType))
2691 return TRUE;
2692
2693 Entry = Entry->Blink;
2694 }
2695
2696 return FALSE;
2697
2698 }
2699
2700
2701 static
2702 ULONG
2703 GetPrimaryPartitionCount(
2704 IN PDISKENTRY DiskEntry)
2705 {
2706 PLIST_ENTRY Entry;
2707 PPARTENTRY PartEntry;
2708 UINT nCount = 0;
2709
2710 Entry = DiskEntry->PrimaryPartListHead.Flink;
2711 while (Entry != &DiskEntry->PrimaryPartListHead)
2712 {
2713 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2714 if (PartEntry->IsPartitioned == TRUE)
2715 nCount++;
2716
2717 Entry = Entry->Flink;
2718 }
2719
2720 return nCount;
2721 }
2722
2723
2724 static
2725 ULONG
2726 GetExtendedPartitionCount(
2727 IN PDISKENTRY DiskEntry)
2728 {
2729 PLIST_ENTRY Entry;
2730 PPARTENTRY PartEntry;
2731 UINT nCount = 0;
2732
2733 Entry = DiskEntry->PrimaryPartListHead.Flink;
2734 while (Entry != &DiskEntry->PrimaryPartListHead)
2735 {
2736 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2737 if (PartEntry->IsPartitioned == TRUE &&
2738 IsContainerPartition(PartEntry->PartitionType))
2739 nCount++;
2740
2741 Entry = Entry->Flink;
2742 }
2743
2744 return nCount;
2745 }
2746
2747
2748 ULONG
2749 PrimaryPartitionCreationChecks(
2750 IN PPARTLIST List)
2751 {
2752 PDISKENTRY DiskEntry;
2753 PPARTENTRY PartEntry;
2754
2755 DiskEntry = List->CurrentDisk;
2756 PartEntry = List->CurrentPartition;
2757
2758 /* Fail if partition is already in use */
2759 if (PartEntry->IsPartitioned == TRUE)
2760 return ERROR_NEW_PARTITION;
2761
2762 /* Fail if there are more than 4 partitions in the list */
2763 if (GetPrimaryPartitionCount(DiskEntry) > 4)
2764 return ERROR_PARTITION_TABLE_FULL;
2765
2766 /* FIXME: Fail if this partiton is located behind an extended partition */
2767 if (IsPreviousPartitionExtended(PartEntry, DiskEntry))
2768 return ERROR_NOT_BEHIND_EXTENDED;
2769
2770 return ERROR_SUCCESS;
2771 }
2772
2773
2774 ULONG
2775 ExtendedPartitionCreationChecks(
2776 IN PPARTLIST List)
2777 {
2778 PDISKENTRY DiskEntry;
2779 PPARTENTRY PartEntry;
2780
2781 DiskEntry = List->CurrentDisk;
2782 PartEntry = List->CurrentPartition;
2783
2784 /* Fail if partition is already in use */
2785 if (PartEntry->IsPartitioned == TRUE)
2786 return ERROR_NEW_PARTITION;
2787
2788 /* Fail if there are more than 4 partitions in the list */
2789 if (GetPrimaryPartitionCount(DiskEntry) > 4)
2790 return ERROR_PARTITION_TABLE_FULL;
2791
2792 /* Fail if there is another extended partition in the list */
2793 if (GetExtendedPartitionCount(DiskEntry) != 0)
2794 return ERROR_ONLY_ONE_EXTENDED;
2795
2796 /* Fail if the partition is not the last list entry */
2797 if (!IsLastPrimaryPartiton(PartEntry))
2798 return ERROR_EXTENDED_NOT_LAST;
2799
2800 return ERROR_SUCCESS;
2801 }
2802
2803
2804 /* EOF */