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