[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 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 }
1377
1378 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1379 #if 0
1380 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1381 {
1382 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1383 Unit = MUIGetString(STRING_GB);
1384 }
1385 else
1386 #endif
1387 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1388 {
1389 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1390 Unit = MUIGetString(STRING_MB);
1391 }
1392 else
1393 {
1394 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1395 Unit = MUIGetString(STRING_KB);
1396 }
1397
1398 if (PartType == NULL)
1399 {
1400 sprintf(LineBuffer,
1401 MUIGetString(STRING_HDDINFOUNK5),
1402 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1403 (PartEntry->DriveLetter == 0) ? '-' : ':',
1404 PartEntry->PartitionType,
1405 PartSize.u.LowPart,
1406 Unit);
1407 }
1408 else
1409 {
1410 sprintf(LineBuffer,
1411 "%c%c %-24s %6lu %s",
1412 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1413 (PartEntry->DriveLetter == 0) ? '-' : ':',
1414 PartType,
1415 PartSize.u.LowPart,
1416 Unit);
1417 }
1418 }
1419
1420 Attribute = (List->CurrentDisk == DiskEntry &&
1421 List->CurrentPartition == PartEntry) ?
1422 FOREGROUND_BLUE | BACKGROUND_WHITE :
1423 FOREGROUND_WHITE | BACKGROUND_BLUE;
1424
1425 if (List->Line >= 0 && List->Line <= Height)
1426 {
1427 FillConsoleOutputCharacterA(StdOutput,
1428 ' ',
1429 Width,
1430 coPos,
1431 &Written);
1432 }
1433 coPos.X += 4;
1434 Width -= 8;
1435 if (List->Line >= 0 && List->Line <= Height)
1436 {
1437 FillConsoleOutputAttribute(StdOutput,
1438 Attribute,
1439 Width,
1440 coPos,
1441 &Written);
1442 }
1443 coPos.X++;
1444 Width -= 2;
1445 if (List->Line >= 0 && List->Line <= Height)
1446 {
1447 WriteConsoleOutputCharacterA(StdOutput,
1448 LineBuffer,
1449 min(strlen(LineBuffer), Width),
1450 coPos,
1451 &Written);
1452 }
1453
1454 List->Line++;
1455 }
1456
1457
1458 static
1459 VOID
1460 PrintDiskData(
1461 PPARTLIST List,
1462 PDISKENTRY DiskEntry)
1463 {
1464 PPARTENTRY PartEntry;
1465 PLIST_ENTRY Entry;
1466 CHAR LineBuffer[128];
1467 COORD coPos;
1468 DWORD Written;
1469 USHORT Width;
1470 USHORT Height;
1471 ULARGE_INTEGER DiskSize;
1472 PCHAR Unit;
1473
1474 Width = List->Right - List->Left - 1;
1475 Height = List->Bottom - List->Top - 2;
1476
1477 coPos.X = List->Left + 1;
1478 coPos.Y = List->Top + 1 + List->Line;
1479
1480 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1481 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1482 {
1483 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1484 Unit = MUIGetString(STRING_GB);
1485 }
1486 else
1487 {
1488 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1489 if (DiskSize.QuadPart == 0)
1490 DiskSize.QuadPart = 1;
1491 Unit = MUIGetString(STRING_MB);
1492 }
1493
1494 if (DiskEntry->DriverName.Length > 0)
1495 {
1496 sprintf(LineBuffer,
1497 MUIGetString(STRING_HDINFOPARTSELECT),
1498 DiskSize.u.LowPart,
1499 Unit,
1500 DiskEntry->DiskNumber,
1501 DiskEntry->Port,
1502 DiskEntry->Bus,
1503 DiskEntry->Id,
1504 DiskEntry->DriverName.Buffer);
1505 }
1506 else
1507 {
1508 sprintf(LineBuffer,
1509 MUIGetString(STRING_HDDINFOUNK6),
1510 DiskSize.u.LowPart,
1511 Unit,
1512 DiskEntry->DiskNumber,
1513 DiskEntry->Port,
1514 DiskEntry->Bus,
1515 DiskEntry->Id);
1516 }
1517
1518 if (List->Line >= 0 && List->Line <= Height)
1519 {
1520 FillConsoleOutputAttribute(StdOutput,
1521 FOREGROUND_WHITE | BACKGROUND_BLUE,
1522 Width,
1523 coPos,
1524 &Written);
1525
1526 FillConsoleOutputCharacterA(StdOutput,
1527 ' ',
1528 Width,
1529 coPos,
1530 &Written);
1531 }
1532
1533 coPos.X++;
1534 if (List->Line >= 0 && List->Line <= Height)
1535 {
1536 WriteConsoleOutputCharacterA(StdOutput,
1537 LineBuffer,
1538 min((USHORT)strlen(LineBuffer), Width - 2),
1539 coPos,
1540 &Written);
1541 }
1542
1543 List->Line++;
1544
1545 /* Print separator line */
1546 PrintEmptyLine(List);
1547
1548 /* Print partition lines*/
1549 Entry = DiskEntry->PrimaryPartListHead.Flink;
1550 while (Entry != &DiskEntry->PrimaryPartListHead)
1551 {
1552 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1553
1554 PrintPartitionData(List,
1555 DiskEntry,
1556 PartEntry);
1557
1558 Entry = Entry->Flink;
1559 }
1560
1561 /* Print separator line */
1562 PrintEmptyLine(List);
1563 }
1564
1565
1566 VOID
1567 DrawPartitionList(
1568 PPARTLIST List)
1569 {
1570 PLIST_ENTRY Entry, Entry2;
1571 PDISKENTRY DiskEntry;
1572 PPARTENTRY PartEntry = NULL;
1573 COORD coPos;
1574 DWORD Written;
1575 SHORT i;
1576 SHORT CurrentDiskLine;
1577 SHORT CurrentPartLine;
1578 SHORT LastLine;
1579 BOOL CurrentPartLineFound = FALSE;
1580 BOOL CurrentDiskLineFound = FALSE;
1581
1582 /* Calculate the line of the current disk and partition */
1583 CurrentDiskLine = 0;
1584 CurrentPartLine = 0;
1585 LastLine = 0;
1586
1587 Entry = List->DiskListHead.Flink;
1588 while (Entry != &List->DiskListHead)
1589 {
1590 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1591
1592 LastLine += 2;
1593 if (CurrentPartLineFound == FALSE)
1594 {
1595 CurrentPartLine += 2;
1596 }
1597
1598 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1599 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1600 {
1601 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1602 if (PartEntry == List->CurrentPartition)
1603 {
1604 CurrentPartLineFound = TRUE;
1605 }
1606
1607 Entry2 = Entry2->Flink;
1608 if (CurrentPartLineFound == FALSE)
1609 {
1610 CurrentPartLine++;
1611 }
1612
1613 LastLine++;
1614 }
1615
1616 if (DiskEntry == List->CurrentDisk)
1617 {
1618 CurrentDiskLineFound = TRUE;
1619 }
1620
1621 Entry = Entry->Flink;
1622 if (Entry != &List->DiskListHead)
1623 {
1624 if (CurrentDiskLineFound == FALSE)
1625 {
1626 CurrentPartLine ++;
1627 CurrentDiskLine = CurrentPartLine;
1628 }
1629
1630 LastLine++;
1631 }
1632 else
1633 {
1634 LastLine--;
1635 }
1636 }
1637
1638 /* If it possible, make the disk name visible */
1639 if (CurrentPartLine < List->Offset)
1640 {
1641 List->Offset = CurrentPartLine;
1642 }
1643 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1644 {
1645 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1646 }
1647
1648 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1649 {
1650 List->Offset = CurrentDiskLine;
1651 }
1652
1653 /* draw upper left corner */
1654 coPos.X = List->Left;
1655 coPos.Y = List->Top;
1656 FillConsoleOutputCharacterA(StdOutput,
1657 0xDA, // '+',
1658 1,
1659 coPos,
1660 &Written);
1661
1662 /* draw upper edge */
1663 coPos.X = List->Left + 1;
1664 coPos.Y = List->Top;
1665 if (List->Offset == 0)
1666 {
1667 FillConsoleOutputCharacterA(StdOutput,
1668 0xC4, // '-',
1669 List->Right - List->Left - 1,
1670 coPos,
1671 &Written);
1672 }
1673 else
1674 {
1675 FillConsoleOutputCharacterA(StdOutput,
1676 0xC4, // '-',
1677 List->Right - List->Left - 5,
1678 coPos,
1679 &Written);
1680 coPos.X = List->Right - 5;
1681 WriteConsoleOutputCharacterA(StdOutput,
1682 "(\x18)", // "(up)"
1683 3,
1684 coPos,
1685 &Written);
1686 coPos.X = List->Right - 2;
1687 FillConsoleOutputCharacterA(StdOutput,
1688 0xC4, // '-',
1689 2,
1690 coPos,
1691 &Written);
1692 }
1693
1694 /* draw upper right corner */
1695 coPos.X = List->Right;
1696 coPos.Y = List->Top;
1697 FillConsoleOutputCharacterA(StdOutput,
1698 0xBF, // '+',
1699 1,
1700 coPos,
1701 &Written);
1702
1703 /* draw left and right edge */
1704 for (i = List->Top + 1; i < List->Bottom; i++)
1705 {
1706 coPos.X = List->Left;
1707 coPos.Y = i;
1708 FillConsoleOutputCharacterA(StdOutput,
1709 0xB3, // '|',
1710 1,
1711 coPos,
1712 &Written);
1713
1714 coPos.X = List->Right;
1715 FillConsoleOutputCharacterA(StdOutput,
1716 0xB3, //'|',
1717 1,
1718 coPos,
1719 &Written);
1720 }
1721
1722 /* draw lower left corner */
1723 coPos.X = List->Left;
1724 coPos.Y = List->Bottom;
1725 FillConsoleOutputCharacterA(StdOutput,
1726 0xC0, // '+',
1727 1,
1728 coPos,
1729 &Written);
1730
1731 /* draw lower edge */
1732 coPos.X = List->Left + 1;
1733 coPos.Y = List->Bottom;
1734 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1735 {
1736 FillConsoleOutputCharacterA(StdOutput,
1737 0xC4, // '-',
1738 List->Right - List->Left - 1,
1739 coPos,
1740 &Written);
1741 }
1742 else
1743 {
1744 FillConsoleOutputCharacterA(StdOutput,
1745 0xC4, // '-',
1746 List->Right - List->Left - 5,
1747 coPos,
1748 &Written);
1749 coPos.X = List->Right - 5;
1750 WriteConsoleOutputCharacterA(StdOutput,
1751 "(\x19)", // "(down)"
1752 3,
1753 coPos,
1754 &Written);
1755 coPos.X = List->Right - 2;
1756 FillConsoleOutputCharacterA(StdOutput,
1757 0xC4, // '-',
1758 2,
1759 coPos,
1760 &Written);
1761 }
1762
1763 /* draw lower right corner */
1764 coPos.X = List->Right;
1765 coPos.Y = List->Bottom;
1766 FillConsoleOutputCharacterA(StdOutput,
1767 0xD9, // '+',
1768 1,
1769 coPos,
1770 &Written);
1771
1772 /* print list entries */
1773 List->Line = - List->Offset;
1774
1775 Entry = List->DiskListHead.Flink;
1776 while (Entry != &List->DiskListHead)
1777 {
1778 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1779
1780 /* Print disk entry */
1781 PrintDiskData(List,
1782 DiskEntry);
1783
1784 Entry = Entry->Flink;
1785 }
1786 }
1787
1788
1789 DWORD
1790 SelectPartition(
1791 PPARTLIST List,
1792 ULONG DiskNumber,
1793 ULONG PartitionNumber)
1794 {
1795 PDISKENTRY DiskEntry;
1796 PPARTENTRY PartEntry;
1797 PLIST_ENTRY Entry1;
1798 PLIST_ENTRY Entry2;
1799
1800 /* Check for empty disks */
1801 if (IsListEmpty(&List->DiskListHead))
1802 return FALSE;
1803
1804 /* Check for first usable entry on next disk */
1805 Entry1 = List->CurrentDisk->ListEntry.Flink;
1806 while (Entry1 != &List->DiskListHead)
1807 {
1808 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1809
1810 if (DiskEntry->DiskNumber == DiskNumber)
1811 {
1812 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1813 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1814 {
1815 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1816
1817 if (PartEntry->PartitionNumber == PartitionNumber)
1818 {
1819 List->CurrentDisk = DiskEntry;
1820 List->CurrentPartition = PartEntry;
1821 DrawPartitionList(List);
1822 return TRUE;
1823 }
1824
1825 Entry2 = Entry2->Flink;
1826 }
1827
1828 return FALSE;
1829 }
1830
1831 Entry1 = Entry1->Flink;
1832 }
1833
1834 return FALSE;
1835 }
1836
1837
1838 VOID
1839 ScrollDownPartitionList(
1840 PPARTLIST List)
1841 {
1842 // PDISKENTRY DiskEntry;
1843 PPARTENTRY PartEntry;
1844 // PLIST_ENTRY Entry1;
1845 PLIST_ENTRY Entry2;
1846
1847 /* Check for empty disks */
1848 if (IsListEmpty(&List->DiskListHead))
1849 return;
1850
1851 /* Check for next usable entry on current disk */
1852 if (List->CurrentPartition != NULL)
1853 {
1854 Entry2 = List->CurrentPartition->ListEntry.Flink;
1855 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
1856 {
1857 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1858
1859 List->CurrentPartition = PartEntry;
1860 DrawPartitionList(List);
1861 return;
1862 }
1863 }
1864
1865 #if 0
1866 /* Check for first usable entry on next disk */
1867 if (List->CurrentDisk != NULL)
1868 {
1869 Entry1 = List->CurrentDisk->ListEntry.Flink;
1870 while (Entry1 != &List->DiskListHead)
1871 {
1872 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1873
1874 Entry2 = DiskEntry->PartListHead.Flink;
1875 if (Entry2 != &DiskEntry->PartListHead)
1876 {
1877 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1878
1879 List->CurrentDisk = DiskEntry;
1880 List->CurrentPartition = PartEntry;
1881 DrawPartitionList(List);
1882 return;
1883 }
1884
1885 Entry1 = Entry1->Flink;
1886 }
1887 }
1888 #endif
1889 }
1890
1891
1892 VOID
1893 ScrollUpPartitionList(
1894 PPARTLIST List)
1895 {
1896 // PDISKENTRY DiskEntry;
1897 PPARTENTRY PartEntry;
1898 // PLIST_ENTRY Entry1;
1899 PLIST_ENTRY Entry2;
1900
1901 /* Check for empty disks */
1902 if (IsListEmpty(&List->DiskListHead))
1903 return;
1904
1905 /* check for previous usable entry on current disk */
1906 if (List->CurrentPartition != NULL)
1907 {
1908 Entry2 = List->CurrentPartition->ListEntry.Blink;
1909 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
1910 {
1911 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1912
1913 List->CurrentPartition = PartEntry;
1914
1915 /* Draw partition list and return */
1916 DrawPartitionList(List);
1917 return;
1918 }
1919 }
1920
1921 #if 0
1922 /* check for last usable entry on previous disk */
1923 if (List->CurrentDisk != NULL)
1924 {
1925 Entry1 = List->CurrentDisk->ListEntry.Blink;
1926 while (Entry1 != &List->DiskListHead)
1927 {
1928 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1929
1930 Entry2 = DiskEntry->PrimaryPartListHead.Blink;
1931 if (Entry2 != &DiskEntry->PrimaryPartListHead)
1932 {
1933 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1934
1935 List->CurrentDisk = DiskEntry;
1936 List->CurrentPartition = PartEntry;
1937
1938 /* Draw partition list and return */
1939 DrawPartitionList(List);
1940 return;
1941 }
1942
1943 Entry1 = Entry1->Blink;
1944 }
1945 }
1946 #endif
1947 }
1948
1949
1950 static
1951 BOOLEAN
1952 IsEmptyLayoutEntry(
1953 PPARTITION_INFORMATION PartitionInfo)
1954 {
1955 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
1956 PartitionInfo->PartitionLength.QuadPart == 0)
1957 // PartitionInfo->PartitionType == 0)
1958 return TRUE;
1959
1960 return FALSE;
1961 }
1962
1963
1964 static
1965 BOOLEAN
1966 IsSamePrimaryLayoutEntry(
1967 IN PPARTITION_INFORMATION PartitionInfo,
1968 IN PDISKENTRY DiskEntry,
1969 IN PPARTENTRY PartEntry)
1970 {
1971 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
1972 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
1973 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
1974 // PartitionInfo->PartitionType == PartEntry->PartitionType
1975 return TRUE;
1976
1977 return FALSE;
1978 }
1979
1980
1981 static
1982 VOID
1983 UpdateDiskLayout(
1984 IN PDISKENTRY DiskEntry)
1985 {
1986 PPARTITION_INFORMATION PartitionInfo;
1987 PLIST_ENTRY ListEntry;
1988 PPARTENTRY PartEntry;
1989 ULONG Index = 0;
1990 ULONG PartitionNumber = 1;
1991
1992 DPRINT1("UpdateDiskLayout()\n");
1993
1994 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
1995 while (ListEntry != &DiskEntry->PrimaryPartListHead)
1996 {
1997 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
1998
1999 if (PartEntry->IsPartitioned == TRUE)
2000 {
2001 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2002
2003 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2004 {
2005 DPRINT1("Updating partition entry %lu\n", Index);
2006 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2007 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2008 PartitionInfo->HiddenSectors = 0;
2009 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2010 PartitionInfo->PartitionType = PartEntry->PartitionType;
2011 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2012 PartitionInfo->RecognizedPartition = FALSE;
2013 PartitionInfo->RewritePartition = TRUE;
2014
2015 PartEntry->PartitionNumber = PartitionNumber;
2016 PartEntry->PartitionIndex = Index;
2017
2018 PartitionNumber++;
2019 }
2020 else if (!IsEmptyLayoutEntry(PartitionInfo))
2021 {
2022 PartitionNumber++;
2023 }
2024
2025 Index++;
2026 }
2027
2028 ListEntry = ListEntry->Flink;
2029 }
2030
2031 for (;Index < 4; Index++)
2032 {
2033 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2034
2035 if (!IsEmptyLayoutEntry(PartitionInfo))
2036 {
2037 DPRINT1("Wiping partition entry %lu\n", Index);
2038 PartitionInfo->StartingOffset.QuadPart = 0;
2039 PartitionInfo->PartitionLength.QuadPart = 0;
2040 PartitionInfo->HiddenSectors = 0;
2041 PartitionInfo->PartitionNumber = 0;
2042 PartitionInfo->PartitionType = 0;
2043 PartitionInfo->BootIndicator = FALSE;
2044 PartitionInfo->RecognizedPartition = FALSE;
2045 PartitionInfo->RewritePartition = TRUE;
2046 }
2047 }
2048
2049 #ifdef DUMP_PARTITION_TABLE
2050 DumpPartitionTable(DiskEntry);
2051 #endif
2052 }
2053
2054
2055 static
2056 PPARTENTRY
2057 GetPrevUnpartitionedEntry(
2058 PDISKENTRY DiskEntry,
2059 PPARTENTRY PartEntry)
2060 {
2061 PPARTENTRY PrevPartEntry;
2062
2063 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2064 {
2065 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2066 PARTENTRY,
2067 ListEntry);
2068 if (PrevPartEntry->IsPartitioned == FALSE)
2069 return PrevPartEntry;
2070 }
2071
2072 return NULL;
2073 }
2074
2075
2076 static
2077 PPARTENTRY
2078 GetNextUnpartitionedEntry(
2079 PDISKENTRY DiskEntry,
2080 PPARTENTRY PartEntry)
2081 {
2082 PPARTENTRY NextPartEntry;
2083
2084 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2085 {
2086 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2087 PARTENTRY,
2088 ListEntry);
2089 if (NextPartEntry->IsPartitioned == FALSE)
2090 return NextPartEntry;
2091 }
2092
2093 return NULL;
2094 }
2095
2096
2097 VOID
2098 CreateNewPartition(
2099 PPARTLIST List,
2100 ULONGLONG SectorCount,
2101 BOOLEAN AutoCreate)
2102 {
2103 PDISKENTRY DiskEntry;
2104 PPARTENTRY PartEntry;
2105 PPARTENTRY NewPartEntry;
2106
2107 DPRINT1("CreateNewPartition(%I64u)\n", SectorCount);
2108
2109 if (List == NULL ||
2110 List->CurrentDisk == NULL ||
2111 List->CurrentPartition == NULL ||
2112 List->CurrentPartition->IsPartitioned == TRUE)
2113 {
2114 return;
2115 }
2116
2117 DiskEntry = List->CurrentDisk;
2118 PartEntry = List->CurrentPartition;
2119
2120 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2121
2122 if (AutoCreate == TRUE ||
2123 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2124 {
2125 DPRINT1("Convert existing partition entry\n");
2126 /* Convert current entry to 'new (unformatted)' */
2127 PartEntry->IsPartitioned = TRUE;
2128 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2129 PartEntry->FormatState = Unformatted;
2130 PartEntry->AutoCreate = AutoCreate;
2131 PartEntry->New = TRUE;
2132 PartEntry->BootIndicator = FALSE; /* FIXME */
2133
2134 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2135 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2136 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2137 }
2138 else
2139 {
2140 DPRINT1("Add new partition entry\n");
2141
2142 /* Insert and initialize a new partition entry */
2143 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2144 HEAP_ZERO_MEMORY,
2145 sizeof(PARTENTRY));
2146 if (NewPartEntry == NULL)
2147 return;
2148
2149 /* Insert the new entry into the list */
2150 InsertTailList(&PartEntry->ListEntry,
2151 &NewPartEntry->ListEntry);
2152
2153 NewPartEntry->DiskEntry = DiskEntry;
2154
2155 NewPartEntry->IsPartitioned = TRUE;
2156 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2157 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2158 NewPartEntry->StartSector.QuadPart;
2159 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2160
2161 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2162 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2163 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2164
2165 NewPartEntry->New = TRUE;
2166 NewPartEntry->FormatState = Unformatted;
2167 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2168
2169 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2170 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2171 }
2172
2173 UpdateDiskLayout(DiskEntry);
2174
2175 DiskEntry->Dirty = TRUE;
2176
2177 UpdatePartitionNumbers(DiskEntry);
2178
2179 AssignDriveLetters(List);
2180 }
2181
2182
2183 VOID
2184 DeleteCurrentPartition(
2185 PPARTLIST List)
2186 {
2187 PDISKENTRY DiskEntry;
2188 PPARTENTRY PartEntry;
2189 PPARTENTRY PrevPartEntry;
2190 PPARTENTRY NextPartEntry;
2191
2192 if (List == NULL ||
2193 List->CurrentDisk == NULL ||
2194 List->CurrentPartition == NULL ||
2195 List->CurrentPartition->IsPartitioned == FALSE)
2196 {
2197 return;
2198 }
2199
2200 DiskEntry = List->CurrentDisk;
2201 PartEntry = List->CurrentPartition;
2202
2203 /* Adjust unpartitioned disk space entries */
2204
2205 /* Get pointer to previous and next unpartitioned entries */
2206 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2207 PartEntry);
2208
2209 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2210 PartEntry);
2211
2212 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2213 {
2214 /* Merge previous, current and next unpartitioned entry */
2215
2216 /* Adjust the previous entries length */
2217 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2218
2219 /* Remove the current entry */
2220 RemoveEntryList(&PartEntry->ListEntry);
2221 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2222
2223 /* Remove the next entry */
2224 RemoveEntryList (&NextPartEntry->ListEntry);
2225 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2226
2227 /* Update current partition */
2228 List->CurrentPartition = PrevPartEntry;
2229 }
2230 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2231 {
2232 /* Merge current and previous unpartitioned entry */
2233
2234 /* Adjust the previous entries length */
2235 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2236
2237 /* Remove the current entry */
2238 RemoveEntryList(&PartEntry->ListEntry);
2239 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2240
2241 /* Update current partition */
2242 List->CurrentPartition = PrevPartEntry;
2243 }
2244 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2245 {
2246 /* Merge current and next unpartitioned entry */
2247
2248 /* Adjust the next entries offset and length */
2249 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2250 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2251
2252 /* Remove the current entry */
2253 RemoveEntryList(&PartEntry->ListEntry);
2254 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2255
2256 /* Update current partition */
2257 List->CurrentPartition = NextPartEntry;
2258 }
2259 else
2260 {
2261 /* Nothing to merge but change current entry */
2262 PartEntry->IsPartitioned = FALSE;
2263 PartEntry->FormatState = Unformatted;
2264 PartEntry->DriveLetter = 0;
2265 }
2266
2267 UpdateDiskLayout(DiskEntry);
2268
2269 DiskEntry->Dirty = TRUE;
2270
2271 UpdatePartitionNumbers(DiskEntry);
2272
2273 AssignDriveLetters(List);
2274 }
2275
2276
2277 VOID
2278 CheckActiveBootPartition(
2279 PPARTLIST List)
2280 {
2281 PDISKENTRY DiskEntry;
2282 PPARTENTRY PartEntry;
2283 PLIST_ENTRY ListEntry;
2284
2285 /* Check for empty disk list */
2286 if (IsListEmpty (&List->DiskListHead))
2287 {
2288 List->ActiveBootDisk = NULL;
2289 List->ActiveBootPartition = NULL;
2290 return;
2291 }
2292
2293 #if 0
2294 if (List->ActiveBootDisk != NULL &&
2295 List->ActiveBootPartition != NULL)
2296 {
2297 /* We already have an active boot partition */
2298 return;
2299 }
2300 #endif
2301
2302 /* Choose the currently selected disk */
2303 DiskEntry = List->CurrentDisk;
2304
2305 /* Check for empty partition list */
2306 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2307 {
2308 List->ActiveBootDisk = NULL;
2309 List->ActiveBootPartition = NULL;
2310 return;
2311 }
2312
2313 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2314 PARTENTRY,
2315 ListEntry);
2316
2317 /* Set active boot partition */
2318 if ((DiskEntry->NewDisk == TRUE) ||
2319 (PartEntry->BootIndicator == FALSE))
2320 {
2321 PartEntry->BootIndicator = TRUE;
2322 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2323 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2324 DiskEntry->Dirty = TRUE;
2325
2326 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2327 List->ActiveBootDisk = DiskEntry;
2328 List->ActiveBootPartition = PartEntry;
2329
2330 return;
2331 }
2332
2333 /* Disk is not new, scan all partitions to find a bootable one */
2334 List->ActiveBootDisk = NULL;
2335 List->ActiveBootPartition = NULL;
2336
2337 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2338 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2339 {
2340 PartEntry = CONTAINING_RECORD(ListEntry,
2341 PARTENTRY,
2342 ListEntry);
2343
2344 /* Check if it is partitioned */
2345 if (PartEntry->IsPartitioned)
2346 {
2347 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2348 PartEntry->BootIndicator)
2349 {
2350 /* Yes, we found it */
2351 List->ActiveBootDisk = DiskEntry;
2352 List->ActiveBootPartition = PartEntry;
2353
2354 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2355 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2356 break;
2357 }
2358 }
2359
2360 /* Go to the next one */
2361 ListEntry = ListEntry->Flink;
2362 }
2363 }
2364
2365
2366 BOOLEAN
2367 CheckForLinuxFdiskPartitions(
2368 PPARTLIST List)
2369 {
2370 #if 0
2371 PDISKENTRY DiskEntry;
2372 PPARTENTRY PartEntry;
2373 PLIST_ENTRY Entry1;
2374 PLIST_ENTRY Entry2;
2375 ULONG PartitionCount;
2376 ULONG i;
2377
2378 Entry1 = List->DiskListHead.Flink;
2379 while (Entry1 != &List->DiskListHead)
2380 {
2381 DiskEntry = CONTAINING_RECORD(Entry1,
2382 DISKENTRY,
2383 ListEntry);
2384
2385 Entry2 = DiskEntry->PartListHead.Flink;
2386 while (Entry2 != &DiskEntry->PartListHead)
2387 {
2388 PartEntry = CONTAINING_RECORD(Entry2,
2389 PARTENTRY,
2390 ListEntry);
2391
2392 if (PartEntry->Unpartitioned == FALSE)
2393 {
2394 PartitionCount = 0;
2395
2396 for (i = 0; i < 4; i++)
2397 {
2398 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2399 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2400 {
2401 PartitionCount++;
2402 }
2403 }
2404
2405 if (PartitionCount > 1)
2406 {
2407 return TRUE;
2408 }
2409 }
2410
2411 Entry2 = Entry2->Flink;
2412 }
2413
2414 Entry1 = Entry1->Flink;
2415 }
2416 #endif
2417
2418 return FALSE;
2419 }
2420
2421
2422 static
2423 NTSTATUS
2424 WritePartitons(
2425 IN PPARTLIST List,
2426 IN PDISKENTRY DiskEntry)
2427 {
2428 WCHAR DstPath[MAX_PATH];
2429 OBJECT_ATTRIBUTES ObjectAttributes;
2430 IO_STATUS_BLOCK Iosb;
2431 UNICODE_STRING Name;
2432 ULONG BufferSize;
2433 HANDLE FileHandle = NULL;
2434 NTSTATUS Status;
2435
2436 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2437
2438 swprintf(DstPath,
2439 L"\\Device\\Harddisk%d\\Partition0",
2440 DiskEntry->DiskNumber);
2441 RtlInitUnicodeString(&Name,
2442 DstPath);
2443 InitializeObjectAttributes(&ObjectAttributes,
2444 &Name,
2445 0,
2446 NULL,
2447 NULL);
2448
2449 Status = NtOpenFile(&FileHandle,
2450 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2451 &ObjectAttributes,
2452 &Iosb,
2453 0,
2454 FILE_SYNCHRONOUS_IO_NONALERT);
2455 if (!NT_SUCCESS(Status))
2456 {
2457 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2458 return Status;
2459 }
2460
2461 #ifdef DUMP_PARTITION_TABLE
2462 DumpPartitionTable(DiskEntry);
2463 #endif
2464
2465 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2466 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2467 Status = NtDeviceIoControlFile(FileHandle,
2468 NULL,
2469 NULL,
2470 NULL,
2471 &Iosb,
2472 IOCTL_DISK_SET_DRIVE_LAYOUT,
2473 DiskEntry->LayoutBuffer,
2474 BufferSize,
2475 NULL,
2476 0);
2477 if (!NT_SUCCESS(Status))
2478 {
2479 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2480 }
2481
2482 if (FileHandle != NULL)
2483 NtClose(FileHandle);
2484
2485 return Status;
2486 }
2487
2488
2489 BOOLEAN
2490 WritePartitionsToDisk(
2491 PPARTLIST List)
2492 {
2493 PLIST_ENTRY Entry;
2494 PDISKENTRY DiskEntry;
2495
2496 if (List == NULL)
2497 return TRUE;
2498
2499 Entry = List->DiskListHead.Flink;
2500 while (Entry != &List->DiskListHead)
2501 {
2502 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2503
2504 if (DiskEntry->Dirty == TRUE)
2505 {
2506 WritePartitons(List, DiskEntry);
2507 }
2508
2509 Entry = Entry->Flink;
2510 }
2511
2512 return TRUE;
2513 }
2514
2515
2516 BOOL
2517 SetMountedDeviceValues(
2518 PPARTLIST List)
2519 {
2520 PLIST_ENTRY Entry1, Entry2;
2521 PDISKENTRY DiskEntry;
2522 PPARTENTRY PartEntry;
2523 LARGE_INTEGER StartingOffset;
2524
2525 if (List == NULL)
2526 {
2527 return FALSE;
2528 }
2529
2530 Entry1 = List->DiskListHead.Flink;
2531 while (Entry1 != &List->DiskListHead)
2532 {
2533 DiskEntry = CONTAINING_RECORD(Entry1,
2534 DISKENTRY,
2535 ListEntry);
2536
2537 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2538 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2539 {
2540 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2541 if (PartEntry->IsPartitioned)
2542 {
2543 if (PartEntry->DriveLetter)
2544 {
2545 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2546 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
2547 DiskEntry->LayoutBuffer->Signature,
2548 StartingOffset))
2549 {
2550 return FALSE;
2551 }
2552 }
2553 }
2554
2555 Entry2 = Entry2->Flink;
2556 }
2557
2558 Entry1 = Entry1->Flink;
2559 }
2560
2561 return TRUE;
2562 }
2563
2564 /* EOF */