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