47a6db053781796cbd5e41ba9fc0402c06da0f8a
[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 = Unformatted;
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->New == TRUE)
1503 {
1504 PartType = MUIGetString(STRING_UNFORMATTED);
1505 }
1506 else if (PartEntry->IsPartitioned == TRUE)
1507 {
1508 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
1509 (PartEntry->PartitionType == PARTITION_FAT_16) ||
1510 (PartEntry->PartitionType == PARTITION_HUGE) ||
1511 (PartEntry->PartitionType == PARTITION_XINT13))
1512 {
1513 PartType = "FAT";
1514 }
1515 else if ((PartEntry->PartitionType == PARTITION_FAT32) ||
1516 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
1517 {
1518 PartType = "FAT32";
1519 }
1520 else if (PartEntry->PartitionType == PARTITION_EXT2)
1521 {
1522 PartType = "EXT2";
1523 }
1524 else if (PartEntry->PartitionType == PARTITION_IFS)
1525 {
1526 PartType = "NTFS"; /* FIXME: Not quite correct! */
1527 }
1528 else if ((PartEntry->PartitionType == PARTITION_EXTENDED) ||
1529 (PartEntry->PartitionType == PARTITION_XINT13_EXTENDED))
1530 {
1531 PartType = MUIGetString(STRING_EXTENDED_PARTITION);
1532 }
1533 }
1534
1535 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1536 #if 0
1537 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1538 {
1539 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1540 Unit = MUIGetString(STRING_GB);
1541 }
1542 else
1543 #endif
1544 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1545 {
1546 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1547 Unit = MUIGetString(STRING_MB);
1548 }
1549 else
1550 {
1551 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1552 Unit = MUIGetString(STRING_KB);
1553 }
1554
1555 if (PartType == NULL)
1556 {
1557 sprintf(LineBuffer,
1558 MUIGetString(STRING_HDDINFOUNK5),
1559 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1560 (PartEntry->DriveLetter == 0) ? '-' : ':',
1561 PartEntry->BootIndicator ? '*' : ' ',
1562 PartEntry->LogicalPartition ? " " : "",
1563 PartEntry->PartitionType,
1564 PartEntry->LogicalPartition ? "" : " ",
1565 PartSize.u.LowPart,
1566 Unit);
1567 }
1568 else
1569 {
1570 sprintf(LineBuffer,
1571 "%c%c %c %s%-24s%s %6lu %s",
1572 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1573 (PartEntry->DriveLetter == 0) ? '-' : ':',
1574 PartEntry->BootIndicator ? '*' : ' ',
1575 PartEntry->LogicalPartition ? " " : "",
1576 PartType,
1577 PartEntry->LogicalPartition ? "" : " ",
1578 PartSize.u.LowPart,
1579 Unit);
1580 }
1581 }
1582
1583 Attribute = (List->CurrentDisk == DiskEntry &&
1584 List->CurrentPartition == PartEntry) ?
1585 FOREGROUND_BLUE | BACKGROUND_WHITE :
1586 FOREGROUND_WHITE | BACKGROUND_BLUE;
1587
1588 if (List->Line >= 0 && List->Line <= Height)
1589 {
1590 FillConsoleOutputCharacterA(StdOutput,
1591 ' ',
1592 Width,
1593 coPos,
1594 &Written);
1595 }
1596 coPos.X += 4;
1597 Width -= 8;
1598 if (List->Line >= 0 && List->Line <= Height)
1599 {
1600 FillConsoleOutputAttribute(StdOutput,
1601 Attribute,
1602 Width,
1603 coPos,
1604 &Written);
1605 }
1606 coPos.X++;
1607 Width -= 2;
1608 if (List->Line >= 0 && List->Line <= Height)
1609 {
1610 WriteConsoleOutputCharacterA(StdOutput,
1611 LineBuffer,
1612 min(strlen(LineBuffer), Width),
1613 coPos,
1614 &Written);
1615 }
1616
1617 List->Line++;
1618 }
1619
1620
1621 static
1622 VOID
1623 PrintDiskData(
1624 PPARTLIST List,
1625 PDISKENTRY DiskEntry)
1626 {
1627 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1628 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1629 CHAR LineBuffer[128];
1630 COORD coPos;
1631 DWORD Written;
1632 USHORT Width;
1633 USHORT Height;
1634 ULARGE_INTEGER DiskSize;
1635 PCHAR Unit;
1636
1637 Width = List->Right - List->Left - 1;
1638 Height = List->Bottom - List->Top - 2;
1639
1640 coPos.X = List->Left + 1;
1641 coPos.Y = List->Top + 1 + List->Line;
1642
1643 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1644 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1645 {
1646 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1647 Unit = MUIGetString(STRING_GB);
1648 }
1649 else
1650 {
1651 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1652 if (DiskSize.QuadPart == 0)
1653 DiskSize.QuadPart = 1;
1654 Unit = MUIGetString(STRING_MB);
1655 }
1656
1657 if (DiskEntry->DriverName.Length > 0)
1658 {
1659 sprintf(LineBuffer,
1660 MUIGetString(STRING_HDINFOPARTSELECT),
1661 DiskSize.u.LowPart,
1662 Unit,
1663 DiskEntry->DiskNumber,
1664 DiskEntry->Port,
1665 DiskEntry->Bus,
1666 DiskEntry->Id,
1667 DiskEntry->DriverName.Buffer);
1668 }
1669 else
1670 {
1671 sprintf(LineBuffer,
1672 MUIGetString(STRING_HDDINFOUNK6),
1673 DiskSize.u.LowPart,
1674 Unit,
1675 DiskEntry->DiskNumber,
1676 DiskEntry->Port,
1677 DiskEntry->Bus,
1678 DiskEntry->Id);
1679 }
1680
1681 if (List->Line >= 0 && List->Line <= Height)
1682 {
1683 FillConsoleOutputAttribute(StdOutput,
1684 FOREGROUND_WHITE | BACKGROUND_BLUE,
1685 Width,
1686 coPos,
1687 &Written);
1688
1689 FillConsoleOutputCharacterA(StdOutput,
1690 ' ',
1691 Width,
1692 coPos,
1693 &Written);
1694 }
1695
1696 coPos.X++;
1697 if (List->Line >= 0 && List->Line <= Height)
1698 {
1699 WriteConsoleOutputCharacterA(StdOutput,
1700 LineBuffer,
1701 min((USHORT)strlen(LineBuffer), Width - 2),
1702 coPos,
1703 &Written);
1704 }
1705
1706 List->Line++;
1707
1708 /* Print separator line */
1709 PrintEmptyLine(List);
1710
1711 /* Print partition lines*/
1712 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1713 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1714 {
1715 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1716
1717 PrintPartitionData(List,
1718 DiskEntry,
1719 PrimaryPartEntry);
1720
1721 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1722 {
1723 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1724 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1725 {
1726 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1727
1728 PrintPartitionData(List,
1729 DiskEntry,
1730 LogicalPartEntry);
1731
1732 LogicalEntry = LogicalEntry->Flink;
1733 }
1734 }
1735
1736 PrimaryEntry = PrimaryEntry->Flink;
1737 }
1738
1739 /* Print separator line */
1740 PrintEmptyLine(List);
1741 }
1742
1743
1744 VOID
1745 DrawPartitionList(
1746 PPARTLIST List)
1747 {
1748 PLIST_ENTRY Entry, Entry2;
1749 PDISKENTRY DiskEntry;
1750 PPARTENTRY PartEntry = NULL;
1751 COORD coPos;
1752 DWORD Written;
1753 SHORT i;
1754 SHORT CurrentDiskLine;
1755 SHORT CurrentPartLine;
1756 SHORT LastLine;
1757 BOOL CurrentPartLineFound = FALSE;
1758 BOOL CurrentDiskLineFound = FALSE;
1759
1760 /* Calculate the line of the current disk and partition */
1761 CurrentDiskLine = 0;
1762 CurrentPartLine = 0;
1763 LastLine = 0;
1764
1765 Entry = List->DiskListHead.Flink;
1766 while (Entry != &List->DiskListHead)
1767 {
1768 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1769
1770 LastLine += 2;
1771 if (CurrentPartLineFound == FALSE)
1772 {
1773 CurrentPartLine += 2;
1774 }
1775
1776 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1777 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1778 {
1779 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1780 if (PartEntry == List->CurrentPartition)
1781 {
1782 CurrentPartLineFound = TRUE;
1783 }
1784
1785 Entry2 = Entry2->Flink;
1786 if (CurrentPartLineFound == FALSE)
1787 {
1788 CurrentPartLine++;
1789 }
1790
1791 LastLine++;
1792 }
1793
1794 if (DiskEntry == List->CurrentDisk)
1795 {
1796 CurrentDiskLineFound = TRUE;
1797 }
1798
1799 Entry = Entry->Flink;
1800 if (Entry != &List->DiskListHead)
1801 {
1802 if (CurrentDiskLineFound == FALSE)
1803 {
1804 CurrentPartLine ++;
1805 CurrentDiskLine = CurrentPartLine;
1806 }
1807
1808 LastLine++;
1809 }
1810 else
1811 {
1812 LastLine--;
1813 }
1814 }
1815
1816 /* If it possible, make the disk name visible */
1817 if (CurrentPartLine < List->Offset)
1818 {
1819 List->Offset = CurrentPartLine;
1820 }
1821 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1822 {
1823 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1824 }
1825
1826 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1827 {
1828 List->Offset = CurrentDiskLine;
1829 }
1830
1831 /* draw upper left corner */
1832 coPos.X = List->Left;
1833 coPos.Y = List->Top;
1834 FillConsoleOutputCharacterA(StdOutput,
1835 0xDA, // '+',
1836 1,
1837 coPos,
1838 &Written);
1839
1840 /* draw upper edge */
1841 coPos.X = List->Left + 1;
1842 coPos.Y = List->Top;
1843 if (List->Offset == 0)
1844 {
1845 FillConsoleOutputCharacterA(StdOutput,
1846 0xC4, // '-',
1847 List->Right - List->Left - 1,
1848 coPos,
1849 &Written);
1850 }
1851 else
1852 {
1853 FillConsoleOutputCharacterA(StdOutput,
1854 0xC4, // '-',
1855 List->Right - List->Left - 5,
1856 coPos,
1857 &Written);
1858 coPos.X = List->Right - 5;
1859 WriteConsoleOutputCharacterA(StdOutput,
1860 "(\x18)", // "(up)"
1861 3,
1862 coPos,
1863 &Written);
1864 coPos.X = List->Right - 2;
1865 FillConsoleOutputCharacterA(StdOutput,
1866 0xC4, // '-',
1867 2,
1868 coPos,
1869 &Written);
1870 }
1871
1872 /* draw upper right corner */
1873 coPos.X = List->Right;
1874 coPos.Y = List->Top;
1875 FillConsoleOutputCharacterA(StdOutput,
1876 0xBF, // '+',
1877 1,
1878 coPos,
1879 &Written);
1880
1881 /* draw left and right edge */
1882 for (i = List->Top + 1; i < List->Bottom; i++)
1883 {
1884 coPos.X = List->Left;
1885 coPos.Y = i;
1886 FillConsoleOutputCharacterA(StdOutput,
1887 0xB3, // '|',
1888 1,
1889 coPos,
1890 &Written);
1891
1892 coPos.X = List->Right;
1893 FillConsoleOutputCharacterA(StdOutput,
1894 0xB3, //'|',
1895 1,
1896 coPos,
1897 &Written);
1898 }
1899
1900 /* draw lower left corner */
1901 coPos.X = List->Left;
1902 coPos.Y = List->Bottom;
1903 FillConsoleOutputCharacterA(StdOutput,
1904 0xC0, // '+',
1905 1,
1906 coPos,
1907 &Written);
1908
1909 /* draw lower edge */
1910 coPos.X = List->Left + 1;
1911 coPos.Y = List->Bottom;
1912 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1913 {
1914 FillConsoleOutputCharacterA(StdOutput,
1915 0xC4, // '-',
1916 List->Right - List->Left - 1,
1917 coPos,
1918 &Written);
1919 }
1920 else
1921 {
1922 FillConsoleOutputCharacterA(StdOutput,
1923 0xC4, // '-',
1924 List->Right - List->Left - 5,
1925 coPos,
1926 &Written);
1927 coPos.X = List->Right - 5;
1928 WriteConsoleOutputCharacterA(StdOutput,
1929 "(\x19)", // "(down)"
1930 3,
1931 coPos,
1932 &Written);
1933 coPos.X = List->Right - 2;
1934 FillConsoleOutputCharacterA(StdOutput,
1935 0xC4, // '-',
1936 2,
1937 coPos,
1938 &Written);
1939 }
1940
1941 /* draw lower right corner */
1942 coPos.X = List->Right;
1943 coPos.Y = List->Bottom;
1944 FillConsoleOutputCharacterA(StdOutput,
1945 0xD9, // '+',
1946 1,
1947 coPos,
1948 &Written);
1949
1950 /* print list entries */
1951 List->Line = - List->Offset;
1952
1953 Entry = List->DiskListHead.Flink;
1954 while (Entry != &List->DiskListHead)
1955 {
1956 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1957
1958 /* Print disk entry */
1959 PrintDiskData(List,
1960 DiskEntry);
1961
1962 Entry = Entry->Flink;
1963 }
1964 }
1965
1966
1967 DWORD
1968 SelectPartition(
1969 PPARTLIST List,
1970 ULONG DiskNumber,
1971 ULONG PartitionNumber)
1972 {
1973 PDISKENTRY DiskEntry;
1974 PPARTENTRY PartEntry;
1975 PLIST_ENTRY Entry1;
1976 PLIST_ENTRY Entry2;
1977
1978 /* Check for empty disks */
1979 if (IsListEmpty(&List->DiskListHead))
1980 return FALSE;
1981
1982 /* Check for first usable entry on next disk */
1983 Entry1 = List->CurrentDisk->ListEntry.Flink;
1984 while (Entry1 != &List->DiskListHead)
1985 {
1986 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1987
1988 if (DiskEntry->DiskNumber == DiskNumber)
1989 {
1990 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1991 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1992 {
1993 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1994
1995 if (PartEntry->PartitionNumber == PartitionNumber)
1996 {
1997 List->CurrentDisk = DiskEntry;
1998 List->CurrentPartition = PartEntry;
1999 DrawPartitionList(List);
2000 return TRUE;
2001 }
2002
2003 Entry2 = Entry2->Flink;
2004 }
2005
2006 return FALSE;
2007 }
2008
2009 Entry1 = Entry1->Flink;
2010 }
2011
2012 return FALSE;
2013 }
2014
2015
2016 BOOL
2017 ScrollDownPartitionList(
2018 PPARTLIST List)
2019 {
2020 PLIST_ENTRY DiskListEntry;
2021 PLIST_ENTRY PartListEntry;
2022 PDISKENTRY DiskEntry;
2023 PPARTENTRY PartEntry;
2024
2025 /* Fail, if no disks are available */
2026 if (IsListEmpty(&List->DiskListHead))
2027 return FALSE;
2028
2029 /* Check for next usable entry on current disk */
2030 if (List->CurrentPartition != NULL)
2031 {
2032 if (List->CurrentPartition->LogicalPartition)
2033 {
2034 /* Logical partition */
2035
2036 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2037 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2038 {
2039 /* Next logical partition */
2040 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2041
2042 List->CurrentPartition = PartEntry;
2043 return TRUE;
2044 }
2045 else
2046 {
2047 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2048 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2049 {
2050 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2051
2052 List->CurrentPartition = PartEntry;
2053 return TRUE;
2054 }
2055 }
2056 }
2057 else
2058 {
2059 /* Primary or extended partition */
2060
2061 if (List->CurrentPartition->IsPartitioned == TRUE &&
2062 IsContainerPartition(List->CurrentPartition->PartitionType))
2063 {
2064 /* First logical partition */
2065 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2066 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2067 {
2068 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2069
2070 List->CurrentPartition = PartEntry;
2071 return TRUE;
2072 }
2073 }
2074 else
2075 {
2076 /* Next primary partition */
2077 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2078 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2079 {
2080 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2081
2082 List->CurrentPartition = PartEntry;
2083 return TRUE;
2084 }
2085 }
2086 }
2087 }
2088
2089 /* Search for the first partition entry on the next disk */
2090 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2091 while (DiskListEntry != &List->DiskListHead)
2092 {
2093 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2094
2095 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2096 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2097 {
2098 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2099
2100 List->CurrentDisk = DiskEntry;
2101 List->CurrentPartition = PartEntry;
2102 return TRUE;
2103 }
2104
2105 DiskListEntry = DiskListEntry->Flink;
2106 }
2107
2108 return FALSE;
2109 }
2110
2111
2112 BOOL
2113 ScrollUpPartitionList(
2114 PPARTLIST List)
2115 {
2116 PLIST_ENTRY DiskListEntry;
2117 PLIST_ENTRY PartListEntry;
2118 PDISKENTRY DiskEntry;
2119 PPARTENTRY PartEntry;
2120
2121 /* Fail, if no disks are available */
2122 if (IsListEmpty(&List->DiskListHead))
2123 return FALSE;
2124
2125 /* Check for previous usable entry on current disk */
2126 if (List->CurrentPartition != NULL)
2127 {
2128 if (List->CurrentPartition->LogicalPartition)
2129 {
2130 /* Logical partition */
2131 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2132 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2133 {
2134 /* Previous logical partition */
2135 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2136 }
2137 else
2138 {
2139 /* Extended partition*/
2140 PartEntry = List->CurrentDisk->ExtendedPartition;
2141 }
2142
2143 List->CurrentPartition = PartEntry;
2144 return TRUE;
2145 }
2146 else
2147 {
2148 /* Primary or extended partition */
2149
2150 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2151 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2152 {
2153 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2154
2155 if (PartEntry->IsPartitioned == TRUE &&
2156 IsContainerPartition(PartEntry->PartitionType))
2157 {
2158 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2159 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2160 }
2161
2162 List->CurrentPartition = PartEntry;
2163 return TRUE;
2164 }
2165
2166 }
2167 }
2168
2169 /* Search for the last partition entry on the previous disk */
2170 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2171 while (DiskListEntry != &List->DiskListHead)
2172 {
2173 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2174
2175 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2176 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2177 {
2178 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2179
2180 if (PartEntry->IsPartitioned == TRUE &&
2181 IsContainerPartition(PartEntry->PartitionType))
2182 {
2183 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2184 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2185 {
2186 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2187
2188 List->CurrentDisk = DiskEntry;
2189 List->CurrentPartition = PartEntry;
2190 return TRUE;
2191 }
2192 }
2193 else
2194 {
2195 List->CurrentDisk = DiskEntry;
2196 List->CurrentPartition = PartEntry;
2197 return TRUE;
2198 }
2199 }
2200
2201 DiskListEntry = DiskListEntry->Blink;
2202 }
2203
2204 return FALSE;
2205 }
2206
2207
2208 static
2209 BOOLEAN
2210 IsEmptyLayoutEntry(
2211 PPARTITION_INFORMATION PartitionInfo)
2212 {
2213 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2214 PartitionInfo->PartitionLength.QuadPart == 0)
2215 // PartitionInfo->PartitionType == 0)
2216 return TRUE;
2217
2218 return FALSE;
2219 }
2220
2221
2222 static
2223 BOOLEAN
2224 IsSamePrimaryLayoutEntry(
2225 IN PPARTITION_INFORMATION PartitionInfo,
2226 IN PDISKENTRY DiskEntry,
2227 IN PPARTENTRY PartEntry)
2228 {
2229 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2230 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2231 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2232 // PartitionInfo->PartitionType == PartEntry->PartitionType
2233 return TRUE;
2234
2235 return FALSE;
2236 }
2237
2238
2239 static
2240 VOID
2241 UpdateDiskLayout(
2242 IN PDISKENTRY DiskEntry)
2243 {
2244 PPARTITION_INFORMATION PartitionInfo;
2245 PLIST_ENTRY ListEntry;
2246 PPARTENTRY PartEntry;
2247 ULONG Index = 0;
2248 ULONG PartitionNumber = 1;
2249
2250 DPRINT1("UpdateDiskLayout()\n");
2251
2252 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2253 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2254 {
2255 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2256
2257 if (PartEntry->IsPartitioned == TRUE)
2258 {
2259 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2260
2261 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2262 {
2263 DPRINT1("Updating partition entry %lu\n", Index);
2264 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2265 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2266 PartitionInfo->HiddenSectors = 0;
2267 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2268 PartitionInfo->PartitionType = PartEntry->PartitionType;
2269 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2270 PartitionInfo->RecognizedPartition = FALSE;
2271 PartitionInfo->RewritePartition = TRUE;
2272
2273 PartEntry->PartitionNumber = PartitionNumber;
2274 PartEntry->PartitionIndex = Index;
2275
2276 PartitionNumber++;
2277 }
2278 else if (!IsEmptyLayoutEntry(PartitionInfo))
2279 {
2280 PartitionNumber++;
2281 }
2282
2283 Index++;
2284 }
2285
2286 ListEntry = ListEntry->Flink;
2287 }
2288
2289 for (;Index < 4; Index++)
2290 {
2291 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2292
2293 if (!IsEmptyLayoutEntry(PartitionInfo))
2294 {
2295 DPRINT1("Wiping partition entry %lu\n", Index);
2296 PartitionInfo->StartingOffset.QuadPart = 0;
2297 PartitionInfo->PartitionLength.QuadPart = 0;
2298 PartitionInfo->HiddenSectors = 0;
2299 PartitionInfo->PartitionNumber = 0;
2300 PartitionInfo->PartitionType = 0;
2301 PartitionInfo->BootIndicator = FALSE;
2302 PartitionInfo->RecognizedPartition = FALSE;
2303 PartitionInfo->RewritePartition = TRUE;
2304 }
2305 }
2306
2307 #ifdef DUMP_PARTITION_TABLE
2308 DumpPartitionTable(DiskEntry);
2309 #endif
2310 }
2311
2312
2313 static
2314 PPARTENTRY
2315 GetPrevUnpartitionedEntry(
2316 PDISKENTRY DiskEntry,
2317 PPARTENTRY PartEntry)
2318 {
2319 PPARTENTRY PrevPartEntry;
2320
2321 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2322 {
2323 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2324 PARTENTRY,
2325 ListEntry);
2326 if (PrevPartEntry->IsPartitioned == FALSE)
2327 return PrevPartEntry;
2328 }
2329
2330 return NULL;
2331 }
2332
2333
2334 static
2335 PPARTENTRY
2336 GetNextUnpartitionedEntry(
2337 PDISKENTRY DiskEntry,
2338 PPARTENTRY PartEntry)
2339 {
2340 PPARTENTRY NextPartEntry;
2341
2342 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2343 {
2344 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2345 PARTENTRY,
2346 ListEntry);
2347 if (NextPartEntry->IsPartitioned == FALSE)
2348 return NextPartEntry;
2349 }
2350
2351 return NULL;
2352 }
2353
2354
2355 VOID
2356 CreatePrimaryPartition(
2357 PPARTLIST List,
2358 ULONGLONG SectorCount,
2359 BOOLEAN AutoCreate)
2360 {
2361 PDISKENTRY DiskEntry;
2362 PPARTENTRY PartEntry;
2363 PPARTENTRY NewPartEntry;
2364
2365 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2366
2367 if (List == NULL ||
2368 List->CurrentDisk == NULL ||
2369 List->CurrentPartition == NULL ||
2370 List->CurrentPartition->IsPartitioned == TRUE)
2371 {
2372 return;
2373 }
2374
2375 DiskEntry = List->CurrentDisk;
2376 PartEntry = List->CurrentPartition;
2377
2378 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2379
2380 if (AutoCreate == TRUE ||
2381 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2382 {
2383 DPRINT1("Convert existing partition entry\n");
2384 /* Convert current entry to 'new (unformatted)' */
2385 PartEntry->IsPartitioned = TRUE;
2386 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2387 PartEntry->FormatState = Unformatted;
2388 PartEntry->AutoCreate = AutoCreate;
2389 PartEntry->New = TRUE;
2390 PartEntry->BootIndicator = FALSE;
2391
2392 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2393 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2394 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2395 }
2396 else
2397 {
2398 DPRINT1("Add new partition entry\n");
2399
2400 /* Insert and initialize a new partition entry */
2401 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2402 HEAP_ZERO_MEMORY,
2403 sizeof(PARTENTRY));
2404 if (NewPartEntry == NULL)
2405 return;
2406
2407 /* Insert the new entry into the list */
2408 InsertTailList(&PartEntry->ListEntry,
2409 &NewPartEntry->ListEntry);
2410
2411 NewPartEntry->DiskEntry = DiskEntry;
2412
2413 NewPartEntry->IsPartitioned = TRUE;
2414 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2415 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2416 NewPartEntry->StartSector.QuadPart;
2417 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2418
2419 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2420 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2421 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2422
2423 NewPartEntry->New = TRUE;
2424 NewPartEntry->FormatState = Unformatted;
2425 NewPartEntry->BootIndicator = FALSE;
2426
2427 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2428 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2429 }
2430
2431 UpdateDiskLayout(DiskEntry);
2432
2433 DiskEntry->Dirty = TRUE;
2434
2435 UpdatePartitionNumbers(DiskEntry);
2436
2437 AssignDriveLetters(List);
2438 }
2439
2440
2441 static
2442 VOID
2443 AddLogicalDiskSpace(
2444 PDISKENTRY DiskEntry)
2445 {
2446 PPARTENTRY NewPartEntry;
2447
2448 DPRINT1("AddLogicalDiskSpace()\n");
2449
2450 /* Create a partition table entry that represents the empty space in the container partition */
2451 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2452 HEAP_ZERO_MEMORY,
2453 sizeof(PARTENTRY));
2454 if (NewPartEntry == NULL)
2455 return;
2456
2457 NewPartEntry->DiskEntry = DiskEntry;
2458 NewPartEntry->LogicalPartition = TRUE;
2459
2460 NewPartEntry->IsPartitioned = FALSE;
2461 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorsPerTrack;
2462 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorsPerTrack;
2463
2464 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2465 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2466 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2467
2468 NewPartEntry->FormatState = Unformatted;
2469
2470 InsertTailList(&DiskEntry->LogicalPartListHead,
2471 &NewPartEntry->ListEntry);
2472 }
2473
2474
2475 VOID
2476 CreateExtendedPartition(
2477 PPARTLIST List,
2478 ULONGLONG SectorCount)
2479 {
2480 PDISKENTRY DiskEntry;
2481 PPARTENTRY PartEntry;
2482 PPARTENTRY NewPartEntry;
2483
2484 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2485
2486 if (List == NULL ||
2487 List->CurrentDisk == NULL ||
2488 List->CurrentPartition == NULL ||
2489 List->CurrentPartition->IsPartitioned == TRUE)
2490 {
2491 return;
2492 }
2493
2494 DiskEntry = List->CurrentDisk;
2495 PartEntry = List->CurrentPartition;
2496
2497 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2498
2499 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2500 {
2501 DPRINT1("Convert existing partition entry\n");
2502 /* Convert current entry to 'new (unformatted)' */
2503 PartEntry->IsPartitioned = TRUE;
2504 PartEntry->FormatState = Formatted;
2505 PartEntry->AutoCreate = FALSE;
2506 PartEntry->New = FALSE;
2507 PartEntry->BootIndicator = FALSE;
2508
2509 if (PartEntry->StartSector.QuadPart < 1450560)
2510 {
2511 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2512 PartEntry->PartitionType = PARTITION_EXTENDED;
2513 }
2514 else
2515 {
2516 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2517 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2518 }
2519
2520 DiskEntry->ExtendedPartition = PartEntry;
2521
2522 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2523 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2524 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2525 }
2526 else
2527 {
2528 DPRINT1("Add new partition entry\n");
2529
2530 /* Insert and initialize a new partition entry */
2531 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2532 HEAP_ZERO_MEMORY,
2533 sizeof(PARTENTRY));
2534 if (NewPartEntry == NULL)
2535 return;
2536
2537 /* Insert the new entry into the list */
2538 InsertTailList(&PartEntry->ListEntry,
2539 &NewPartEntry->ListEntry);
2540
2541 NewPartEntry->DiskEntry = DiskEntry;
2542
2543 NewPartEntry->IsPartitioned = TRUE;
2544 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2545 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2546 NewPartEntry->StartSector.QuadPart;
2547
2548 NewPartEntry->New = FALSE;
2549 NewPartEntry->FormatState = Formatted;
2550 NewPartEntry->BootIndicator = FALSE;
2551
2552 if (NewPartEntry->StartSector.QuadPart < 1450560)
2553 {
2554 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2555 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2556 }
2557 else
2558 {
2559 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2560 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2561 }
2562
2563 DiskEntry->ExtendedPartition = NewPartEntry;
2564
2565 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2566 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2567
2568 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2569 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2570 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2571 }
2572
2573 AddLogicalDiskSpace(DiskEntry);
2574
2575 UpdateDiskLayout(DiskEntry);
2576
2577 DiskEntry->Dirty = TRUE;
2578
2579 UpdatePartitionNumbers(DiskEntry);
2580
2581 AssignDriveLetters(List);
2582 }
2583
2584
2585 VOID
2586 CreateLogicalPartition(
2587 PPARTLIST List,
2588 ULONGLONG SectorCount)
2589 {
2590 // PDISKENTRY DiskEntry;
2591 PPARTENTRY PartEntry;
2592 // PPARTENTRY NewPartEntry;
2593
2594 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2595
2596 if (List == NULL ||
2597 List->CurrentDisk == NULL ||
2598 List->CurrentPartition == NULL ||
2599 List->CurrentPartition->IsPartitioned == TRUE)
2600 {
2601 return;
2602 }
2603
2604 // DiskEntry = List->CurrentDisk;
2605 PartEntry = List->CurrentPartition;
2606
2607 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2608 }
2609
2610
2611 VOID
2612 DeleteCurrentPartition(
2613 PPARTLIST List)
2614 {
2615 PDISKENTRY DiskEntry;
2616 PPARTENTRY PartEntry;
2617 PPARTENTRY PrevPartEntry;
2618 PPARTENTRY NextPartEntry;
2619 PPARTENTRY LogicalPartEntry;
2620 PLIST_ENTRY Entry;
2621
2622 if (List == NULL ||
2623 List->CurrentDisk == NULL ||
2624 List->CurrentPartition == NULL ||
2625 List->CurrentPartition->IsPartitioned == FALSE)
2626 {
2627 return;
2628 }
2629
2630 DiskEntry = List->CurrentDisk;
2631 PartEntry = List->CurrentPartition;
2632
2633 /* Delete all logical partiton entries if an extended partition will be deleted */
2634 if (DiskEntry->ExtendedPartition == PartEntry)
2635 {
2636 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2637 {
2638 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2639 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2640
2641 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2642 }
2643
2644 DiskEntry->ExtendedPartition = NULL;
2645 }
2646
2647 /* Adjust unpartitioned disk space entries */
2648
2649 /* Get pointer to previous and next unpartitioned entries */
2650 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2651 PartEntry);
2652
2653 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2654 PartEntry);
2655
2656 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2657 {
2658 /* Merge previous, current and next unpartitioned entry */
2659
2660 /* Adjust the previous entries length */
2661 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2662
2663 /* Remove the current entry */
2664 RemoveEntryList(&PartEntry->ListEntry);
2665 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2666
2667 /* Remove the next entry */
2668 RemoveEntryList (&NextPartEntry->ListEntry);
2669 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2670
2671 /* Update current partition */
2672 List->CurrentPartition = PrevPartEntry;
2673 }
2674 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2675 {
2676 /* Merge current and previous unpartitioned entry */
2677
2678 /* Adjust the previous entries length */
2679 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2680
2681 /* Remove the current entry */
2682 RemoveEntryList(&PartEntry->ListEntry);
2683 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2684
2685 /* Update current partition */
2686 List->CurrentPartition = PrevPartEntry;
2687 }
2688 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2689 {
2690 /* Merge current and next unpartitioned entry */
2691
2692 /* Adjust the next entries offset and length */
2693 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2694 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2695
2696 /* Remove the current entry */
2697 RemoveEntryList(&PartEntry->ListEntry);
2698 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2699
2700 /* Update current partition */
2701 List->CurrentPartition = NextPartEntry;
2702 }
2703 else
2704 {
2705 /* Nothing to merge but change current entry */
2706 PartEntry->IsPartitioned = FALSE;
2707 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2708 PartEntry->FormatState = Unformatted;
2709 PartEntry->DriveLetter = 0;
2710 }
2711
2712 UpdateDiskLayout(DiskEntry);
2713
2714 DiskEntry->Dirty = TRUE;
2715
2716 UpdatePartitionNumbers(DiskEntry);
2717
2718 AssignDriveLetters(List);
2719 }
2720
2721
2722 VOID
2723 CheckActiveBootPartition(
2724 PPARTLIST List)
2725 {
2726 PDISKENTRY DiskEntry;
2727 PPARTENTRY PartEntry;
2728 PLIST_ENTRY ListEntry;
2729
2730 /* Check for empty disk list */
2731 if (IsListEmpty (&List->DiskListHead))
2732 {
2733 List->ActiveBootDisk = NULL;
2734 List->ActiveBootPartition = NULL;
2735 return;
2736 }
2737
2738 #if 0
2739 if (List->ActiveBootDisk != NULL &&
2740 List->ActiveBootPartition != NULL)
2741 {
2742 /* We already have an active boot partition */
2743 return;
2744 }
2745 #endif
2746
2747 /* Choose the currently selected disk */
2748 DiskEntry = List->CurrentDisk;
2749
2750 /* Check for empty partition list */
2751 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2752 {
2753 List->ActiveBootDisk = NULL;
2754 List->ActiveBootPartition = NULL;
2755 return;
2756 }
2757
2758 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2759 PARTENTRY,
2760 ListEntry);
2761
2762 /* Set active boot partition */
2763 if ((DiskEntry->NewDisk == TRUE) ||
2764 (PartEntry->BootIndicator == FALSE))
2765 {
2766 PartEntry->BootIndicator = TRUE;
2767 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2768 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2769 DiskEntry->Dirty = TRUE;
2770
2771 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2772 List->ActiveBootDisk = DiskEntry;
2773 List->ActiveBootPartition = PartEntry;
2774
2775 return;
2776 }
2777
2778 /* Disk is not new, scan all partitions to find a bootable one */
2779 List->ActiveBootDisk = NULL;
2780 List->ActiveBootPartition = NULL;
2781
2782 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2783 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2784 {
2785 PartEntry = CONTAINING_RECORD(ListEntry,
2786 PARTENTRY,
2787 ListEntry);
2788
2789 /* Check if it is partitioned */
2790 if (PartEntry->IsPartitioned)
2791 {
2792 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2793 PartEntry->BootIndicator)
2794 {
2795 /* Yes, we found it */
2796 List->ActiveBootDisk = DiskEntry;
2797 List->ActiveBootPartition = PartEntry;
2798
2799 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2800 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2801 break;
2802 }
2803 }
2804
2805 /* Go to the next one */
2806 ListEntry = ListEntry->Flink;
2807 }
2808 }
2809
2810
2811 BOOLEAN
2812 CheckForLinuxFdiskPartitions(
2813 PPARTLIST List)
2814 {
2815 #if 0
2816 PDISKENTRY DiskEntry;
2817 PPARTENTRY PartEntry;
2818 PLIST_ENTRY Entry1;
2819 PLIST_ENTRY Entry2;
2820 ULONG PartitionCount;
2821 ULONG i;
2822
2823 Entry1 = List->DiskListHead.Flink;
2824 while (Entry1 != &List->DiskListHead)
2825 {
2826 DiskEntry = CONTAINING_RECORD(Entry1,
2827 DISKENTRY,
2828 ListEntry);
2829
2830 Entry2 = DiskEntry->PartListHead.Flink;
2831 while (Entry2 != &DiskEntry->PartListHead)
2832 {
2833 PartEntry = CONTAINING_RECORD(Entry2,
2834 PARTENTRY,
2835 ListEntry);
2836
2837 if (PartEntry->Unpartitioned == FALSE)
2838 {
2839 PartitionCount = 0;
2840
2841 for (i = 0; i < 4; i++)
2842 {
2843 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2844 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2845 {
2846 PartitionCount++;
2847 }
2848 }
2849
2850 if (PartitionCount > 1)
2851 {
2852 return TRUE;
2853 }
2854 }
2855
2856 Entry2 = Entry2->Flink;
2857 }
2858
2859 Entry1 = Entry1->Flink;
2860 }
2861 #endif
2862
2863 return FALSE;
2864 }
2865
2866
2867 static
2868 NTSTATUS
2869 WritePartitons(
2870 IN PPARTLIST List,
2871 IN PDISKENTRY DiskEntry)
2872 {
2873 WCHAR DstPath[MAX_PATH];
2874 OBJECT_ATTRIBUTES ObjectAttributes;
2875 IO_STATUS_BLOCK Iosb;
2876 UNICODE_STRING Name;
2877 ULONG BufferSize;
2878 HANDLE FileHandle = NULL;
2879 NTSTATUS Status;
2880
2881 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2882
2883 swprintf(DstPath,
2884 L"\\Device\\Harddisk%d\\Partition0",
2885 DiskEntry->DiskNumber);
2886 RtlInitUnicodeString(&Name,
2887 DstPath);
2888 InitializeObjectAttributes(&ObjectAttributes,
2889 &Name,
2890 0,
2891 NULL,
2892 NULL);
2893
2894 Status = NtOpenFile(&FileHandle,
2895 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2896 &ObjectAttributes,
2897 &Iosb,
2898 0,
2899 FILE_SYNCHRONOUS_IO_NONALERT);
2900 if (!NT_SUCCESS(Status))
2901 {
2902 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2903 return Status;
2904 }
2905
2906 #ifdef DUMP_PARTITION_TABLE
2907 DumpPartitionTable(DiskEntry);
2908 #endif
2909
2910 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2911 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2912 Status = NtDeviceIoControlFile(FileHandle,
2913 NULL,
2914 NULL,
2915 NULL,
2916 &Iosb,
2917 IOCTL_DISK_SET_DRIVE_LAYOUT,
2918 DiskEntry->LayoutBuffer,
2919 BufferSize,
2920 NULL,
2921 0);
2922 if (!NT_SUCCESS(Status))
2923 {
2924 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2925 }
2926
2927 if (FileHandle != NULL)
2928 NtClose(FileHandle);
2929
2930 return Status;
2931 }
2932
2933
2934 BOOLEAN
2935 WritePartitionsToDisk(
2936 PPARTLIST List)
2937 {
2938 PLIST_ENTRY Entry;
2939 PDISKENTRY DiskEntry;
2940
2941 if (List == NULL)
2942 return TRUE;
2943
2944 Entry = List->DiskListHead.Flink;
2945 while (Entry != &List->DiskListHead)
2946 {
2947 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2948
2949 if (DiskEntry->Dirty == TRUE)
2950 {
2951 WritePartitons(List, DiskEntry);
2952 }
2953
2954 Entry = Entry->Flink;
2955 }
2956
2957 return TRUE;
2958 }
2959
2960
2961 BOOL
2962 SetMountedDeviceValues(
2963 PPARTLIST List)
2964 {
2965 PLIST_ENTRY Entry1, Entry2;
2966 PDISKENTRY DiskEntry;
2967 PPARTENTRY PartEntry;
2968 LARGE_INTEGER StartingOffset;
2969
2970 if (List == NULL)
2971 {
2972 return FALSE;
2973 }
2974
2975 Entry1 = List->DiskListHead.Flink;
2976 while (Entry1 != &List->DiskListHead)
2977 {
2978 DiskEntry = CONTAINING_RECORD(Entry1,
2979 DISKENTRY,
2980 ListEntry);
2981
2982 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2983 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2984 {
2985 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2986 if (PartEntry->IsPartitioned)
2987 {
2988 if (PartEntry->DriveLetter)
2989 {
2990 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2991 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
2992 DiskEntry->LayoutBuffer->Signature,
2993 StartingOffset))
2994 {
2995 return FALSE;
2996 }
2997 }
2998 }
2999
3000 Entry2 = Entry2->Flink;
3001 }
3002
3003 Entry1 = Entry1->Flink;
3004 }
3005
3006 return TRUE;
3007 }
3008
3009
3010 static
3011 ULONG
3012 GetPrimaryPartitionCount(
3013 IN PDISKENTRY DiskEntry)
3014 {
3015 PLIST_ENTRY Entry;
3016 PPARTENTRY PartEntry;
3017 UINT nCount = 0;
3018
3019 Entry = DiskEntry->PrimaryPartListHead.Flink;
3020 while (Entry != &DiskEntry->PrimaryPartListHead)
3021 {
3022 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3023 if (PartEntry->IsPartitioned == TRUE)
3024 nCount++;
3025
3026 Entry = Entry->Flink;
3027 }
3028
3029 return nCount;
3030 }
3031
3032
3033 ULONG
3034 PrimaryPartitionCreationChecks(
3035 IN PPARTLIST List)
3036 {
3037 PDISKENTRY DiskEntry;
3038 PPARTENTRY PartEntry;
3039
3040 DiskEntry = List->CurrentDisk;
3041 PartEntry = List->CurrentPartition;
3042
3043 /* Fail if partition is already in use */
3044 if (PartEntry->IsPartitioned == TRUE)
3045 return ERROR_NEW_PARTITION;
3046
3047 /* Fail if there are more than 4 partitions in the list */
3048 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3049 return ERROR_PARTITION_TABLE_FULL;
3050
3051 return ERROR_SUCCESS;
3052 }
3053
3054
3055 ULONG
3056 ExtendedPartitionCreationChecks(
3057 IN PPARTLIST List)
3058 {
3059 PDISKENTRY DiskEntry;
3060 PPARTENTRY PartEntry;
3061
3062 DiskEntry = List->CurrentDisk;
3063 PartEntry = List->CurrentPartition;
3064
3065 /* Fail if partition is already in use */
3066 if (PartEntry->IsPartitioned == TRUE)
3067 return ERROR_NEW_PARTITION;
3068
3069 /* Fail if there are more than 4 partitions in the list */
3070 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3071 return ERROR_PARTITION_TABLE_FULL;
3072
3073 /* Fail if there is another extended partition in the list */
3074 if (DiskEntry->ExtendedPartition != NULL)
3075 return ERROR_ONLY_ONE_EXTENDED;
3076
3077 return ERROR_SUCCESS;
3078 }
3079
3080
3081 ULONG
3082 LogicalPartitionCreationChecks(
3083 IN PPARTLIST List)
3084 {
3085 // PDISKENTRY DiskEntry;
3086 PPARTENTRY PartEntry;
3087
3088 // DiskEntry = List->CurrentDisk;
3089 PartEntry = List->CurrentPartition;
3090
3091 /* Fail if partition is already in use */
3092 if (PartEntry->IsPartitioned == TRUE)
3093 return ERROR_NEW_PARTITION;
3094
3095 return ERROR_SUCCESS;
3096 }
3097
3098 /* EOF */