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