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