61b93a2582f4a3fc0966944e7322cf989c6d079c
[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 (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->PartitionCount == 0)
1178 {
1179 DiskEntry->NewDisk = TRUE;
1180 DiskEntry->LayoutBuffer->PartitionCount = 4;
1181
1182 for (i = 0; i < 4; i++)
1183 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1184 }
1185 else
1186 {
1187 for (i = 0; i < 4; i++)
1188 {
1189 AddPartitionToDisk(DiskNumber,
1190 DiskEntry,
1191 i,
1192 FALSE);
1193 }
1194
1195 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1196 {
1197 AddPartitionToDisk(DiskNumber,
1198 DiskEntry,
1199 i,
1200 TRUE);
1201 }
1202 }
1203 }
1204
1205 ScanForUnpartitionedDiskSpace(DiskEntry);
1206 }
1207
1208
1209 PPARTLIST
1210 CreatePartitionList(
1211 SHORT Left,
1212 SHORT Top,
1213 SHORT Right,
1214 SHORT Bottom)
1215 {
1216 PPARTLIST List;
1217 OBJECT_ATTRIBUTES ObjectAttributes;
1218 SYSTEM_DEVICE_INFORMATION Sdi;
1219 IO_STATUS_BLOCK Iosb;
1220 ULONG ReturnSize;
1221 NTSTATUS Status;
1222 ULONG DiskNumber;
1223 WCHAR Buffer[MAX_PATH];
1224 UNICODE_STRING Name;
1225 HANDLE FileHandle;
1226
1227 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1228 0,
1229 sizeof (PARTLIST));
1230 if (List == NULL)
1231 return NULL;
1232
1233 List->Left = Left;
1234 List->Top = Top;
1235 List->Right = Right;
1236 List->Bottom = Bottom;
1237
1238 List->Line = 0;
1239 List->Offset = 0;
1240
1241 List->TopDisk = (ULONG)-1;
1242 List->TopPartition = (ULONG)-1;
1243
1244 List->CurrentDisk = NULL;
1245 List->CurrentPartition = NULL;
1246
1247 InitializeListHead(&List->DiskListHead);
1248 InitializeListHead(&List->BiosDiskListHead);
1249
1250 EnumerateBiosDiskEntries(List);
1251
1252 Status = NtQuerySystemInformation(SystemDeviceInformation,
1253 &Sdi,
1254 sizeof(SYSTEM_DEVICE_INFORMATION),
1255 &ReturnSize);
1256 if (!NT_SUCCESS(Status))
1257 {
1258 RtlFreeHeap(ProcessHeap, 0, List);
1259 return NULL;
1260 }
1261
1262 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1263 {
1264 swprintf(Buffer,
1265 L"\\Device\\Harddisk%d\\Partition0",
1266 DiskNumber);
1267 RtlInitUnicodeString(&Name,
1268 Buffer);
1269
1270 InitializeObjectAttributes(&ObjectAttributes,
1271 &Name,
1272 0,
1273 NULL,
1274 NULL);
1275
1276 Status = NtOpenFile(&FileHandle,
1277 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1278 &ObjectAttributes,
1279 &Iosb,
1280 FILE_SHARE_READ,
1281 FILE_SYNCHRONOUS_IO_NONALERT);
1282 if (NT_SUCCESS(Status))
1283 {
1284 AddDiskToList(FileHandle,
1285 DiskNumber,
1286 List);
1287
1288 NtClose(FileHandle);
1289 }
1290 }
1291
1292 UpdateDiskSignatures(List);
1293
1294 AssignDriveLetters(List);
1295
1296 List->TopDisk = 0;
1297 List->TopPartition = 0;
1298
1299 /* Search for first usable disk and partition */
1300 if (IsListEmpty(&List->DiskListHead))
1301 {
1302 List->CurrentDisk = NULL;
1303 List->CurrentPartition = NULL;
1304 }
1305 else
1306 {
1307 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1308 DISKENTRY,
1309 ListEntry);
1310
1311 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1312 {
1313 List->CurrentPartition = 0;
1314 }
1315 else
1316 {
1317 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1318 PARTENTRY,
1319 ListEntry);
1320 }
1321 }
1322
1323 return List;
1324 }
1325
1326
1327 VOID
1328 DestroyPartitionList(
1329 PPARTLIST List)
1330 {
1331 PDISKENTRY DiskEntry;
1332 PBIOSDISKENTRY BiosDiskEntry;
1333 PPARTENTRY PartEntry;
1334 PLIST_ENTRY Entry;
1335
1336 /* Release disk and partition info */
1337 while (!IsListEmpty(&List->DiskListHead))
1338 {
1339 Entry = RemoveHeadList(&List->DiskListHead);
1340 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1341
1342 /* Release driver name */
1343 RtlFreeUnicodeString(&DiskEntry->DriverName);
1344
1345 /* Release primary partition list */
1346 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1347 {
1348 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1349 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1350
1351 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1352 }
1353
1354 /* Release logical partition list */
1355 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1356 {
1357 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1358 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1359
1360 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1361 }
1362
1363 /* Release layout buffer */
1364 if (DiskEntry->LayoutBuffer != NULL)
1365 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1366
1367
1368 /* Release disk entry */
1369 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1370 }
1371
1372 /* release the bios disk info */
1373 while(!IsListEmpty(&List->BiosDiskListHead))
1374 {
1375 Entry = RemoveHeadList(&List->BiosDiskListHead);
1376 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1377
1378 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1379 }
1380
1381 /* Release list head */
1382 RtlFreeHeap(ProcessHeap, 0, List);
1383 }
1384
1385
1386 static
1387 VOID
1388 PrintEmptyLine(
1389 PPARTLIST List)
1390 {
1391 COORD coPos;
1392 DWORD Written;
1393 USHORT Width;
1394 USHORT Height;
1395
1396 Width = List->Right - List->Left - 1;
1397 Height = List->Bottom - List->Top - 2;
1398
1399 coPos.X = List->Left + 1;
1400 coPos.Y = List->Top + 1 + List->Line;
1401
1402 if (List->Line >= 0 && List->Line <= Height)
1403 {
1404 FillConsoleOutputAttribute(StdOutput,
1405 FOREGROUND_WHITE | BACKGROUND_BLUE,
1406 Width,
1407 coPos,
1408 &Written);
1409
1410 FillConsoleOutputCharacterA(StdOutput,
1411 ' ',
1412 Width,
1413 coPos,
1414 &Written);
1415 }
1416
1417 List->Line++;
1418 }
1419
1420
1421 static
1422 VOID
1423 PrintPartitionData(
1424 PPARTLIST List,
1425 PDISKENTRY DiskEntry,
1426 PPARTENTRY PartEntry)
1427 {
1428 CHAR LineBuffer[128];
1429 COORD coPos;
1430 DWORD Written;
1431 USHORT Width;
1432 USHORT Height;
1433 LARGE_INTEGER PartSize;
1434 PCHAR Unit;
1435 UCHAR Attribute;
1436 PCHAR PartType;
1437
1438 Width = List->Right - List->Left - 1;
1439 Height = List->Bottom - List->Top - 2;
1440
1441 coPos.X = List->Left + 1;
1442 coPos.Y = List->Top + 1 + List->Line;
1443
1444 if (PartEntry->IsPartitioned == FALSE)
1445 {
1446 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1447 #if 0
1448 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1449 {
1450 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1451 Unit = MUIGetString(STRING_GB);
1452 }
1453 else
1454 #endif
1455 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1456 {
1457 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1458 Unit = MUIGetString(STRING_MB);
1459 }
1460 else
1461 {
1462 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1463 Unit = MUIGetString(STRING_KB);
1464 }
1465
1466 sprintf(LineBuffer,
1467 MUIGetString(STRING_UNPSPACE),
1468 PartEntry->LogicalPartition ? " " : "",
1469 PartEntry->LogicalPartition ? "" : " ",
1470 PartSize.u.LowPart,
1471 Unit);
1472 }
1473 else
1474 {
1475 /* Determine partition type */
1476 PartType = NULL;
1477 if (PartEntry->New == TRUE)
1478 {
1479 PartType = MUIGetString(STRING_UNFORMATTED);
1480 }
1481 else if (PartEntry->IsPartitioned == TRUE)
1482 {
1483 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
1484 (PartEntry->PartitionType == PARTITION_FAT_16) ||
1485 (PartEntry->PartitionType == PARTITION_HUGE) ||
1486 (PartEntry->PartitionType == PARTITION_XINT13))
1487 {
1488 PartType = "FAT";
1489 }
1490 else if ((PartEntry->PartitionType == PARTITION_FAT32) ||
1491 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
1492 {
1493 PartType = "FAT32";
1494 }
1495 else if (PartEntry->PartitionType == PARTITION_EXT2)
1496 {
1497 PartType = "EXT2";
1498 }
1499 else if (PartEntry->PartitionType == PARTITION_IFS)
1500 {
1501 PartType = "NTFS"; /* FIXME: Not quite correct! */
1502 }
1503 else if ((PartEntry->PartitionType == PARTITION_EXTENDED) ||
1504 (PartEntry->PartitionType == PARTITION_XINT13_EXTENDED))
1505 {
1506 PartType = MUIGetString(STRING_EXTENDED_PARTITION);
1507 }
1508 }
1509
1510 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1511 #if 0
1512 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1513 {
1514 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1515 Unit = MUIGetString(STRING_GB);
1516 }
1517 else
1518 #endif
1519 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1520 {
1521 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1522 Unit = MUIGetString(STRING_MB);
1523 }
1524 else
1525 {
1526 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1527 Unit = MUIGetString(STRING_KB);
1528 }
1529
1530 if (PartType == NULL)
1531 {
1532 sprintf(LineBuffer,
1533 MUIGetString(STRING_HDDINFOUNK5),
1534 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1535 (PartEntry->DriveLetter == 0) ? '-' : ':',
1536 PartEntry->LogicalPartition ? " " : "",
1537 PartEntry->PartitionType,
1538 PartEntry->LogicalPartition ? "" : " ",
1539 PartSize.u.LowPart,
1540 Unit);
1541 }
1542 else
1543 {
1544 sprintf(LineBuffer,
1545 "%c%c %s%-24s%s %6lu %s",
1546 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1547 (PartEntry->DriveLetter == 0) ? '-' : ':',
1548 PartEntry->LogicalPartition ? " " : "",
1549 PartType,
1550 PartEntry->LogicalPartition ? "" : " ",
1551 PartSize.u.LowPart,
1552 Unit);
1553 }
1554 }
1555
1556 Attribute = (List->CurrentDisk == DiskEntry &&
1557 List->CurrentPartition == PartEntry) ?
1558 FOREGROUND_BLUE | BACKGROUND_WHITE :
1559 FOREGROUND_WHITE | BACKGROUND_BLUE;
1560
1561 if (List->Line >= 0 && List->Line <= Height)
1562 {
1563 FillConsoleOutputCharacterA(StdOutput,
1564 ' ',
1565 Width,
1566 coPos,
1567 &Written);
1568 }
1569 coPos.X += 4;
1570 Width -= 8;
1571 if (List->Line >= 0 && List->Line <= Height)
1572 {
1573 FillConsoleOutputAttribute(StdOutput,
1574 Attribute,
1575 Width,
1576 coPos,
1577 &Written);
1578 }
1579 coPos.X++;
1580 Width -= 2;
1581 if (List->Line >= 0 && List->Line <= Height)
1582 {
1583 WriteConsoleOutputCharacterA(StdOutput,
1584 LineBuffer,
1585 min(strlen(LineBuffer), Width),
1586 coPos,
1587 &Written);
1588 }
1589
1590 List->Line++;
1591 }
1592
1593
1594 static
1595 VOID
1596 PrintDiskData(
1597 PPARTLIST List,
1598 PDISKENTRY DiskEntry)
1599 {
1600 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1601 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1602 CHAR LineBuffer[128];
1603 COORD coPos;
1604 DWORD Written;
1605 USHORT Width;
1606 USHORT Height;
1607 ULARGE_INTEGER DiskSize;
1608 PCHAR Unit;
1609
1610 Width = List->Right - List->Left - 1;
1611 Height = List->Bottom - List->Top - 2;
1612
1613 coPos.X = List->Left + 1;
1614 coPos.Y = List->Top + 1 + List->Line;
1615
1616 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1617 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1618 {
1619 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1620 Unit = MUIGetString(STRING_GB);
1621 }
1622 else
1623 {
1624 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1625 if (DiskSize.QuadPart == 0)
1626 DiskSize.QuadPart = 1;
1627 Unit = MUIGetString(STRING_MB);
1628 }
1629
1630 if (DiskEntry->DriverName.Length > 0)
1631 {
1632 sprintf(LineBuffer,
1633 MUIGetString(STRING_HDINFOPARTSELECT),
1634 DiskSize.u.LowPart,
1635 Unit,
1636 DiskEntry->DiskNumber,
1637 DiskEntry->Port,
1638 DiskEntry->Bus,
1639 DiskEntry->Id,
1640 DiskEntry->DriverName.Buffer);
1641 }
1642 else
1643 {
1644 sprintf(LineBuffer,
1645 MUIGetString(STRING_HDDINFOUNK6),
1646 DiskSize.u.LowPart,
1647 Unit,
1648 DiskEntry->DiskNumber,
1649 DiskEntry->Port,
1650 DiskEntry->Bus,
1651 DiskEntry->Id);
1652 }
1653
1654 if (List->Line >= 0 && List->Line <= Height)
1655 {
1656 FillConsoleOutputAttribute(StdOutput,
1657 FOREGROUND_WHITE | BACKGROUND_BLUE,
1658 Width,
1659 coPos,
1660 &Written);
1661
1662 FillConsoleOutputCharacterA(StdOutput,
1663 ' ',
1664 Width,
1665 coPos,
1666 &Written);
1667 }
1668
1669 coPos.X++;
1670 if (List->Line >= 0 && List->Line <= Height)
1671 {
1672 WriteConsoleOutputCharacterA(StdOutput,
1673 LineBuffer,
1674 min((USHORT)strlen(LineBuffer), Width - 2),
1675 coPos,
1676 &Written);
1677 }
1678
1679 List->Line++;
1680
1681 /* Print separator line */
1682 PrintEmptyLine(List);
1683
1684 /* Print partition lines*/
1685 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1686 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1687 {
1688 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1689
1690 PrintPartitionData(List,
1691 DiskEntry,
1692 PrimaryPartEntry);
1693
1694 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1695 {
1696 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1697 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1698 {
1699 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1700
1701 PrintPartitionData(List,
1702 DiskEntry,
1703 LogicalPartEntry);
1704
1705 LogicalEntry = LogicalEntry->Flink;
1706 }
1707 }
1708
1709 PrimaryEntry = PrimaryEntry->Flink;
1710 }
1711
1712 /* Print separator line */
1713 PrintEmptyLine(List);
1714 }
1715
1716
1717 VOID
1718 DrawPartitionList(
1719 PPARTLIST List)
1720 {
1721 PLIST_ENTRY Entry, Entry2;
1722 PDISKENTRY DiskEntry;
1723 PPARTENTRY PartEntry = NULL;
1724 COORD coPos;
1725 DWORD Written;
1726 SHORT i;
1727 SHORT CurrentDiskLine;
1728 SHORT CurrentPartLine;
1729 SHORT LastLine;
1730 BOOL CurrentPartLineFound = FALSE;
1731 BOOL CurrentDiskLineFound = FALSE;
1732
1733 /* Calculate the line of the current disk and partition */
1734 CurrentDiskLine = 0;
1735 CurrentPartLine = 0;
1736 LastLine = 0;
1737
1738 Entry = List->DiskListHead.Flink;
1739 while (Entry != &List->DiskListHead)
1740 {
1741 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1742
1743 LastLine += 2;
1744 if (CurrentPartLineFound == FALSE)
1745 {
1746 CurrentPartLine += 2;
1747 }
1748
1749 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1750 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1751 {
1752 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1753 if (PartEntry == List->CurrentPartition)
1754 {
1755 CurrentPartLineFound = TRUE;
1756 }
1757
1758 Entry2 = Entry2->Flink;
1759 if (CurrentPartLineFound == FALSE)
1760 {
1761 CurrentPartLine++;
1762 }
1763
1764 LastLine++;
1765 }
1766
1767 if (DiskEntry == List->CurrentDisk)
1768 {
1769 CurrentDiskLineFound = TRUE;
1770 }
1771
1772 Entry = Entry->Flink;
1773 if (Entry != &List->DiskListHead)
1774 {
1775 if (CurrentDiskLineFound == FALSE)
1776 {
1777 CurrentPartLine ++;
1778 CurrentDiskLine = CurrentPartLine;
1779 }
1780
1781 LastLine++;
1782 }
1783 else
1784 {
1785 LastLine--;
1786 }
1787 }
1788
1789 /* If it possible, make the disk name visible */
1790 if (CurrentPartLine < List->Offset)
1791 {
1792 List->Offset = CurrentPartLine;
1793 }
1794 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1795 {
1796 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1797 }
1798
1799 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1800 {
1801 List->Offset = CurrentDiskLine;
1802 }
1803
1804 /* draw upper left corner */
1805 coPos.X = List->Left;
1806 coPos.Y = List->Top;
1807 FillConsoleOutputCharacterA(StdOutput,
1808 0xDA, // '+',
1809 1,
1810 coPos,
1811 &Written);
1812
1813 /* draw upper edge */
1814 coPos.X = List->Left + 1;
1815 coPos.Y = List->Top;
1816 if (List->Offset == 0)
1817 {
1818 FillConsoleOutputCharacterA(StdOutput,
1819 0xC4, // '-',
1820 List->Right - List->Left - 1,
1821 coPos,
1822 &Written);
1823 }
1824 else
1825 {
1826 FillConsoleOutputCharacterA(StdOutput,
1827 0xC4, // '-',
1828 List->Right - List->Left - 5,
1829 coPos,
1830 &Written);
1831 coPos.X = List->Right - 5;
1832 WriteConsoleOutputCharacterA(StdOutput,
1833 "(\x18)", // "(up)"
1834 3,
1835 coPos,
1836 &Written);
1837 coPos.X = List->Right - 2;
1838 FillConsoleOutputCharacterA(StdOutput,
1839 0xC4, // '-',
1840 2,
1841 coPos,
1842 &Written);
1843 }
1844
1845 /* draw upper right corner */
1846 coPos.X = List->Right;
1847 coPos.Y = List->Top;
1848 FillConsoleOutputCharacterA(StdOutput,
1849 0xBF, // '+',
1850 1,
1851 coPos,
1852 &Written);
1853
1854 /* draw left and right edge */
1855 for (i = List->Top + 1; i < List->Bottom; i++)
1856 {
1857 coPos.X = List->Left;
1858 coPos.Y = i;
1859 FillConsoleOutputCharacterA(StdOutput,
1860 0xB3, // '|',
1861 1,
1862 coPos,
1863 &Written);
1864
1865 coPos.X = List->Right;
1866 FillConsoleOutputCharacterA(StdOutput,
1867 0xB3, //'|',
1868 1,
1869 coPos,
1870 &Written);
1871 }
1872
1873 /* draw lower left corner */
1874 coPos.X = List->Left;
1875 coPos.Y = List->Bottom;
1876 FillConsoleOutputCharacterA(StdOutput,
1877 0xC0, // '+',
1878 1,
1879 coPos,
1880 &Written);
1881
1882 /* draw lower edge */
1883 coPos.X = List->Left + 1;
1884 coPos.Y = List->Bottom;
1885 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1886 {
1887 FillConsoleOutputCharacterA(StdOutput,
1888 0xC4, // '-',
1889 List->Right - List->Left - 1,
1890 coPos,
1891 &Written);
1892 }
1893 else
1894 {
1895 FillConsoleOutputCharacterA(StdOutput,
1896 0xC4, // '-',
1897 List->Right - List->Left - 5,
1898 coPos,
1899 &Written);
1900 coPos.X = List->Right - 5;
1901 WriteConsoleOutputCharacterA(StdOutput,
1902 "(\x19)", // "(down)"
1903 3,
1904 coPos,
1905 &Written);
1906 coPos.X = List->Right - 2;
1907 FillConsoleOutputCharacterA(StdOutput,
1908 0xC4, // '-',
1909 2,
1910 coPos,
1911 &Written);
1912 }
1913
1914 /* draw lower right corner */
1915 coPos.X = List->Right;
1916 coPos.Y = List->Bottom;
1917 FillConsoleOutputCharacterA(StdOutput,
1918 0xD9, // '+',
1919 1,
1920 coPos,
1921 &Written);
1922
1923 /* print list entries */
1924 List->Line = - List->Offset;
1925
1926 Entry = List->DiskListHead.Flink;
1927 while (Entry != &List->DiskListHead)
1928 {
1929 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1930
1931 /* Print disk entry */
1932 PrintDiskData(List,
1933 DiskEntry);
1934
1935 Entry = Entry->Flink;
1936 }
1937 }
1938
1939
1940 DWORD
1941 SelectPartition(
1942 PPARTLIST List,
1943 ULONG DiskNumber,
1944 ULONG PartitionNumber)
1945 {
1946 PDISKENTRY DiskEntry;
1947 PPARTENTRY PartEntry;
1948 PLIST_ENTRY Entry1;
1949 PLIST_ENTRY Entry2;
1950
1951 /* Check for empty disks */
1952 if (IsListEmpty(&List->DiskListHead))
1953 return FALSE;
1954
1955 /* Check for first usable entry on next disk */
1956 Entry1 = List->CurrentDisk->ListEntry.Flink;
1957 while (Entry1 != &List->DiskListHead)
1958 {
1959 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1960
1961 if (DiskEntry->DiskNumber == DiskNumber)
1962 {
1963 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1964 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1965 {
1966 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1967
1968 if (PartEntry->PartitionNumber == PartitionNumber)
1969 {
1970 List->CurrentDisk = DiskEntry;
1971 List->CurrentPartition = PartEntry;
1972 DrawPartitionList(List);
1973 return TRUE;
1974 }
1975
1976 Entry2 = Entry2->Flink;
1977 }
1978
1979 return FALSE;
1980 }
1981
1982 Entry1 = Entry1->Flink;
1983 }
1984
1985 return FALSE;
1986 }
1987
1988
1989 VOID
1990 ScrollDownPartitionList(
1991 PPARTLIST List)
1992 {
1993 // PDISKENTRY DiskEntry;
1994 PPARTENTRY PartEntry;
1995 // PLIST_ENTRY Entry1;
1996 PLIST_ENTRY Entry2;
1997
1998 /* Check for empty disks */
1999 if (IsListEmpty(&List->DiskListHead))
2000 return;
2001
2002 /* Check for next usable entry on current disk */
2003 if (List->CurrentPartition != NULL)
2004 {
2005 Entry2 = List->CurrentPartition->ListEntry.Flink;
2006 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
2007 {
2008 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2009
2010 List->CurrentPartition = PartEntry;
2011 DrawPartitionList(List);
2012 return;
2013 }
2014 }
2015
2016 #if 0
2017 /* Check for first usable entry on next disk */
2018 if (List->CurrentDisk != NULL)
2019 {
2020 Entry1 = List->CurrentDisk->ListEntry.Flink;
2021 while (Entry1 != &List->DiskListHead)
2022 {
2023 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
2024
2025 Entry2 = DiskEntry->PartListHead.Flink;
2026 if (Entry2 != &DiskEntry->PartListHead)
2027 {
2028 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2029
2030 List->CurrentDisk = DiskEntry;
2031 List->CurrentPartition = PartEntry;
2032 DrawPartitionList(List);
2033 return;
2034 }
2035
2036 Entry1 = Entry1->Flink;
2037 }
2038 }
2039 #endif
2040 }
2041
2042
2043 VOID
2044 ScrollUpPartitionList(
2045 PPARTLIST List)
2046 {
2047 // PDISKENTRY DiskEntry;
2048 PPARTENTRY PartEntry;
2049 // PLIST_ENTRY Entry1;
2050 PLIST_ENTRY Entry2;
2051
2052 /* Check for empty disks */
2053 if (IsListEmpty(&List->DiskListHead))
2054 return;
2055
2056 /* check for previous usable entry on current disk */
2057 if (List->CurrentPartition != NULL)
2058 {
2059 Entry2 = List->CurrentPartition->ListEntry.Blink;
2060 if (Entry2 != &List->CurrentDisk->PrimaryPartListHead)
2061 {
2062 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2063
2064 List->CurrentPartition = PartEntry;
2065
2066 /* Draw partition list and return */
2067 DrawPartitionList(List);
2068 return;
2069 }
2070 }
2071
2072 #if 0
2073 /* check for last usable entry on previous disk */
2074 if (List->CurrentDisk != NULL)
2075 {
2076 Entry1 = List->CurrentDisk->ListEntry.Blink;
2077 while (Entry1 != &List->DiskListHead)
2078 {
2079 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
2080
2081 Entry2 = DiskEntry->PrimaryPartListHead.Blink;
2082 if (Entry2 != &DiskEntry->PrimaryPartListHead)
2083 {
2084 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2085
2086 List->CurrentDisk = DiskEntry;
2087 List->CurrentPartition = PartEntry;
2088
2089 /* Draw partition list and return */
2090 DrawPartitionList(List);
2091 return;
2092 }
2093
2094 Entry1 = Entry1->Blink;
2095 }
2096 }
2097 #endif
2098 }
2099
2100
2101 static
2102 BOOLEAN
2103 IsEmptyLayoutEntry(
2104 PPARTITION_INFORMATION PartitionInfo)
2105 {
2106 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2107 PartitionInfo->PartitionLength.QuadPart == 0)
2108 // PartitionInfo->PartitionType == 0)
2109 return TRUE;
2110
2111 return FALSE;
2112 }
2113
2114
2115 static
2116 BOOLEAN
2117 IsSamePrimaryLayoutEntry(
2118 IN PPARTITION_INFORMATION PartitionInfo,
2119 IN PDISKENTRY DiskEntry,
2120 IN PPARTENTRY PartEntry)
2121 {
2122 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2123 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2124 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2125 // PartitionInfo->PartitionType == PartEntry->PartitionType
2126 return TRUE;
2127
2128 return FALSE;
2129 }
2130
2131
2132 static
2133 VOID
2134 UpdateDiskLayout(
2135 IN PDISKENTRY DiskEntry)
2136 {
2137 PPARTITION_INFORMATION PartitionInfo;
2138 PLIST_ENTRY ListEntry;
2139 PPARTENTRY PartEntry;
2140 ULONG Index = 0;
2141 ULONG PartitionNumber = 1;
2142
2143 DPRINT1("UpdateDiskLayout()\n");
2144
2145 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2146 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2147 {
2148 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2149
2150 if (PartEntry->IsPartitioned == TRUE)
2151 {
2152 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2153
2154 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2155 {
2156 DPRINT1("Updating partition entry %lu\n", Index);
2157 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2158 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2159 PartitionInfo->HiddenSectors = 0;
2160 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2161 PartitionInfo->PartitionType = PartEntry->PartitionType;
2162 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2163 PartitionInfo->RecognizedPartition = FALSE;
2164 PartitionInfo->RewritePartition = TRUE;
2165
2166 PartEntry->PartitionNumber = PartitionNumber;
2167 PartEntry->PartitionIndex = Index;
2168
2169 PartitionNumber++;
2170 }
2171 else if (!IsEmptyLayoutEntry(PartitionInfo))
2172 {
2173 PartitionNumber++;
2174 }
2175
2176 Index++;
2177 }
2178
2179 ListEntry = ListEntry->Flink;
2180 }
2181
2182 for (;Index < 4; Index++)
2183 {
2184 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2185
2186 if (!IsEmptyLayoutEntry(PartitionInfo))
2187 {
2188 DPRINT1("Wiping partition entry %lu\n", Index);
2189 PartitionInfo->StartingOffset.QuadPart = 0;
2190 PartitionInfo->PartitionLength.QuadPart = 0;
2191 PartitionInfo->HiddenSectors = 0;
2192 PartitionInfo->PartitionNumber = 0;
2193 PartitionInfo->PartitionType = 0;
2194 PartitionInfo->BootIndicator = FALSE;
2195 PartitionInfo->RecognizedPartition = FALSE;
2196 PartitionInfo->RewritePartition = TRUE;
2197 }
2198 }
2199
2200 #ifdef DUMP_PARTITION_TABLE
2201 DumpPartitionTable(DiskEntry);
2202 #endif
2203 }
2204
2205
2206 static
2207 PPARTENTRY
2208 GetPrevUnpartitionedEntry(
2209 PDISKENTRY DiskEntry,
2210 PPARTENTRY PartEntry)
2211 {
2212 PPARTENTRY PrevPartEntry;
2213
2214 if (PartEntry->ListEntry.Blink != &DiskEntry->PrimaryPartListHead)
2215 {
2216 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2217 PARTENTRY,
2218 ListEntry);
2219 if (PrevPartEntry->IsPartitioned == FALSE)
2220 return PrevPartEntry;
2221 }
2222
2223 return NULL;
2224 }
2225
2226
2227 static
2228 PPARTENTRY
2229 GetNextUnpartitionedEntry(
2230 PDISKENTRY DiskEntry,
2231 PPARTENTRY PartEntry)
2232 {
2233 PPARTENTRY NextPartEntry;
2234
2235 if (PartEntry->ListEntry.Flink != &DiskEntry->PrimaryPartListHead)
2236 {
2237 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2238 PARTENTRY,
2239 ListEntry);
2240 if (NextPartEntry->IsPartitioned == FALSE)
2241 return NextPartEntry;
2242 }
2243
2244 return NULL;
2245 }
2246
2247
2248 VOID
2249 CreatePrimaryPartition(
2250 PPARTLIST List,
2251 ULONGLONG SectorCount,
2252 BOOLEAN AutoCreate)
2253 {
2254 PDISKENTRY DiskEntry;
2255 PPARTENTRY PartEntry;
2256 PPARTENTRY NewPartEntry;
2257
2258 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2259
2260 if (List == NULL ||
2261 List->CurrentDisk == NULL ||
2262 List->CurrentPartition == NULL ||
2263 List->CurrentPartition->IsPartitioned == TRUE)
2264 {
2265 return;
2266 }
2267
2268 DiskEntry = List->CurrentDisk;
2269 PartEntry = List->CurrentPartition;
2270
2271 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2272
2273 if (AutoCreate == TRUE ||
2274 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2275 {
2276 DPRINT1("Convert existing partition entry\n");
2277 /* Convert current entry to 'new (unformatted)' */
2278 PartEntry->IsPartitioned = TRUE;
2279 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2280 PartEntry->FormatState = Unformatted;
2281 PartEntry->AutoCreate = AutoCreate;
2282 PartEntry->New = TRUE;
2283 PartEntry->BootIndicator = FALSE; /* FIXME */
2284
2285 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2286 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2287 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2288 }
2289 else
2290 {
2291 DPRINT1("Add new partition entry\n");
2292
2293 /* Insert and initialize a new partition entry */
2294 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2295 HEAP_ZERO_MEMORY,
2296 sizeof(PARTENTRY));
2297 if (NewPartEntry == NULL)
2298 return;
2299
2300 /* Insert the new entry into the list */
2301 InsertTailList(&PartEntry->ListEntry,
2302 &NewPartEntry->ListEntry);
2303
2304 NewPartEntry->DiskEntry = DiskEntry;
2305
2306 NewPartEntry->IsPartitioned = TRUE;
2307 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2308 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2309 NewPartEntry->StartSector.QuadPart;
2310 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2311
2312 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2313 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2314 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2315
2316 NewPartEntry->New = TRUE;
2317 NewPartEntry->FormatState = Unformatted;
2318 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2319
2320 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2321 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2322 }
2323
2324 UpdateDiskLayout(DiskEntry);
2325
2326 DiskEntry->Dirty = TRUE;
2327
2328 UpdatePartitionNumbers(DiskEntry);
2329
2330 AssignDriveLetters(List);
2331 }
2332
2333
2334 static
2335 VOID
2336 AddLogicalDiskSpace(
2337 PDISKENTRY DiskEntry)
2338 {
2339 PPARTENTRY NewPartEntry;
2340
2341 DPRINT1("AddLogicalDiskSpace()\n");
2342
2343 /* Create a partition table entry that represents the empty space in the container partition */
2344 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2345 HEAP_ZERO_MEMORY,
2346 sizeof(PARTENTRY));
2347 if (NewPartEntry == NULL)
2348 return;
2349
2350 NewPartEntry->DiskEntry = DiskEntry;
2351 NewPartEntry->LogicalPartition = TRUE;
2352
2353 NewPartEntry->IsPartitioned = FALSE;
2354 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorsPerTrack;
2355 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorsPerTrack;
2356
2357 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2358 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2359 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2360
2361 NewPartEntry->FormatState = Unformatted;
2362
2363 InsertTailList(&DiskEntry->LogicalPartListHead,
2364 &NewPartEntry->ListEntry);
2365 }
2366
2367
2368 VOID
2369 CreateExtendedPartition(
2370 PPARTLIST List,
2371 ULONGLONG SectorCount)
2372 {
2373 PDISKENTRY DiskEntry;
2374 PPARTENTRY PartEntry;
2375 PPARTENTRY NewPartEntry;
2376
2377 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2378
2379 if (List == NULL ||
2380 List->CurrentDisk == NULL ||
2381 List->CurrentPartition == NULL ||
2382 List->CurrentPartition->IsPartitioned == TRUE)
2383 {
2384 return;
2385 }
2386
2387 DiskEntry = List->CurrentDisk;
2388 PartEntry = List->CurrentPartition;
2389
2390 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2391
2392 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2393 {
2394 DPRINT1("Convert existing partition entry\n");
2395 /* Convert current entry to 'new (unformatted)' */
2396 PartEntry->IsPartitioned = TRUE;
2397 PartEntry->FormatState = Formatted;
2398 PartEntry->AutoCreate = FALSE;
2399 PartEntry->New = FALSE;
2400 PartEntry->BootIndicator = FALSE; /* FIXME */
2401
2402 if (PartEntry->StartSector.QuadPart < 1450560)
2403 {
2404 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2405 PartEntry->PartitionType = PARTITION_EXTENDED;
2406 }
2407 else
2408 {
2409 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2410 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2411 }
2412
2413 DiskEntry->ExtendedPartition = PartEntry;
2414
2415 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2416 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2417 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2418 }
2419 else
2420 {
2421 DPRINT1("Add new partition entry\n");
2422
2423 /* Insert and initialize a new partition entry */
2424 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2425 HEAP_ZERO_MEMORY,
2426 sizeof(PARTENTRY));
2427 if (NewPartEntry == NULL)
2428 return;
2429
2430 /* Insert the new entry into the list */
2431 InsertTailList(&PartEntry->ListEntry,
2432 &NewPartEntry->ListEntry);
2433
2434 NewPartEntry->DiskEntry = DiskEntry;
2435
2436 NewPartEntry->IsPartitioned = TRUE;
2437 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2438 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2439 NewPartEntry->StartSector.QuadPart;
2440
2441 NewPartEntry->New = FALSE;
2442 NewPartEntry->FormatState = Formatted;
2443 NewPartEntry->BootIndicator = FALSE; /* FIXME */
2444
2445 if (NewPartEntry->StartSector.QuadPart < 1450560)
2446 {
2447 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2448 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2449 }
2450 else
2451 {
2452 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2453 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2454 }
2455
2456 DiskEntry->ExtendedPartition = NewPartEntry;
2457
2458 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2459 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2460
2461 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2462 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2463 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2464 }
2465
2466 AddLogicalDiskSpace(DiskEntry);
2467
2468 UpdateDiskLayout(DiskEntry);
2469
2470 DiskEntry->Dirty = TRUE;
2471
2472 UpdatePartitionNumbers(DiskEntry);
2473
2474 AssignDriveLetters(List);
2475 }
2476
2477
2478 VOID
2479 DeleteCurrentPartition(
2480 PPARTLIST List)
2481 {
2482 PDISKENTRY DiskEntry;
2483 PPARTENTRY PartEntry;
2484 PPARTENTRY PrevPartEntry;
2485 PPARTENTRY NextPartEntry;
2486 PPARTENTRY LogicalPartEntry;
2487 PLIST_ENTRY Entry;
2488
2489 if (List == NULL ||
2490 List->CurrentDisk == NULL ||
2491 List->CurrentPartition == NULL ||
2492 List->CurrentPartition->IsPartitioned == FALSE)
2493 {
2494 return;
2495 }
2496
2497 DiskEntry = List->CurrentDisk;
2498 PartEntry = List->CurrentPartition;
2499
2500 /* Delete all logical partiton entries if an extended partition will be deleted */
2501 if (DiskEntry->ExtendedPartition == PartEntry)
2502 {
2503 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2504 {
2505 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2506 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2507
2508 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2509 }
2510
2511 DiskEntry->ExtendedPartition = NULL;
2512 }
2513
2514 /* Adjust unpartitioned disk space entries */
2515
2516 /* Get pointer to previous and next unpartitioned entries */
2517 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2518 PartEntry);
2519
2520 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2521 PartEntry);
2522
2523 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2524 {
2525 /* Merge previous, current and next unpartitioned entry */
2526
2527 /* Adjust the previous entries length */
2528 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2529
2530 /* Remove the current entry */
2531 RemoveEntryList(&PartEntry->ListEntry);
2532 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2533
2534 /* Remove the next entry */
2535 RemoveEntryList (&NextPartEntry->ListEntry);
2536 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2537
2538 /* Update current partition */
2539 List->CurrentPartition = PrevPartEntry;
2540 }
2541 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2542 {
2543 /* Merge current and previous unpartitioned entry */
2544
2545 /* Adjust the previous entries length */
2546 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2547
2548 /* Remove the current entry */
2549 RemoveEntryList(&PartEntry->ListEntry);
2550 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2551
2552 /* Update current partition */
2553 List->CurrentPartition = PrevPartEntry;
2554 }
2555 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2556 {
2557 /* Merge current and next unpartitioned entry */
2558
2559 /* Adjust the next entries offset and length */
2560 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2561 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2562
2563 /* Remove the current entry */
2564 RemoveEntryList(&PartEntry->ListEntry);
2565 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2566
2567 /* Update current partition */
2568 List->CurrentPartition = NextPartEntry;
2569 }
2570 else
2571 {
2572 /* Nothing to merge but change current entry */
2573 PartEntry->IsPartitioned = FALSE;
2574 PartEntry->FormatState = Unformatted;
2575 PartEntry->DriveLetter = 0;
2576 }
2577
2578 UpdateDiskLayout(DiskEntry);
2579
2580 DiskEntry->Dirty = TRUE;
2581
2582 UpdatePartitionNumbers(DiskEntry);
2583
2584 AssignDriveLetters(List);
2585 }
2586
2587
2588 VOID
2589 CheckActiveBootPartition(
2590 PPARTLIST List)
2591 {
2592 PDISKENTRY DiskEntry;
2593 PPARTENTRY PartEntry;
2594 PLIST_ENTRY ListEntry;
2595
2596 /* Check for empty disk list */
2597 if (IsListEmpty (&List->DiskListHead))
2598 {
2599 List->ActiveBootDisk = NULL;
2600 List->ActiveBootPartition = NULL;
2601 return;
2602 }
2603
2604 #if 0
2605 if (List->ActiveBootDisk != NULL &&
2606 List->ActiveBootPartition != NULL)
2607 {
2608 /* We already have an active boot partition */
2609 return;
2610 }
2611 #endif
2612
2613 /* Choose the currently selected disk */
2614 DiskEntry = List->CurrentDisk;
2615
2616 /* Check for empty partition list */
2617 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2618 {
2619 List->ActiveBootDisk = NULL;
2620 List->ActiveBootPartition = NULL;
2621 return;
2622 }
2623
2624 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2625 PARTENTRY,
2626 ListEntry);
2627
2628 /* Set active boot partition */
2629 if ((DiskEntry->NewDisk == TRUE) ||
2630 (PartEntry->BootIndicator == FALSE))
2631 {
2632 PartEntry->BootIndicator = TRUE;
2633 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2634 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2635 DiskEntry->Dirty = TRUE;
2636
2637 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2638 List->ActiveBootDisk = DiskEntry;
2639 List->ActiveBootPartition = PartEntry;
2640
2641 return;
2642 }
2643
2644 /* Disk is not new, scan all partitions to find a bootable one */
2645 List->ActiveBootDisk = NULL;
2646 List->ActiveBootPartition = NULL;
2647
2648 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2649 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2650 {
2651 PartEntry = CONTAINING_RECORD(ListEntry,
2652 PARTENTRY,
2653 ListEntry);
2654
2655 /* Check if it is partitioned */
2656 if (PartEntry->IsPartitioned)
2657 {
2658 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2659 PartEntry->BootIndicator)
2660 {
2661 /* Yes, we found it */
2662 List->ActiveBootDisk = DiskEntry;
2663 List->ActiveBootPartition = PartEntry;
2664
2665 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2666 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2667 break;
2668 }
2669 }
2670
2671 /* Go to the next one */
2672 ListEntry = ListEntry->Flink;
2673 }
2674 }
2675
2676
2677 BOOLEAN
2678 CheckForLinuxFdiskPartitions(
2679 PPARTLIST List)
2680 {
2681 #if 0
2682 PDISKENTRY DiskEntry;
2683 PPARTENTRY PartEntry;
2684 PLIST_ENTRY Entry1;
2685 PLIST_ENTRY Entry2;
2686 ULONG PartitionCount;
2687 ULONG i;
2688
2689 Entry1 = List->DiskListHead.Flink;
2690 while (Entry1 != &List->DiskListHead)
2691 {
2692 DiskEntry = CONTAINING_RECORD(Entry1,
2693 DISKENTRY,
2694 ListEntry);
2695
2696 Entry2 = DiskEntry->PartListHead.Flink;
2697 while (Entry2 != &DiskEntry->PartListHead)
2698 {
2699 PartEntry = CONTAINING_RECORD(Entry2,
2700 PARTENTRY,
2701 ListEntry);
2702
2703 if (PartEntry->Unpartitioned == FALSE)
2704 {
2705 PartitionCount = 0;
2706
2707 for (i = 0; i < 4; i++)
2708 {
2709 if (!IsContainerPartition(PartEntry->PartInfo[i].PartitionType) &&
2710 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2711 {
2712 PartitionCount++;
2713 }
2714 }
2715
2716 if (PartitionCount > 1)
2717 {
2718 return TRUE;
2719 }
2720 }
2721
2722 Entry2 = Entry2->Flink;
2723 }
2724
2725 Entry1 = Entry1->Flink;
2726 }
2727 #endif
2728
2729 return FALSE;
2730 }
2731
2732
2733 static
2734 NTSTATUS
2735 WritePartitons(
2736 IN PPARTLIST List,
2737 IN PDISKENTRY DiskEntry)
2738 {
2739 WCHAR DstPath[MAX_PATH];
2740 OBJECT_ATTRIBUTES ObjectAttributes;
2741 IO_STATUS_BLOCK Iosb;
2742 UNICODE_STRING Name;
2743 ULONG BufferSize;
2744 HANDLE FileHandle = NULL;
2745 NTSTATUS Status;
2746
2747 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2748
2749 swprintf(DstPath,
2750 L"\\Device\\Harddisk%d\\Partition0",
2751 DiskEntry->DiskNumber);
2752 RtlInitUnicodeString(&Name,
2753 DstPath);
2754 InitializeObjectAttributes(&ObjectAttributes,
2755 &Name,
2756 0,
2757 NULL,
2758 NULL);
2759
2760 Status = NtOpenFile(&FileHandle,
2761 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2762 &ObjectAttributes,
2763 &Iosb,
2764 0,
2765 FILE_SYNCHRONOUS_IO_NONALERT);
2766 if (!NT_SUCCESS(Status))
2767 {
2768 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2769 return Status;
2770 }
2771
2772 #ifdef DUMP_PARTITION_TABLE
2773 DumpPartitionTable(DiskEntry);
2774 #endif
2775
2776 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2777 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2778 Status = NtDeviceIoControlFile(FileHandle,
2779 NULL,
2780 NULL,
2781 NULL,
2782 &Iosb,
2783 IOCTL_DISK_SET_DRIVE_LAYOUT,
2784 DiskEntry->LayoutBuffer,
2785 BufferSize,
2786 NULL,
2787 0);
2788 if (!NT_SUCCESS(Status))
2789 {
2790 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2791 }
2792
2793 if (FileHandle != NULL)
2794 NtClose(FileHandle);
2795
2796 return Status;
2797 }
2798
2799
2800 BOOLEAN
2801 WritePartitionsToDisk(
2802 PPARTLIST List)
2803 {
2804 PLIST_ENTRY Entry;
2805 PDISKENTRY DiskEntry;
2806
2807 if (List == NULL)
2808 return TRUE;
2809
2810 Entry = List->DiskListHead.Flink;
2811 while (Entry != &List->DiskListHead)
2812 {
2813 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2814
2815 if (DiskEntry->Dirty == TRUE)
2816 {
2817 WritePartitons(List, DiskEntry);
2818 }
2819
2820 Entry = Entry->Flink;
2821 }
2822
2823 return TRUE;
2824 }
2825
2826
2827 BOOL
2828 SetMountedDeviceValues(
2829 PPARTLIST List)
2830 {
2831 PLIST_ENTRY Entry1, Entry2;
2832 PDISKENTRY DiskEntry;
2833 PPARTENTRY PartEntry;
2834 LARGE_INTEGER StartingOffset;
2835
2836 if (List == NULL)
2837 {
2838 return FALSE;
2839 }
2840
2841 Entry1 = List->DiskListHead.Flink;
2842 while (Entry1 != &List->DiskListHead)
2843 {
2844 DiskEntry = CONTAINING_RECORD(Entry1,
2845 DISKENTRY,
2846 ListEntry);
2847
2848 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2849 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2850 {
2851 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2852 if (PartEntry->IsPartitioned)
2853 {
2854 if (PartEntry->DriveLetter)
2855 {
2856 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2857 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
2858 DiskEntry->LayoutBuffer->Signature,
2859 StartingOffset))
2860 {
2861 return FALSE;
2862 }
2863 }
2864 }
2865
2866 Entry2 = Entry2->Flink;
2867 }
2868
2869 Entry1 = Entry1->Flink;
2870 }
2871
2872 return TRUE;
2873 }
2874
2875
2876 static
2877 BOOLEAN
2878 IsLastPrimaryPartiton(
2879 IN PPARTENTRY PartEntry)
2880 {
2881 return (PartEntry->ListEntry.Flink == &PartEntry->DiskEntry->PrimaryPartListHead);
2882 }
2883
2884
2885 static
2886 BOOLEAN
2887 IsPreviousPartitionExtended(
2888 IN PPARTENTRY PartEntry,
2889 IN PDISKENTRY DiskEntry)
2890 {
2891 PPARTENTRY PrevPartEntry;
2892 PLIST_ENTRY Entry;
2893
2894 Entry = PartEntry->ListEntry.Blink;
2895
2896 while (Entry != &DiskEntry->PrimaryPartListHead)
2897 {
2898 PrevPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2899
2900 if (IsContainerPartition(PrevPartEntry->PartitionType))
2901 return TRUE;
2902
2903 Entry = Entry->Blink;
2904 }
2905
2906 return FALSE;
2907
2908 }
2909
2910
2911 static
2912 ULONG
2913 GetPrimaryPartitionCount(
2914 IN PDISKENTRY DiskEntry)
2915 {
2916 PLIST_ENTRY Entry;
2917 PPARTENTRY PartEntry;
2918 UINT nCount = 0;
2919
2920 Entry = DiskEntry->PrimaryPartListHead.Flink;
2921 while (Entry != &DiskEntry->PrimaryPartListHead)
2922 {
2923 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2924 if (PartEntry->IsPartitioned == TRUE)
2925 nCount++;
2926
2927 Entry = Entry->Flink;
2928 }
2929
2930 return nCount;
2931 }
2932
2933
2934 ULONG
2935 PrimaryPartitionCreationChecks(
2936 IN PPARTLIST List)
2937 {
2938 PDISKENTRY DiskEntry;
2939 PPARTENTRY PartEntry;
2940
2941 DiskEntry = List->CurrentDisk;
2942 PartEntry = List->CurrentPartition;
2943
2944 /* Fail if partition is already in use */
2945 if (PartEntry->IsPartitioned == TRUE)
2946 return ERROR_NEW_PARTITION;
2947
2948 /* Fail if there are more than 4 partitions in the list */
2949 if (GetPrimaryPartitionCount(DiskEntry) > 4)
2950 return ERROR_PARTITION_TABLE_FULL;
2951
2952 /* Fail if this partiton is located behind an extended partition */
2953 if (IsPreviousPartitionExtended(PartEntry, DiskEntry))
2954 return ERROR_NOT_BEHIND_EXTENDED;
2955
2956 return ERROR_SUCCESS;
2957 }
2958
2959
2960 ULONG
2961 ExtendedPartitionCreationChecks(
2962 IN PPARTLIST List)
2963 {
2964 PDISKENTRY DiskEntry;
2965 PPARTENTRY PartEntry;
2966
2967 DiskEntry = List->CurrentDisk;
2968 PartEntry = List->CurrentPartition;
2969
2970 /* Fail if partition is already in use */
2971 if (PartEntry->IsPartitioned == TRUE)
2972 return ERROR_NEW_PARTITION;
2973
2974 /* Fail if there are more than 4 partitions in the list */
2975 if (GetPrimaryPartitionCount(DiskEntry) > 4)
2976 return ERROR_PARTITION_TABLE_FULL;
2977
2978 /* Fail if there is another extended partition in the list */
2979 if (DiskEntry->ExtendedPartition != NULL)
2980 return ERROR_ONLY_ONE_EXTENDED;
2981
2982 /* Fail if the partition is not the last list entry */
2983 if (!IsLastPrimaryPartiton(PartEntry))
2984 return ERROR_EXTENDED_NOT_LAST;
2985
2986 return ERROR_SUCCESS;
2987 }
2988
2989 /* EOF */