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