* Sync up to trunk head (r65120).
[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 (List->CurrentPartition->IsPartitioned == TRUE &&
2058 IsContainerPartition(List->CurrentPartition->PartitionType))
2059 {
2060 /* First logical partition */
2061 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2062 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2063 {
2064 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2065
2066 List->CurrentPartition = PartEntry;
2067 return TRUE;
2068 }
2069 }
2070 else
2071 {
2072 /* Next primary partition */
2073 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2074 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2075 {
2076 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2077
2078 List->CurrentPartition = PartEntry;
2079 return TRUE;
2080 }
2081 }
2082 }
2083 }
2084
2085 /* Search for the first partition entry on the next disk */
2086 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2087 while (DiskListEntry != &List->DiskListHead)
2088 {
2089 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2090
2091 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2092 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2093 {
2094 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2095
2096 List->CurrentDisk = DiskEntry;
2097 List->CurrentPartition = PartEntry;
2098 return TRUE;
2099 }
2100
2101 DiskListEntry = DiskListEntry->Flink;
2102 }
2103
2104 return FALSE;
2105 }
2106
2107
2108 BOOL
2109 ScrollUpPartitionList(
2110 PPARTLIST List)
2111 {
2112 PLIST_ENTRY DiskListEntry;
2113 PLIST_ENTRY PartListEntry;
2114 PDISKENTRY DiskEntry;
2115 PPARTENTRY PartEntry;
2116
2117 /* Fail, if no disks are available */
2118 if (IsListEmpty(&List->DiskListHead))
2119 return FALSE;
2120
2121 /* Check for previous usable entry on current disk */
2122 if (List->CurrentPartition != NULL)
2123 {
2124 if (List->CurrentPartition->LogicalPartition)
2125 {
2126 /* Logical partition */
2127 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2128 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2129 {
2130 /* Previous logical partition */
2131 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2132 }
2133 else
2134 {
2135 /* Extended partition*/
2136 PartEntry = List->CurrentDisk->ExtendedPartition;
2137 }
2138
2139 List->CurrentPartition = PartEntry;
2140 return TRUE;
2141 }
2142 else
2143 {
2144 /* Primary or extended partition */
2145
2146 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2147 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2148 {
2149 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2150
2151 if (PartEntry->IsPartitioned == TRUE &&
2152 IsContainerPartition(PartEntry->PartitionType))
2153 {
2154 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2155 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2156 }
2157
2158 List->CurrentPartition = PartEntry;
2159 return TRUE;
2160 }
2161
2162 }
2163 }
2164
2165 /* Search for the last partition entry on the previous disk */
2166 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2167 while (DiskListEntry != &List->DiskListHead)
2168 {
2169 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2170
2171 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2172 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2173 {
2174 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2175
2176 if (PartEntry->IsPartitioned == TRUE &&
2177 IsContainerPartition(PartEntry->PartitionType))
2178 {
2179 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2180 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2181 {
2182 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2183
2184 List->CurrentDisk = DiskEntry;
2185 List->CurrentPartition = PartEntry;
2186 return TRUE;
2187 }
2188 }
2189 else
2190 {
2191 List->CurrentDisk = DiskEntry;
2192 List->CurrentPartition = PartEntry;
2193 return TRUE;
2194 }
2195 }
2196
2197 DiskListEntry = DiskListEntry->Blink;
2198 }
2199
2200 return FALSE;
2201 }
2202
2203
2204 static
2205 BOOLEAN
2206 IsEmptyLayoutEntry(
2207 PPARTITION_INFORMATION PartitionInfo)
2208 {
2209 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2210 PartitionInfo->PartitionLength.QuadPart == 0)
2211 // PartitionInfo->PartitionType == 0)
2212 return TRUE;
2213
2214 return FALSE;
2215 }
2216
2217
2218 static
2219 BOOLEAN
2220 IsSamePrimaryLayoutEntry(
2221 IN PPARTITION_INFORMATION PartitionInfo,
2222 IN PDISKENTRY DiskEntry,
2223 IN PPARTENTRY PartEntry)
2224 {
2225 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2226 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2227 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2228 // PartitionInfo->PartitionType == PartEntry->PartitionType
2229 return TRUE;
2230
2231 return FALSE;
2232 }
2233
2234
2235 static
2236 VOID
2237 UpdateDiskLayout(
2238 IN PDISKENTRY DiskEntry)
2239 {
2240 PPARTITION_INFORMATION PartitionInfo;
2241 PLIST_ENTRY ListEntry;
2242 PPARTENTRY PartEntry;
2243 ULONG Index = 0;
2244 ULONG PartitionNumber = 1;
2245
2246 DPRINT1("UpdateDiskLayout()\n");
2247
2248 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2249 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2250 {
2251 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2252
2253 if (PartEntry->IsPartitioned == TRUE)
2254 {
2255 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2256
2257 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2258 {
2259 DPRINT1("Updating partition entry %lu\n", Index);
2260 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2261 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2262 PartitionInfo->HiddenSectors = 0;
2263 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2264 PartitionInfo->PartitionType = PartEntry->PartitionType;
2265 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2266 PartitionInfo->RecognizedPartition = FALSE;
2267 PartitionInfo->RewritePartition = TRUE;
2268
2269 PartEntry->PartitionNumber = PartitionNumber;
2270 PartEntry->PartitionIndex = Index;
2271
2272 PartitionNumber++;
2273 }
2274 else if (!IsEmptyLayoutEntry(PartitionInfo))
2275 {
2276 PartitionNumber++;
2277 }
2278
2279 Index++;
2280 }
2281
2282 ListEntry = ListEntry->Flink;
2283 }
2284
2285 for (;Index < 4; Index++)
2286 {
2287 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2288
2289 if (!IsEmptyLayoutEntry(PartitionInfo))
2290 {
2291 DPRINT1("Wiping partition entry %lu\n", Index);
2292 PartitionInfo->StartingOffset.QuadPart = 0;
2293 PartitionInfo->PartitionLength.QuadPart = 0;
2294 PartitionInfo->HiddenSectors = 0;
2295 PartitionInfo->PartitionNumber = 0;
2296 PartitionInfo->PartitionType = 0;
2297 PartitionInfo->BootIndicator = FALSE;
2298 PartitionInfo->RecognizedPartition = FALSE;
2299 PartitionInfo->RewritePartition = TRUE;
2300 }
2301 }
2302
2303 #ifdef DUMP_PARTITION_TABLE
2304 DumpPartitionTable(DiskEntry);
2305 #endif
2306 }
2307
2308
2309 static
2310 PPARTENTRY
2311 GetPrevUnpartitionedEntry(
2312 PDISKENTRY DiskEntry,
2313 PPARTENTRY PartEntry)
2314 {
2315 PPARTENTRY PrevPartEntry;
2316
2317 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2318 {
2319 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2320 PARTENTRY,
2321 ListEntry);
2322 if (PrevPartEntry->IsPartitioned == FALSE)
2323 return PrevPartEntry;
2324 }
2325
2326 return NULL;
2327 }
2328
2329
2330 static
2331 PPARTENTRY
2332 GetNextUnpartitionedEntry(
2333 PDISKENTRY DiskEntry,
2334 PPARTENTRY PartEntry)
2335 {
2336 PPARTENTRY NextPartEntry;
2337
2338 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2339 {
2340 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2341 PARTENTRY,
2342 ListEntry);
2343 if (NextPartEntry->IsPartitioned == FALSE)
2344 return NextPartEntry;
2345 }
2346
2347 return NULL;
2348 }
2349
2350
2351 VOID
2352 CreatePrimaryPartition(
2353 PPARTLIST List,
2354 ULONGLONG SectorCount,
2355 BOOLEAN AutoCreate)
2356 {
2357 PDISKENTRY DiskEntry;
2358 PPARTENTRY PartEntry;
2359 PPARTENTRY NewPartEntry;
2360
2361 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2362
2363 if (List == NULL ||
2364 List->CurrentDisk == NULL ||
2365 List->CurrentPartition == NULL ||
2366 List->CurrentPartition->IsPartitioned == TRUE)
2367 {
2368 return;
2369 }
2370
2371 DiskEntry = List->CurrentDisk;
2372 PartEntry = List->CurrentPartition;
2373
2374 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2375
2376 if (AutoCreate == TRUE ||
2377 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2378 {
2379 DPRINT1("Convert existing partition entry\n");
2380 /* Convert current entry to 'new (unformatted)' */
2381 PartEntry->IsPartitioned = TRUE;
2382 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2383 PartEntry->FormatState = Unformatted;
2384 PartEntry->AutoCreate = AutoCreate;
2385 PartEntry->New = TRUE;
2386 PartEntry->BootIndicator = FALSE; /* FIXME */
2387
2388 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2389 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2390 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2391 }
2392 else
2393 {
2394 DPRINT1("Add new partition entry\n");
2395
2396 /* Insert and initialize a new partition entry */
2397 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2398 HEAP_ZERO_MEMORY,
2399 sizeof(PARTENTRY));
2400 if (NewPartEntry == NULL)
2401 return;
2402
2403 /* Insert the new entry into the list */
2404 InsertTailList(&PartEntry->ListEntry,
2405 &NewPartEntry->ListEntry);
2406
2407 NewPartEntry->DiskEntry = DiskEntry;
2408
2409 NewPartEntry->IsPartitioned = TRUE;
2410 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2411 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2412 NewPartEntry->StartSector.QuadPart;
2413 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2414
2415 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2416 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2417 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2418
2419 NewPartEntry->New = TRUE;
2420 NewPartEntry->FormatState = Unformatted;
2421 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2422
2423 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2424 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2425 }
2426
2427 UpdateDiskLayout(DiskEntry);
2428
2429 DiskEntry->Dirty = TRUE;
2430
2431 UpdatePartitionNumbers(DiskEntry);
2432
2433 AssignDriveLetters(List);
2434 }
2435
2436
2437 static
2438 VOID
2439 AddLogicalDiskSpace(
2440 PDISKENTRY DiskEntry)
2441 {
2442 PPARTENTRY NewPartEntry;
2443
2444 DPRINT1("AddLogicalDiskSpace()\n");
2445
2446 /* Create a partition table entry that represents the empty space in the container partition */
2447 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2448 HEAP_ZERO_MEMORY,
2449 sizeof(PARTENTRY));
2450 if (NewPartEntry == NULL)
2451 return;
2452
2453 NewPartEntry->DiskEntry = DiskEntry;
2454 NewPartEntry->LogicalPartition = TRUE;
2455
2456 NewPartEntry->IsPartitioned = FALSE;
2457 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorsPerTrack;
2458 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorsPerTrack;
2459
2460 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2461 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2462 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2463
2464 NewPartEntry->FormatState = Unformatted;
2465
2466 InsertTailList(&DiskEntry->LogicalPartListHead,
2467 &NewPartEntry->ListEntry);
2468 }
2469
2470
2471 VOID
2472 CreateExtendedPartition(
2473 PPARTLIST List,
2474 ULONGLONG SectorCount)
2475 {
2476 PDISKENTRY DiskEntry;
2477 PPARTENTRY PartEntry;
2478 PPARTENTRY NewPartEntry;
2479
2480 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2481
2482 if (List == NULL ||
2483 List->CurrentDisk == NULL ||
2484 List->CurrentPartition == NULL ||
2485 List->CurrentPartition->IsPartitioned == TRUE)
2486 {
2487 return;
2488 }
2489
2490 DiskEntry = List->CurrentDisk;
2491 PartEntry = List->CurrentPartition;
2492
2493 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2494
2495 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2496 {
2497 DPRINT1("Convert existing partition entry\n");
2498 /* Convert current entry to 'new (unformatted)' */
2499 PartEntry->IsPartitioned = TRUE;
2500 PartEntry->FormatState = Formatted;
2501 PartEntry->AutoCreate = FALSE;
2502 PartEntry->New = FALSE;
2503 PartEntry->BootIndicator = FALSE; /* FIXME */
2504
2505 if (PartEntry->StartSector.QuadPart < 1450560)
2506 {
2507 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2508 PartEntry->PartitionType = PARTITION_EXTENDED;
2509 }
2510 else
2511 {
2512 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2513 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2514 }
2515
2516 DiskEntry->ExtendedPartition = PartEntry;
2517
2518 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2519 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2520 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2521 }
2522 else
2523 {
2524 DPRINT1("Add new partition entry\n");
2525
2526 /* Insert and initialize a new partition entry */
2527 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2528 HEAP_ZERO_MEMORY,
2529 sizeof(PARTENTRY));
2530 if (NewPartEntry == NULL)
2531 return;
2532
2533 /* Insert the new entry into the list */
2534 InsertTailList(&PartEntry->ListEntry,
2535 &NewPartEntry->ListEntry);
2536
2537 NewPartEntry->DiskEntry = DiskEntry;
2538
2539 NewPartEntry->IsPartitioned = TRUE;
2540 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2541 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2542 NewPartEntry->StartSector.QuadPart;
2543
2544 NewPartEntry->New = FALSE;
2545 NewPartEntry->FormatState = Formatted;
2546 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2547
2548 if (NewPartEntry->StartSector.QuadPart < 1450560)
2549 {
2550 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2551 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2552 }
2553 else
2554 {
2555 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2556 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2557 }
2558
2559 DiskEntry->ExtendedPartition = NewPartEntry;
2560
2561 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2562 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2563
2564 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2565 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2566 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2567 }
2568
2569 AddLogicalDiskSpace(DiskEntry);
2570
2571 UpdateDiskLayout(DiskEntry);
2572
2573 DiskEntry->Dirty = TRUE;
2574
2575 UpdatePartitionNumbers(DiskEntry);
2576
2577 AssignDriveLetters(List);
2578 }
2579
2580
2581 VOID
2582 CreateLogicalPartition(
2583 PPARTLIST List,
2584 ULONGLONG SectorCount)
2585 {
2586 // PDISKENTRY DiskEntry;
2587 PPARTENTRY PartEntry;
2588 // PPARTENTRY NewPartEntry;
2589
2590 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2591
2592 if (List == NULL ||
2593 List->CurrentDisk == NULL ||
2594 List->CurrentPartition == NULL ||
2595 List->CurrentPartition->IsPartitioned == TRUE)
2596 {
2597 return;
2598 }
2599
2600 // DiskEntry = List->CurrentDisk;
2601 PartEntry = List->CurrentPartition;
2602
2603 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2604 }
2605
2606
2607 VOID
2608 DeleteCurrentPartition(
2609 PPARTLIST List)
2610 {
2611 PDISKENTRY DiskEntry;
2612 PPARTENTRY PartEntry;
2613 PPARTENTRY PrevPartEntry;
2614 PPARTENTRY NextPartEntry;
2615 PPARTENTRY LogicalPartEntry;
2616 PLIST_ENTRY Entry;
2617
2618 if (List == NULL ||
2619 List->CurrentDisk == NULL ||
2620 List->CurrentPartition == NULL ||
2621 List->CurrentPartition->IsPartitioned == FALSE)
2622 {
2623 return;
2624 }
2625
2626 DiskEntry = List->CurrentDisk;
2627 PartEntry = List->CurrentPartition;
2628
2629 /* Delete all logical partiton entries if an extended partition will be deleted */
2630 if (DiskEntry->ExtendedPartition == PartEntry)
2631 {
2632 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2633 {
2634 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2635 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2636
2637 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2638 }
2639
2640 DiskEntry->ExtendedPartition = NULL;
2641 }
2642
2643 /* Adjust unpartitioned disk space entries */
2644
2645 /* Get pointer to previous and next unpartitioned entries */
2646 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2647 PartEntry);
2648
2649 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2650 PartEntry);
2651
2652 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2653 {
2654 /* Merge previous, current and next unpartitioned entry */
2655
2656 /* Adjust the previous entries length */
2657 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2658
2659 /* Remove the current entry */
2660 RemoveEntryList(&PartEntry->ListEntry);
2661 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2662
2663 /* Remove the next entry */
2664 RemoveEntryList (&NextPartEntry->ListEntry);
2665 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2666
2667 /* Update current partition */
2668 List->CurrentPartition = PrevPartEntry;
2669 }
2670 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2671 {
2672 /* Merge current and previous unpartitioned entry */
2673
2674 /* Adjust the previous entries length */
2675 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2676
2677 /* Remove the current entry */
2678 RemoveEntryList(&PartEntry->ListEntry);
2679 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2680
2681 /* Update current partition */
2682 List->CurrentPartition = PrevPartEntry;
2683 }
2684 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2685 {
2686 /* Merge current and next unpartitioned entry */
2687
2688 /* Adjust the next entries offset and length */
2689 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2690 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2691
2692 /* Remove the current entry */
2693 RemoveEntryList(&PartEntry->ListEntry);
2694 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2695
2696 /* Update current partition */
2697 List->CurrentPartition = NextPartEntry;
2698 }
2699 else
2700 {
2701 /* Nothing to merge but change current entry */
2702 PartEntry->IsPartitioned = FALSE;
2703 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2704 PartEntry->FormatState = Unformatted;
2705 PartEntry->DriveLetter = 0;
2706 }
2707
2708 UpdateDiskLayout(DiskEntry);
2709
2710 DiskEntry->Dirty = TRUE;
2711
2712 UpdatePartitionNumbers(DiskEntry);
2713
2714 AssignDriveLetters(List);
2715 }
2716
2717
2718 VOID
2719 CheckActiveBootPartition(
2720 PPARTLIST List)
2721 {
2722 PDISKENTRY DiskEntry;
2723 PPARTENTRY PartEntry;
2724 PLIST_ENTRY ListEntry;
2725
2726 /* Check for empty disk list */
2727 if (IsListEmpty (&List->DiskListHead))
2728 {
2729 List->ActiveBootDisk = NULL;
2730 List->ActiveBootPartition = NULL;
2731 return;
2732 }
2733
2734 #if 0
2735 if (List->ActiveBootDisk != NULL &&
2736 List->ActiveBootPartition != NULL)
2737 {
2738 /* We already have an active boot partition */
2739 return;
2740 }
2741 #endif
2742
2743 /* Choose the currently selected disk */
2744 DiskEntry = List->CurrentDisk;
2745
2746 /* Check for empty partition list */
2747 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2748 {
2749 List->ActiveBootDisk = NULL;
2750 List->ActiveBootPartition = NULL;
2751 return;
2752 }
2753
2754 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2755 PARTENTRY,
2756 ListEntry);
2757
2758 /* Set active boot partition */
2759 if ((DiskEntry->NewDisk == TRUE) ||
2760 (PartEntry->BootIndicator == FALSE))
2761 {
2762 PartEntry->BootIndicator = TRUE;
2763 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2764 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2765 DiskEntry->Dirty = TRUE;
2766
2767 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2768 List->ActiveBootDisk = DiskEntry;
2769 List->ActiveBootPartition = PartEntry;
2770
2771 return;
2772 }
2773
2774 /* Disk is not new, scan all partitions to find a bootable one */
2775 List->ActiveBootDisk = NULL;
2776 List->ActiveBootPartition = NULL;
2777
2778 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2779 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2780 {
2781 PartEntry = CONTAINING_RECORD(ListEntry,
2782 PARTENTRY,
2783 ListEntry);
2784
2785 /* Check if it is partitioned */
2786 if (PartEntry->IsPartitioned)
2787 {
2788 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2789 PartEntry->BootIndicator)
2790 {
2791 /* Yes, we found it */
2792 List->ActiveBootDisk = DiskEntry;
2793 List->ActiveBootPartition = PartEntry;
2794
2795 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2796 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2797 break;
2798 }
2799 }
2800
2801 /* Go to the next one */
2802 ListEntry = ListEntry->Flink;
2803 }
2804 }
2805
2806
2807 BOOLEAN
2808 CheckForLinuxFdiskPartitions(
2809 PPARTLIST List)
2810 {
2811 #if 0
2812 PDISKENTRY DiskEntry;
2813 PPARTENTRY PartEntry;
2814 PLIST_ENTRY Entry1;
2815 PLIST_ENTRY Entry2;
2816 ULONG PartitionCount;
2817 ULONG i;
2818
2819 Entry1 = List->DiskListHead.Flink;
2820 while (Entry1 != &List->DiskListHead)
2821 {
2822 DiskEntry = CONTAINING_RECORD(Entry1,
2823 DISKENTRY,
2824 ListEntry);
2825
2826 Entry2 = DiskEntry->PartListHead.Flink;
2827 while (Entry2 != &DiskEntry->PartListHead)
2828 {
2829 PartEntry = CONTAINING_RECORD(Entry2,
2830 PARTENTRY,
2831 ListEntry);
2832
2833 if (PartEntry->Unpartitioned == FALSE)
2834 {
2835 PartitionCount = 0;
2836
2837 for (i = 0; i < 4; i++)
2838 {
2839 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2840 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2841 {
2842 PartitionCount++;
2843 }
2844 }
2845
2846 if (PartitionCount > 1)
2847 {
2848 return TRUE;
2849 }
2850 }
2851
2852 Entry2 = Entry2->Flink;
2853 }
2854
2855 Entry1 = Entry1->Flink;
2856 }
2857 #endif
2858
2859 return FALSE;
2860 }
2861
2862
2863 static
2864 NTSTATUS
2865 WritePartitons(
2866 IN PPARTLIST List,
2867 IN PDISKENTRY DiskEntry)
2868 {
2869 WCHAR DstPath[MAX_PATH];
2870 OBJECT_ATTRIBUTES ObjectAttributes;
2871 IO_STATUS_BLOCK Iosb;
2872 UNICODE_STRING Name;
2873 ULONG BufferSize;
2874 HANDLE FileHandle = NULL;
2875 NTSTATUS Status;
2876
2877 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2878
2879 swprintf(DstPath,
2880 L"\\Device\\Harddisk%d\\Partition0",
2881 DiskEntry->DiskNumber);
2882 RtlInitUnicodeString(&Name,
2883 DstPath);
2884 InitializeObjectAttributes(&ObjectAttributes,
2885 &Name,
2886 0,
2887 NULL,
2888 NULL);
2889
2890 Status = NtOpenFile(&FileHandle,
2891 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2892 &ObjectAttributes,
2893 &Iosb,
2894 0,
2895 FILE_SYNCHRONOUS_IO_NONALERT);
2896 if (!NT_SUCCESS(Status))
2897 {
2898 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2899 return Status;
2900 }
2901
2902 #ifdef DUMP_PARTITION_TABLE
2903 DumpPartitionTable(DiskEntry);
2904 #endif
2905
2906 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2907 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2908 Status = NtDeviceIoControlFile(FileHandle,
2909 NULL,
2910 NULL,
2911 NULL,
2912 &Iosb,
2913 IOCTL_DISK_SET_DRIVE_LAYOUT,
2914 DiskEntry->LayoutBuffer,
2915 BufferSize,
2916 NULL,
2917 0);
2918 if (!NT_SUCCESS(Status))
2919 {
2920 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2921 }
2922
2923 if (FileHandle != NULL)
2924 NtClose(FileHandle);
2925
2926 return Status;
2927 }
2928
2929
2930 BOOLEAN
2931 WritePartitionsToDisk(
2932 PPARTLIST List)
2933 {
2934 PLIST_ENTRY Entry;
2935 PDISKENTRY DiskEntry;
2936
2937 if (List == NULL)
2938 return TRUE;
2939
2940 Entry = List->DiskListHead.Flink;
2941 while (Entry != &List->DiskListHead)
2942 {
2943 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2944
2945 if (DiskEntry->Dirty == TRUE)
2946 {
2947 WritePartitons(List, DiskEntry);
2948 }
2949
2950 Entry = Entry->Flink;
2951 }
2952
2953 return TRUE;
2954 }
2955
2956
2957 BOOL
2958 SetMountedDeviceValues(
2959 PPARTLIST List)
2960 {
2961 PLIST_ENTRY Entry1, Entry2;
2962 PDISKENTRY DiskEntry;
2963 PPARTENTRY PartEntry;
2964 LARGE_INTEGER StartingOffset;
2965
2966 if (List == NULL)
2967 {
2968 return FALSE;
2969 }
2970
2971 Entry1 = List->DiskListHead.Flink;
2972 while (Entry1 != &List->DiskListHead)
2973 {
2974 DiskEntry = CONTAINING_RECORD(Entry1,
2975 DISKENTRY,
2976 ListEntry);
2977
2978 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2979 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2980 {
2981 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2982 if (PartEntry->IsPartitioned)
2983 {
2984 if (PartEntry->DriveLetter)
2985 {
2986 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2987 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
2988 DiskEntry->LayoutBuffer->Signature,
2989 StartingOffset))
2990 {
2991 return FALSE;
2992 }
2993 }
2994 }
2995
2996 Entry2 = Entry2->Flink;
2997 }
2998
2999 Entry1 = Entry1->Flink;
3000 }
3001
3002 return TRUE;
3003 }
3004
3005
3006 static
3007 ULONG
3008 GetPrimaryPartitionCount(
3009 IN PDISKENTRY DiskEntry)
3010 {
3011 PLIST_ENTRY Entry;
3012 PPARTENTRY PartEntry;
3013 UINT nCount = 0;
3014
3015 Entry = DiskEntry->PrimaryPartListHead.Flink;
3016 while (Entry != &DiskEntry->PrimaryPartListHead)
3017 {
3018 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3019 if (PartEntry->IsPartitioned == TRUE)
3020 nCount++;
3021
3022 Entry = Entry->Flink;
3023 }
3024
3025 return nCount;
3026 }
3027
3028
3029 ULONG
3030 PrimaryPartitionCreationChecks(
3031 IN PPARTLIST List)
3032 {
3033 PDISKENTRY DiskEntry;
3034 PPARTENTRY PartEntry;
3035
3036 DiskEntry = List->CurrentDisk;
3037 PartEntry = List->CurrentPartition;
3038
3039 /* Fail if partition is already in use */
3040 if (PartEntry->IsPartitioned == TRUE)
3041 return ERROR_NEW_PARTITION;
3042
3043 /* Fail if there are more than 4 partitions in the list */
3044 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3045 return ERROR_PARTITION_TABLE_FULL;
3046
3047 return ERROR_SUCCESS;
3048 }
3049
3050
3051 ULONG
3052 ExtendedPartitionCreationChecks(
3053 IN PPARTLIST List)
3054 {
3055 PDISKENTRY DiskEntry;
3056 PPARTENTRY PartEntry;
3057
3058 DiskEntry = List->CurrentDisk;
3059 PartEntry = List->CurrentPartition;
3060
3061 /* Fail if partition is already in use */
3062 if (PartEntry->IsPartitioned == TRUE)
3063 return ERROR_NEW_PARTITION;
3064
3065 /* Fail if there are more than 4 partitions in the list */
3066 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3067 return ERROR_PARTITION_TABLE_FULL;
3068
3069 /* Fail if there is another extended partition in the list */
3070 if (DiskEntry->ExtendedPartition != NULL)
3071 return ERROR_ONLY_ONE_EXTENDED;
3072
3073 return ERROR_SUCCESS;
3074 }
3075
3076
3077 ULONG
3078 LogicalPartitionCreationChecks(
3079 IN PPARTLIST List)
3080 {
3081 // PDISKENTRY DiskEntry;
3082 PPARTENTRY PartEntry;
3083
3084 // DiskEntry = List->CurrentDisk;
3085 PartEntry = List->CurrentPartition;
3086
3087 /* Fail if partition is already in use */
3088 if (PartEntry->IsPartitioned == TRUE)
3089 return ERROR_NEW_PARTITION;
3090
3091 return ERROR_SUCCESS;
3092 }
3093
3094 /* EOF */