[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
978 Status = NtDeviceIoControlFile(FileHandle,
979 NULL,
980 NULL,
981 NULL,
982 &Iosb,
983 IOCTL_DISK_GET_DRIVE_GEOMETRY,
984 NULL,
985 0,
986 &DiskGeometry,
987 sizeof(DISK_GEOMETRY));
988 if (!NT_SUCCESS(Status))
989 {
990 return;
991 }
992
993 if (DiskGeometry.MediaType != FixedMedia &&
994 DiskGeometry.MediaType != RemovableMedia)
995 {
996 return;
997 }
998
999 Status = NtDeviceIoControlFile(FileHandle,
1000 NULL,
1001 NULL,
1002 NULL,
1003 &Iosb,
1004 IOCTL_SCSI_GET_ADDRESS,
1005 NULL,
1006 0,
1007 &ScsiAddress,
1008 sizeof(SCSI_ADDRESS));
1009 if (!NT_SUCCESS(Status))
1010 {
1011 return;
1012 }
1013
1014 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1015 0,
1016 DiskGeometry.BytesPerSector);
1017 if (Mbr == NULL)
1018 {
1019 return;
1020 }
1021
1022 FileOffset.QuadPart = 0;
1023 Status = NtReadFile(FileHandle,
1024 NULL,
1025 NULL,
1026 NULL,
1027 &Iosb,
1028 (PVOID)Mbr,
1029 DiskGeometry.BytesPerSector,
1030 &FileOffset,
1031 NULL);
1032 if (!NT_SUCCESS(Status))
1033 {
1034 RtlFreeHeap(ProcessHeap,
1035 0,
1036 Mbr);
1037 DPRINT1("NtReadFile failed, status=%x\n", Status);
1038 return;
1039 }
1040 Signature = Mbr->Signature;
1041
1042 /* Calculate the MBR checksum */
1043 Checksum = 0;
1044 Buffer = (PULONG)Mbr;
1045 for (i = 0; i < 128; i++)
1046 {
1047 Checksum += Buffer[i];
1048 }
1049 Checksum = ~Checksum + 1;
1050
1051 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
1052 DPRINT("Identifier: %S\n", Identifier);
1053
1054 DiskEntry = RtlAllocateHeap(ProcessHeap,
1055 HEAP_ZERO_MEMORY,
1056 sizeof(DISKENTRY));
1057 if (DiskEntry == NULL)
1058 {
1059 return;
1060 }
1061
1062 // DiskEntry->Checksum = Checksum;
1063 // DiskEntry->Signature = Signature;
1064 DiskEntry->BiosFound = FALSE;
1065
1066 /* Check if this disk has a valid MBR */
1067 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
1068 DiskEntry->NoMbr = TRUE;
1069 else
1070 DiskEntry->NoMbr = FALSE;
1071
1072 /* Free Mbr sector buffer */
1073 RtlFreeHeap(ProcessHeap,
1074 0,
1075 Mbr);
1076
1077 ListEntry = List->BiosDiskListHead.Flink;
1078 while(ListEntry != &List->BiosDiskListHead)
1079 {
1080 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1081 /* FIXME:
1082 * Compare the size from bios and the reported size from driver.
1083 * If we have more than one disk with a zero or with the same signatur
1084 * we must create new signatures and reboot. After the reboot,
1085 * it is possible to identify the disks.
1086 */
1087 if (BiosDiskEntry->Signature == Signature &&
1088 BiosDiskEntry->Checksum == Checksum &&
1089 !BiosDiskEntry->Recognized)
1090 {
1091 if (!DiskEntry->BiosFound)
1092 {
1093 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1094 DiskEntry->BiosFound = TRUE;
1095 BiosDiskEntry->Recognized = TRUE;
1096 }
1097 else
1098 {
1099 }
1100 }
1101 ListEntry = ListEntry->Flink;
1102 }
1103
1104 if (!DiskEntry->BiosFound)
1105 {
1106 #if 0
1107 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1108 return;
1109 #else
1110 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1111 #endif
1112 }
1113
1114 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1115 InitializeListHead(&DiskEntry->LogicalPartListHead);
1116
1117 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1118 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1119 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1120 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1121
1122 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1123 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
1124 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
1125 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
1126
1127 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1128 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1129 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1130
1131 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1132
1133 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount);
1134 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1135
1136 DiskEntry->DiskNumber = DiskNumber;
1137 DiskEntry->Port = ScsiAddress.PortNumber;
1138 DiskEntry->Bus = ScsiAddress.PathId;
1139 DiskEntry->Id = ScsiAddress.TargetId;
1140
1141 GetDriverName(DiskEntry);
1142
1143 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1144
1145 /* Allocate a layout buffer with 4 partition entries first */
1146 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1147 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1148 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1149 HEAP_ZERO_MEMORY,
1150 LayoutBufferSize);
1151 if (DiskEntry->LayoutBuffer == NULL)
1152 {
1153 return;
1154 }
1155
1156 Status = NtDeviceIoControlFile(FileHandle,
1157 NULL,
1158 NULL,
1159 NULL,
1160 &Iosb,
1161 IOCTL_DISK_GET_DRIVE_LAYOUT,
1162 NULL,
1163 0,
1164 DiskEntry->LayoutBuffer,
1165 LayoutBufferSize);
1166 DPRINT("Status: 0x%08lx\n", Status);
1167 DPRINT("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1168
1169 /* If we need more than 4 partition entries, reallocte the buffer and
1170 retrieve the disk layout again */
1171 if (!NT_SUCCESS(Status) && DiskEntry->LayoutBuffer->PartitionCount > 4)
1172 {
1173 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1174 ((DiskEntry->LayoutBuffer->PartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1175 DiskEntry->LayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1176 HEAP_ZERO_MEMORY,
1177 DiskEntry->LayoutBuffer,
1178 LayoutBufferSize);
1179 if (DiskEntry->LayoutBuffer == NULL)
1180 {
1181 return;
1182 }
1183
1184 Status = NtDeviceIoControlFile(FileHandle,
1185 NULL,
1186 NULL,
1187 NULL,
1188 &Iosb,
1189 IOCTL_DISK_GET_DRIVE_LAYOUT,
1190 NULL,
1191 0,
1192 DiskEntry->LayoutBuffer,
1193 LayoutBufferSize);
1194 }
1195
1196 if (NT_SUCCESS(Status))
1197 {
1198 #ifdef DUMP_PARTITION_TABLE
1199 DumpPartitionTable(DiskEntry);
1200 #endif
1201
1202 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1203 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1204 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
1205 {
1206 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1207 {
1208 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1209 }
1210 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1211 {
1212 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1213 }
1214 else
1215 {
1216 DPRINT1("No matching aligment found! Partiton 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1217 }
1218 }
1219 else
1220 {
1221 DPRINT1("No valid partiton table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1222 }
1223
1224
1225 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1226 {
1227 DiskEntry->NewDisk = TRUE;
1228 DiskEntry->LayoutBuffer->PartitionCount = 4;
1229
1230 for (i = 0; i < 4; i++)
1231 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1232 }
1233 else
1234 {
1235 for (i = 0; i < 4; i++)
1236 {
1237 AddPartitionToDisk(DiskNumber,
1238 DiskEntry,
1239 i,
1240 FALSE);
1241 }
1242
1243 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1244 {
1245 AddPartitionToDisk(DiskNumber,
1246 DiskEntry,
1247 i,
1248 TRUE);
1249 }
1250 }
1251 }
1252
1253 ScanForUnpartitionedDiskSpace(DiskEntry);
1254 }
1255
1256
1257 PPARTLIST
1258 CreatePartitionList(
1259 SHORT Left,
1260 SHORT Top,
1261 SHORT Right,
1262 SHORT Bottom)
1263 {
1264 PPARTLIST List;
1265 OBJECT_ATTRIBUTES ObjectAttributes;
1266 SYSTEM_DEVICE_INFORMATION Sdi;
1267 IO_STATUS_BLOCK Iosb;
1268 ULONG ReturnSize;
1269 NTSTATUS Status;
1270 ULONG DiskNumber;
1271 WCHAR Buffer[MAX_PATH];
1272 UNICODE_STRING Name;
1273 HANDLE FileHandle;
1274
1275 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1276 0,
1277 sizeof (PARTLIST));
1278 if (List == NULL)
1279 return NULL;
1280
1281 List->Left = Left;
1282 List->Top = Top;
1283 List->Right = Right;
1284 List->Bottom = Bottom;
1285
1286 List->Line = 0;
1287 List->Offset = 0;
1288
1289 List->TopDisk = (ULONG)-1;
1290 List->TopPartition = (ULONG)-1;
1291
1292 List->CurrentDisk = NULL;
1293 List->CurrentPartition = NULL;
1294
1295 List->BootDisk = NULL;
1296 List->BootPartition = NULL;
1297
1298 List->TempDisk = NULL;
1299 List->TempPartition = NULL;
1300 List->FormatState = Start;
1301
1302 InitializeListHead(&List->DiskListHead);
1303 InitializeListHead(&List->BiosDiskListHead);
1304
1305 EnumerateBiosDiskEntries(List);
1306
1307 Status = NtQuerySystemInformation(SystemDeviceInformation,
1308 &Sdi,
1309 sizeof(SYSTEM_DEVICE_INFORMATION),
1310 &ReturnSize);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 RtlFreeHeap(ProcessHeap, 0, List);
1314 return NULL;
1315 }
1316
1317 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1318 {
1319 swprintf(Buffer,
1320 L"\\Device\\Harddisk%d\\Partition0",
1321 DiskNumber);
1322 RtlInitUnicodeString(&Name,
1323 Buffer);
1324
1325 InitializeObjectAttributes(&ObjectAttributes,
1326 &Name,
1327 0,
1328 NULL,
1329 NULL);
1330
1331 Status = NtOpenFile(&FileHandle,
1332 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1333 &ObjectAttributes,
1334 &Iosb,
1335 FILE_SHARE_READ,
1336 FILE_SYNCHRONOUS_IO_NONALERT);
1337 if (NT_SUCCESS(Status))
1338 {
1339 AddDiskToList(FileHandle,
1340 DiskNumber,
1341 List);
1342
1343 NtClose(FileHandle);
1344 }
1345 }
1346
1347 UpdateDiskSignatures(List);
1348
1349 AssignDriveLetters(List);
1350
1351 List->TopDisk = 0;
1352 List->TopPartition = 0;
1353
1354 /* Search for first usable disk and partition */
1355 if (IsListEmpty(&List->DiskListHead))
1356 {
1357 List->CurrentDisk = NULL;
1358 List->CurrentPartition = NULL;
1359 }
1360 else
1361 {
1362 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1363 DISKENTRY,
1364 ListEntry);
1365
1366 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1367 {
1368 List->CurrentPartition = 0;
1369 }
1370 else
1371 {
1372 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1373 PARTENTRY,
1374 ListEntry);
1375 }
1376 }
1377
1378 return List;
1379 }
1380
1381
1382 VOID
1383 DestroyPartitionList(
1384 PPARTLIST List)
1385 {
1386 PDISKENTRY DiskEntry;
1387 PBIOSDISKENTRY BiosDiskEntry;
1388 PPARTENTRY PartEntry;
1389 PLIST_ENTRY Entry;
1390
1391 /* Release disk and partition info */
1392 while (!IsListEmpty(&List->DiskListHead))
1393 {
1394 Entry = RemoveHeadList(&List->DiskListHead);
1395 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1396
1397 /* Release driver name */
1398 RtlFreeUnicodeString(&DiskEntry->DriverName);
1399
1400 /* Release primary partition list */
1401 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1402 {
1403 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1404 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1405
1406 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1407 }
1408
1409 /* Release logical partition list */
1410 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1411 {
1412 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1413 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1414
1415 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1416 }
1417
1418 /* Release layout buffer */
1419 if (DiskEntry->LayoutBuffer != NULL)
1420 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1421
1422
1423 /* Release disk entry */
1424 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1425 }
1426
1427 /* release the bios disk info */
1428 while(!IsListEmpty(&List->BiosDiskListHead))
1429 {
1430 Entry = RemoveHeadList(&List->BiosDiskListHead);
1431 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1432
1433 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1434 }
1435
1436 /* Release list head */
1437 RtlFreeHeap(ProcessHeap, 0, List);
1438 }
1439
1440
1441 static
1442 VOID
1443 PrintEmptyLine(
1444 PPARTLIST List)
1445 {
1446 COORD coPos;
1447 DWORD Written;
1448 USHORT Width;
1449 USHORT Height;
1450
1451 Width = List->Right - List->Left - 1;
1452 Height = List->Bottom - List->Top - 2;
1453
1454 coPos.X = List->Left + 1;
1455 coPos.Y = List->Top + 1 + List->Line;
1456
1457 if (List->Line >= 0 && List->Line <= Height)
1458 {
1459 FillConsoleOutputAttribute(StdOutput,
1460 FOREGROUND_WHITE | BACKGROUND_BLUE,
1461 Width,
1462 coPos,
1463 &Written);
1464
1465 FillConsoleOutputCharacterA(StdOutput,
1466 ' ',
1467 Width,
1468 coPos,
1469 &Written);
1470 }
1471
1472 List->Line++;
1473 }
1474
1475
1476 static
1477 VOID
1478 PrintPartitionData(
1479 PPARTLIST List,
1480 PDISKENTRY DiskEntry,
1481 PPARTENTRY PartEntry)
1482 {
1483 CHAR LineBuffer[128];
1484 COORD coPos;
1485 DWORD Written;
1486 USHORT Width;
1487 USHORT Height;
1488 LARGE_INTEGER PartSize;
1489 PCHAR Unit;
1490 UCHAR Attribute;
1491 PCHAR PartType;
1492
1493 Width = List->Right - List->Left - 1;
1494 Height = List->Bottom - List->Top - 2;
1495
1496 coPos.X = List->Left + 1;
1497 coPos.Y = List->Top + 1 + List->Line;
1498
1499 if (PartEntry->IsPartitioned == FALSE)
1500 {
1501 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1502 #if 0
1503 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1504 {
1505 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1506 Unit = MUIGetString(STRING_GB);
1507 }
1508 else
1509 #endif
1510 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1511 {
1512 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1513 Unit = MUIGetString(STRING_MB);
1514 }
1515 else
1516 {
1517 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1518 Unit = MUIGetString(STRING_KB);
1519 }
1520
1521 sprintf(LineBuffer,
1522 MUIGetString(STRING_UNPSPACE),
1523 PartEntry->LogicalPartition ? " " : "",
1524 PartEntry->LogicalPartition ? "" : " ",
1525 PartSize.u.LowPart,
1526 Unit);
1527 }
1528 else
1529 {
1530 /* Determine partition type */
1531 PartType = NULL;
1532 if (PartEntry->New == TRUE)
1533 {
1534 PartType = MUIGetString(STRING_UNFORMATTED);
1535 }
1536 else if (PartEntry->IsPartitioned == TRUE)
1537 {
1538 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
1539 (PartEntry->PartitionType == PARTITION_FAT_16) ||
1540 (PartEntry->PartitionType == PARTITION_HUGE) ||
1541 (PartEntry->PartitionType == PARTITION_XINT13))
1542 {
1543 PartType = "FAT";
1544 }
1545 else if ((PartEntry->PartitionType == PARTITION_FAT32) ||
1546 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
1547 {
1548 PartType = "FAT32";
1549 }
1550 else if (PartEntry->PartitionType == PARTITION_EXT2)
1551 {
1552 PartType = "EXT2";
1553 }
1554 else if (PartEntry->PartitionType == PARTITION_IFS)
1555 {
1556 PartType = "NTFS"; /* FIXME: Not quite correct! */
1557 }
1558 else if ((PartEntry->PartitionType == PARTITION_EXTENDED) ||
1559 (PartEntry->PartitionType == PARTITION_XINT13_EXTENDED))
1560 {
1561 PartType = MUIGetString(STRING_EXTENDED_PARTITION);
1562 }
1563 }
1564
1565 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1566 #if 0
1567 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1568 {
1569 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1570 Unit = MUIGetString(STRING_GB);
1571 }
1572 else
1573 #endif
1574 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1575 {
1576 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1577 Unit = MUIGetString(STRING_MB);
1578 }
1579 else
1580 {
1581 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1582 Unit = MUIGetString(STRING_KB);
1583 }
1584
1585 if (PartType == NULL)
1586 {
1587 sprintf(LineBuffer,
1588 MUIGetString(STRING_HDDINFOUNK5),
1589 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1590 (PartEntry->DriveLetter == 0) ? '-' : ':',
1591 PartEntry->BootIndicator ? '*' : ' ',
1592 PartEntry->LogicalPartition ? " " : "",
1593 PartEntry->PartitionType,
1594 PartEntry->LogicalPartition ? "" : " ",
1595 PartSize.u.LowPart,
1596 Unit);
1597 }
1598 else
1599 {
1600 sprintf(LineBuffer,
1601 "%c%c %c %s%-24s%s %6lu %s",
1602 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1603 (PartEntry->DriveLetter == 0) ? '-' : ':',
1604 PartEntry->BootIndicator ? '*' : ' ',
1605 PartEntry->LogicalPartition ? " " : "",
1606 PartType,
1607 PartEntry->LogicalPartition ? "" : " ",
1608 PartSize.u.LowPart,
1609 Unit);
1610 }
1611 }
1612
1613 Attribute = (List->CurrentDisk == DiskEntry &&
1614 List->CurrentPartition == PartEntry) ?
1615 FOREGROUND_BLUE | BACKGROUND_WHITE :
1616 FOREGROUND_WHITE | BACKGROUND_BLUE;
1617
1618 if (List->Line >= 0 && List->Line <= Height)
1619 {
1620 FillConsoleOutputCharacterA(StdOutput,
1621 ' ',
1622 Width,
1623 coPos,
1624 &Written);
1625 }
1626 coPos.X += 4;
1627 Width -= 8;
1628 if (List->Line >= 0 && List->Line <= Height)
1629 {
1630 FillConsoleOutputAttribute(StdOutput,
1631 Attribute,
1632 Width,
1633 coPos,
1634 &Written);
1635 }
1636 coPos.X++;
1637 Width -= 2;
1638 if (List->Line >= 0 && List->Line <= Height)
1639 {
1640 WriteConsoleOutputCharacterA(StdOutput,
1641 LineBuffer,
1642 min(strlen(LineBuffer), Width),
1643 coPos,
1644 &Written);
1645 }
1646
1647 List->Line++;
1648 }
1649
1650
1651 static
1652 VOID
1653 PrintDiskData(
1654 PPARTLIST List,
1655 PDISKENTRY DiskEntry)
1656 {
1657 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1658 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1659 CHAR LineBuffer[128];
1660 COORD coPos;
1661 DWORD Written;
1662 USHORT Width;
1663 USHORT Height;
1664 ULARGE_INTEGER DiskSize;
1665 PCHAR Unit;
1666
1667 Width = List->Right - List->Left - 1;
1668 Height = List->Bottom - List->Top - 2;
1669
1670 coPos.X = List->Left + 1;
1671 coPos.Y = List->Top + 1 + List->Line;
1672
1673 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1674 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1675 {
1676 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1677 Unit = MUIGetString(STRING_GB);
1678 }
1679 else
1680 {
1681 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1682 if (DiskSize.QuadPart == 0)
1683 DiskSize.QuadPart = 1;
1684 Unit = MUIGetString(STRING_MB);
1685 }
1686
1687 if (DiskEntry->DriverName.Length > 0)
1688 {
1689 sprintf(LineBuffer,
1690 MUIGetString(STRING_HDINFOPARTSELECT),
1691 DiskSize.u.LowPart,
1692 Unit,
1693 DiskEntry->DiskNumber,
1694 DiskEntry->Port,
1695 DiskEntry->Bus,
1696 DiskEntry->Id,
1697 DiskEntry->DriverName.Buffer);
1698 }
1699 else
1700 {
1701 sprintf(LineBuffer,
1702 MUIGetString(STRING_HDDINFOUNK6),
1703 DiskSize.u.LowPart,
1704 Unit,
1705 DiskEntry->DiskNumber,
1706 DiskEntry->Port,
1707 DiskEntry->Bus,
1708 DiskEntry->Id);
1709 }
1710
1711 if (List->Line >= 0 && List->Line <= Height)
1712 {
1713 FillConsoleOutputAttribute(StdOutput,
1714 FOREGROUND_WHITE | BACKGROUND_BLUE,
1715 Width,
1716 coPos,
1717 &Written);
1718
1719 FillConsoleOutputCharacterA(StdOutput,
1720 ' ',
1721 Width,
1722 coPos,
1723 &Written);
1724 }
1725
1726 coPos.X++;
1727 if (List->Line >= 0 && List->Line <= Height)
1728 {
1729 WriteConsoleOutputCharacterA(StdOutput,
1730 LineBuffer,
1731 min((USHORT)strlen(LineBuffer), Width - 2),
1732 coPos,
1733 &Written);
1734 }
1735
1736 List->Line++;
1737
1738 /* Print separator line */
1739 PrintEmptyLine(List);
1740
1741 /* Print partition lines*/
1742 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1743 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1744 {
1745 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1746
1747 PrintPartitionData(List,
1748 DiskEntry,
1749 PrimaryPartEntry);
1750
1751 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1752 {
1753 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1754 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1755 {
1756 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1757
1758 PrintPartitionData(List,
1759 DiskEntry,
1760 LogicalPartEntry);
1761
1762 LogicalEntry = LogicalEntry->Flink;
1763 }
1764 }
1765
1766 PrimaryEntry = PrimaryEntry->Flink;
1767 }
1768
1769 /* Print separator line */
1770 PrintEmptyLine(List);
1771 }
1772
1773
1774 VOID
1775 DrawPartitionList(
1776 PPARTLIST List)
1777 {
1778 PLIST_ENTRY Entry, Entry2;
1779 PDISKENTRY DiskEntry;
1780 PPARTENTRY PartEntry = NULL;
1781 COORD coPos;
1782 DWORD Written;
1783 SHORT i;
1784 SHORT CurrentDiskLine;
1785 SHORT CurrentPartLine;
1786 SHORT LastLine;
1787 BOOL CurrentPartLineFound = FALSE;
1788 BOOL CurrentDiskLineFound = FALSE;
1789
1790 /* Calculate the line of the current disk and partition */
1791 CurrentDiskLine = 0;
1792 CurrentPartLine = 0;
1793 LastLine = 0;
1794
1795 Entry = List->DiskListHead.Flink;
1796 while (Entry != &List->DiskListHead)
1797 {
1798 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1799
1800 LastLine += 2;
1801 if (CurrentPartLineFound == FALSE)
1802 {
1803 CurrentPartLine += 2;
1804 }
1805
1806 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1807 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1808 {
1809 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1810 if (PartEntry == List->CurrentPartition)
1811 {
1812 CurrentPartLineFound = TRUE;
1813 }
1814
1815 Entry2 = Entry2->Flink;
1816 if (CurrentPartLineFound == FALSE)
1817 {
1818 CurrentPartLine++;
1819 }
1820
1821 LastLine++;
1822 }
1823
1824 if (DiskEntry == List->CurrentDisk)
1825 {
1826 CurrentDiskLineFound = TRUE;
1827 }
1828
1829 Entry = Entry->Flink;
1830 if (Entry != &List->DiskListHead)
1831 {
1832 if (CurrentDiskLineFound == FALSE)
1833 {
1834 CurrentPartLine ++;
1835 CurrentDiskLine = CurrentPartLine;
1836 }
1837
1838 LastLine++;
1839 }
1840 else
1841 {
1842 LastLine--;
1843 }
1844 }
1845
1846 /* If it possible, make the disk name visible */
1847 if (CurrentPartLine < List->Offset)
1848 {
1849 List->Offset = CurrentPartLine;
1850 }
1851 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1852 {
1853 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1854 }
1855
1856 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1857 {
1858 List->Offset = CurrentDiskLine;
1859 }
1860
1861 /* draw upper left corner */
1862 coPos.X = List->Left;
1863 coPos.Y = List->Top;
1864 FillConsoleOutputCharacterA(StdOutput,
1865 0xDA, // '+',
1866 1,
1867 coPos,
1868 &Written);
1869
1870 /* draw upper edge */
1871 coPos.X = List->Left + 1;
1872 coPos.Y = List->Top;
1873 if (List->Offset == 0)
1874 {
1875 FillConsoleOutputCharacterA(StdOutput,
1876 0xC4, // '-',
1877 List->Right - List->Left - 1,
1878 coPos,
1879 &Written);
1880 }
1881 else
1882 {
1883 FillConsoleOutputCharacterA(StdOutput,
1884 0xC4, // '-',
1885 List->Right - List->Left - 5,
1886 coPos,
1887 &Written);
1888 coPos.X = List->Right - 5;
1889 WriteConsoleOutputCharacterA(StdOutput,
1890 "(\x18)", // "(up)"
1891 3,
1892 coPos,
1893 &Written);
1894 coPos.X = List->Right - 2;
1895 FillConsoleOutputCharacterA(StdOutput,
1896 0xC4, // '-',
1897 2,
1898 coPos,
1899 &Written);
1900 }
1901
1902 /* draw upper right corner */
1903 coPos.X = List->Right;
1904 coPos.Y = List->Top;
1905 FillConsoleOutputCharacterA(StdOutput,
1906 0xBF, // '+',
1907 1,
1908 coPos,
1909 &Written);
1910
1911 /* draw left and right edge */
1912 for (i = List->Top + 1; i < List->Bottom; i++)
1913 {
1914 coPos.X = List->Left;
1915 coPos.Y = i;
1916 FillConsoleOutputCharacterA(StdOutput,
1917 0xB3, // '|',
1918 1,
1919 coPos,
1920 &Written);
1921
1922 coPos.X = List->Right;
1923 FillConsoleOutputCharacterA(StdOutput,
1924 0xB3, //'|',
1925 1,
1926 coPos,
1927 &Written);
1928 }
1929
1930 /* draw lower left corner */
1931 coPos.X = List->Left;
1932 coPos.Y = List->Bottom;
1933 FillConsoleOutputCharacterA(StdOutput,
1934 0xC0, // '+',
1935 1,
1936 coPos,
1937 &Written);
1938
1939 /* draw lower edge */
1940 coPos.X = List->Left + 1;
1941 coPos.Y = List->Bottom;
1942 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1943 {
1944 FillConsoleOutputCharacterA(StdOutput,
1945 0xC4, // '-',
1946 List->Right - List->Left - 1,
1947 coPos,
1948 &Written);
1949 }
1950 else
1951 {
1952 FillConsoleOutputCharacterA(StdOutput,
1953 0xC4, // '-',
1954 List->Right - List->Left - 5,
1955 coPos,
1956 &Written);
1957 coPos.X = List->Right - 5;
1958 WriteConsoleOutputCharacterA(StdOutput,
1959 "(\x19)", // "(down)"
1960 3,
1961 coPos,
1962 &Written);
1963 coPos.X = List->Right - 2;
1964 FillConsoleOutputCharacterA(StdOutput,
1965 0xC4, // '-',
1966 2,
1967 coPos,
1968 &Written);
1969 }
1970
1971 /* draw lower right corner */
1972 coPos.X = List->Right;
1973 coPos.Y = List->Bottom;
1974 FillConsoleOutputCharacterA(StdOutput,
1975 0xD9, // '+',
1976 1,
1977 coPos,
1978 &Written);
1979
1980 /* print list entries */
1981 List->Line = - List->Offset;
1982
1983 Entry = List->DiskListHead.Flink;
1984 while (Entry != &List->DiskListHead)
1985 {
1986 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1987
1988 /* Print disk entry */
1989 PrintDiskData(List,
1990 DiskEntry);
1991
1992 Entry = Entry->Flink;
1993 }
1994 }
1995
1996
1997 DWORD
1998 SelectPartition(
1999 PPARTLIST List,
2000 ULONG DiskNumber,
2001 ULONG PartitionNumber)
2002 {
2003 PDISKENTRY DiskEntry;
2004 PPARTENTRY PartEntry;
2005 PLIST_ENTRY Entry1;
2006 PLIST_ENTRY Entry2;
2007
2008 /* Check for empty disks */
2009 if (IsListEmpty(&List->DiskListHead))
2010 return FALSE;
2011
2012 /* Check for first usable entry on next disk */
2013 Entry1 = List->CurrentDisk->ListEntry.Flink;
2014 while (Entry1 != &List->DiskListHead)
2015 {
2016 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
2017
2018 if (DiskEntry->DiskNumber == DiskNumber)
2019 {
2020 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2021 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2022 {
2023 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2024
2025 if (PartEntry->PartitionNumber == PartitionNumber)
2026 {
2027 List->CurrentDisk = DiskEntry;
2028 List->CurrentPartition = PartEntry;
2029 DrawPartitionList(List);
2030 return TRUE;
2031 }
2032
2033 Entry2 = Entry2->Flink;
2034 }
2035
2036 return FALSE;
2037 }
2038
2039 Entry1 = Entry1->Flink;
2040 }
2041
2042 return FALSE;
2043 }
2044
2045
2046 BOOL
2047 ScrollDownPartitionList(
2048 PPARTLIST List)
2049 {
2050 PLIST_ENTRY DiskListEntry;
2051 PLIST_ENTRY PartListEntry;
2052 PDISKENTRY DiskEntry;
2053 PPARTENTRY PartEntry;
2054
2055 /* Fail, if no disks are available */
2056 if (IsListEmpty(&List->DiskListHead))
2057 return FALSE;
2058
2059 /* Check for next usable entry on current disk */
2060 if (List->CurrentPartition != NULL)
2061 {
2062 if (List->CurrentPartition->LogicalPartition)
2063 {
2064 /* Logical partition */
2065
2066 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2067 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2068 {
2069 /* Next logical partition */
2070 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2071
2072 List->CurrentPartition = PartEntry;
2073 return TRUE;
2074 }
2075 else
2076 {
2077 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2078 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2079 {
2080 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2081
2082 List->CurrentPartition = PartEntry;
2083 return TRUE;
2084 }
2085 }
2086 }
2087 else
2088 {
2089 /* Primary or extended partition */
2090
2091 if (List->CurrentPartition->IsPartitioned == TRUE &&
2092 IsContainerPartition(List->CurrentPartition->PartitionType))
2093 {
2094 /* First logical partition */
2095 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2096 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2097 {
2098 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2099
2100 List->CurrentPartition = PartEntry;
2101 return TRUE;
2102 }
2103 }
2104 else
2105 {
2106 /* Next primary partition */
2107 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2108 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2109 {
2110 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2111
2112 List->CurrentPartition = PartEntry;
2113 return TRUE;
2114 }
2115 }
2116 }
2117 }
2118
2119 /* Search for the first partition entry on the next disk */
2120 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2121 while (DiskListEntry != &List->DiskListHead)
2122 {
2123 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2124
2125 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2126 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2127 {
2128 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2129
2130 List->CurrentDisk = DiskEntry;
2131 List->CurrentPartition = PartEntry;
2132 return TRUE;
2133 }
2134
2135 DiskListEntry = DiskListEntry->Flink;
2136 }
2137
2138 return FALSE;
2139 }
2140
2141
2142 BOOL
2143 ScrollUpPartitionList(
2144 PPARTLIST List)
2145 {
2146 PLIST_ENTRY DiskListEntry;
2147 PLIST_ENTRY PartListEntry;
2148 PDISKENTRY DiskEntry;
2149 PPARTENTRY PartEntry;
2150
2151 /* Fail, if no disks are available */
2152 if (IsListEmpty(&List->DiskListHead))
2153 return FALSE;
2154
2155 /* Check for previous usable entry on current disk */
2156 if (List->CurrentPartition != NULL)
2157 {
2158 if (List->CurrentPartition->LogicalPartition)
2159 {
2160 /* Logical partition */
2161 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2162 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2163 {
2164 /* Previous logical partition */
2165 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2166 }
2167 else
2168 {
2169 /* Extended partition*/
2170 PartEntry = List->CurrentDisk->ExtendedPartition;
2171 }
2172
2173 List->CurrentPartition = PartEntry;
2174 return TRUE;
2175 }
2176 else
2177 {
2178 /* Primary or extended partition */
2179
2180 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2181 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2182 {
2183 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2184
2185 if (PartEntry->IsPartitioned == TRUE &&
2186 IsContainerPartition(PartEntry->PartitionType))
2187 {
2188 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2189 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2190 }
2191
2192 List->CurrentPartition = PartEntry;
2193 return TRUE;
2194 }
2195
2196 }
2197 }
2198
2199 /* Search for the last partition entry on the previous disk */
2200 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2201 while (DiskListEntry != &List->DiskListHead)
2202 {
2203 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2204
2205 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2206 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2207 {
2208 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2209
2210 if (PartEntry->IsPartitioned == TRUE &&
2211 IsContainerPartition(PartEntry->PartitionType))
2212 {
2213 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2214 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2215 {
2216 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2217
2218 List->CurrentDisk = DiskEntry;
2219 List->CurrentPartition = PartEntry;
2220 return TRUE;
2221 }
2222 }
2223 else
2224 {
2225 List->CurrentDisk = DiskEntry;
2226 List->CurrentPartition = PartEntry;
2227 return TRUE;
2228 }
2229 }
2230
2231 DiskListEntry = DiskListEntry->Blink;
2232 }
2233
2234 return FALSE;
2235 }
2236
2237
2238 static
2239 BOOLEAN
2240 IsEmptyLayoutEntry(
2241 PPARTITION_INFORMATION PartitionInfo)
2242 {
2243 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2244 PartitionInfo->PartitionLength.QuadPart == 0)
2245 // PartitionInfo->PartitionType == 0)
2246 return TRUE;
2247
2248 return FALSE;
2249 }
2250
2251
2252 static
2253 BOOLEAN
2254 IsSamePrimaryLayoutEntry(
2255 IN PPARTITION_INFORMATION PartitionInfo,
2256 IN PDISKENTRY DiskEntry,
2257 IN PPARTENTRY PartEntry)
2258 {
2259 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2260 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2261 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2262 // PartitionInfo->PartitionType == PartEntry->PartitionType
2263 return TRUE;
2264
2265 return FALSE;
2266 }
2267
2268
2269 static
2270 VOID
2271 UpdateDiskLayout(
2272 IN PDISKENTRY DiskEntry)
2273 {
2274 PPARTITION_INFORMATION PartitionInfo;
2275 PLIST_ENTRY ListEntry;
2276 PPARTENTRY PartEntry;
2277 ULONG Index = 0;
2278 ULONG PartitionNumber = 1;
2279
2280 DPRINT1("UpdateDiskLayout()\n");
2281
2282 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2283 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2284 {
2285 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2286
2287 if (PartEntry->IsPartitioned == TRUE)
2288 {
2289 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2290
2291 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2292 {
2293 DPRINT1("Updating partition entry %lu\n", Index);
2294
2295 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2296 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2297 PartitionInfo->HiddenSectors = 0;
2298 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2299 PartitionInfo->PartitionType = PartEntry->PartitionType;
2300 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2301 PartitionInfo->RecognizedPartition = FALSE;
2302 PartitionInfo->RewritePartition = TRUE;
2303
2304 PartEntry->PartitionNumber = PartitionNumber;
2305 PartEntry->PartitionIndex = Index;
2306
2307 PartitionNumber++;
2308 }
2309 else if (!IsEmptyLayoutEntry(PartitionInfo))
2310 {
2311 PartitionNumber++;
2312 }
2313
2314 Index++;
2315 }
2316
2317 ListEntry = ListEntry->Flink;
2318 }
2319
2320 for (;Index < 4; Index++)
2321 {
2322 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2323
2324 if (!IsEmptyLayoutEntry(PartitionInfo))
2325 {
2326 DPRINT1("Wiping partition entry %lu\n", Index);
2327
2328 PartitionInfo->StartingOffset.QuadPart = 0;
2329 PartitionInfo->PartitionLength.QuadPart = 0;
2330 PartitionInfo->HiddenSectors = 0;
2331 PartitionInfo->PartitionNumber = 0;
2332 PartitionInfo->PartitionType = 0;
2333 PartitionInfo->BootIndicator = FALSE;
2334 PartitionInfo->RecognizedPartition = FALSE;
2335 PartitionInfo->RewritePartition = TRUE;
2336 }
2337 }
2338
2339 #ifdef DUMP_PARTITION_TABLE
2340 DumpPartitionTable(DiskEntry);
2341 #endif
2342 }
2343
2344
2345 static
2346 PPARTENTRY
2347 GetPrevUnpartitionedEntry(
2348 PDISKENTRY DiskEntry,
2349 PPARTENTRY PartEntry)
2350 {
2351 PPARTENTRY PrevPartEntry;
2352 PLIST_ENTRY ListHead;
2353
2354 if (PartEntry->LogicalPartition)
2355 ListHead = &DiskEntry->LogicalPartListHead;
2356 else
2357 ListHead = &DiskEntry->PrimaryPartListHead;
2358
2359 if (PartEntry->ListEntry.Blink != ListHead)
2360 {
2361 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2362 PARTENTRY,
2363 ListEntry);
2364 if (PrevPartEntry->IsPartitioned == FALSE)
2365 return PrevPartEntry;
2366 }
2367
2368 return NULL;
2369 }
2370
2371
2372 static
2373 PPARTENTRY
2374 GetNextUnpartitionedEntry(
2375 PDISKENTRY DiskEntry,
2376 PPARTENTRY PartEntry)
2377 {
2378 PPARTENTRY NextPartEntry;
2379 PLIST_ENTRY ListHead;
2380
2381 if (PartEntry->LogicalPartition)
2382 ListHead = &DiskEntry->LogicalPartListHead;
2383 else
2384 ListHead = &DiskEntry->PrimaryPartListHead;
2385
2386 if (PartEntry->ListEntry.Flink != ListHead)
2387 {
2388 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2389 PARTENTRY,
2390 ListEntry);
2391 if (NextPartEntry->IsPartitioned == FALSE)
2392 return NextPartEntry;
2393 }
2394
2395 return NULL;
2396 }
2397
2398
2399 VOID
2400 CreatePrimaryPartition(
2401 PPARTLIST List,
2402 ULONGLONG SectorCount,
2403 BOOLEAN AutoCreate)
2404 {
2405 PDISKENTRY DiskEntry;
2406 PPARTENTRY PartEntry;
2407 PPARTENTRY NewPartEntry;
2408
2409 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2410
2411 if (List == NULL ||
2412 List->CurrentDisk == NULL ||
2413 List->CurrentPartition == NULL ||
2414 List->CurrentPartition->IsPartitioned == TRUE)
2415 {
2416 return;
2417 }
2418
2419 DiskEntry = List->CurrentDisk;
2420 PartEntry = List->CurrentPartition;
2421
2422 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2423
2424 if (AutoCreate == TRUE ||
2425 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2426 {
2427 DPRINT1("Convert existing partition entry\n");
2428
2429 /* Convert current entry to 'new (unformatted)' */
2430 PartEntry->IsPartitioned = TRUE;
2431 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2432 PartEntry->FormatState = Unformatted;
2433 PartEntry->AutoCreate = AutoCreate;
2434 PartEntry->New = TRUE;
2435 PartEntry->BootIndicator = FALSE;
2436
2437 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2438 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2439 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2440 }
2441 else
2442 {
2443 DPRINT1("Add new partition entry\n");
2444
2445 /* Insert and initialize a new partition entry */
2446 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2447 HEAP_ZERO_MEMORY,
2448 sizeof(PARTENTRY));
2449 if (NewPartEntry == NULL)
2450 return;
2451
2452 /* Insert the new entry into the list */
2453 InsertTailList(&PartEntry->ListEntry,
2454 &NewPartEntry->ListEntry);
2455
2456 NewPartEntry->DiskEntry = DiskEntry;
2457
2458 NewPartEntry->IsPartitioned = TRUE;
2459 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2460 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2461 NewPartEntry->StartSector.QuadPart;
2462 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2463
2464 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2465 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2466 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2467
2468 NewPartEntry->New = TRUE;
2469 NewPartEntry->FormatState = Unformatted;
2470 NewPartEntry->BootIndicator = FALSE;
2471
2472 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2473 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2474 }
2475
2476 UpdateDiskLayout(DiskEntry);
2477
2478 DiskEntry->Dirty = TRUE;
2479
2480 UpdatePartitionNumbers(DiskEntry);
2481
2482 AssignDriveLetters(List);
2483 }
2484
2485
2486 static
2487 VOID
2488 AddLogicalDiskSpace(
2489 PDISKENTRY DiskEntry)
2490 {
2491 PPARTENTRY NewPartEntry;
2492
2493 DPRINT1("AddLogicalDiskSpace()\n");
2494
2495 /* Create a partition table entry that represents the empty space in the container partition */
2496 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2497 HEAP_ZERO_MEMORY,
2498 sizeof(PARTENTRY));
2499 if (NewPartEntry == NULL)
2500 return;
2501
2502 NewPartEntry->DiskEntry = DiskEntry;
2503 NewPartEntry->LogicalPartition = TRUE;
2504
2505 NewPartEntry->IsPartitioned = FALSE;
2506 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2507 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2508
2509 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2510 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2511 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2512
2513 NewPartEntry->FormatState = Unformatted;
2514
2515 InsertTailList(&DiskEntry->LogicalPartListHead,
2516 &NewPartEntry->ListEntry);
2517 }
2518
2519
2520 VOID
2521 CreateExtendedPartition(
2522 PPARTLIST List,
2523 ULONGLONG SectorCount)
2524 {
2525 PDISKENTRY DiskEntry;
2526 PPARTENTRY PartEntry;
2527 PPARTENTRY NewPartEntry;
2528
2529 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2530
2531 if (List == NULL ||
2532 List->CurrentDisk == NULL ||
2533 List->CurrentPartition == NULL ||
2534 List->CurrentPartition->IsPartitioned == TRUE)
2535 {
2536 return;
2537 }
2538
2539 DiskEntry = List->CurrentDisk;
2540 PartEntry = List->CurrentPartition;
2541
2542 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2543
2544 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2545 {
2546 DPRINT1("Convert existing partition entry\n");
2547
2548 /* Convert current entry to 'new (unformatted)' */
2549 PartEntry->IsPartitioned = TRUE;
2550 PartEntry->FormatState = Formatted;
2551 PartEntry->AutoCreate = FALSE;
2552 PartEntry->New = FALSE;
2553 PartEntry->BootIndicator = FALSE;
2554
2555 if (PartEntry->StartSector.QuadPart < 1450560)
2556 {
2557 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2558 PartEntry->PartitionType = PARTITION_EXTENDED;
2559 }
2560 else
2561 {
2562 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2563 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2564 }
2565
2566 DiskEntry->ExtendedPartition = PartEntry;
2567
2568 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2569 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2570 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2571 }
2572 else
2573 {
2574 DPRINT1("Add new partition entry\n");
2575
2576 /* Insert and initialize a new partition entry */
2577 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2578 HEAP_ZERO_MEMORY,
2579 sizeof(PARTENTRY));
2580 if (NewPartEntry == NULL)
2581 return;
2582
2583 /* Insert the new entry into the list */
2584 InsertTailList(&PartEntry->ListEntry,
2585 &NewPartEntry->ListEntry);
2586
2587 NewPartEntry->DiskEntry = DiskEntry;
2588
2589 NewPartEntry->IsPartitioned = TRUE;
2590 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2591 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2592 NewPartEntry->StartSector.QuadPart;
2593
2594 NewPartEntry->New = FALSE;
2595 NewPartEntry->FormatState = Formatted;
2596 NewPartEntry->BootIndicator = FALSE;
2597
2598 if (NewPartEntry->StartSector.QuadPart < 1450560)
2599 {
2600 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2601 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2602 }
2603 else
2604 {
2605 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2606 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2607 }
2608
2609 DiskEntry->ExtendedPartition = NewPartEntry;
2610
2611 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2612 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2613
2614 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2615 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2616 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2617 }
2618
2619 AddLogicalDiskSpace(DiskEntry);
2620
2621 UpdateDiskLayout(DiskEntry);
2622
2623 DiskEntry->Dirty = TRUE;
2624
2625 UpdatePartitionNumbers(DiskEntry);
2626
2627 AssignDriveLetters(List);
2628 }
2629
2630
2631 VOID
2632 CreateLogicalPartition(
2633 PPARTLIST List,
2634 ULONGLONG SectorCount)
2635 {
2636 PDISKENTRY DiskEntry;
2637 PPARTENTRY PartEntry;
2638 PPARTENTRY NewPartEntry;
2639
2640 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2641
2642 if (List == NULL ||
2643 List->CurrentDisk == NULL ||
2644 List->CurrentPartition == NULL ||
2645 List->CurrentPartition->IsPartitioned == TRUE)
2646 {
2647 return;
2648 }
2649
2650 DiskEntry = List->CurrentDisk;
2651 PartEntry = List->CurrentPartition;
2652
2653 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2654
2655 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2656 {
2657 DPRINT1("Convert existing partition entry\n");
2658
2659 /* Convert current entry to 'new (unformatted)' */
2660 PartEntry->IsPartitioned = TRUE;
2661 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2662 PartEntry->FormatState = Unformatted;
2663 PartEntry->AutoCreate = FALSE;
2664 PartEntry->New = TRUE;
2665 PartEntry->BootIndicator = FALSE;
2666 PartEntry->LogicalPartition = TRUE;
2667
2668 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2669 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2670 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2671 }
2672 else
2673 {
2674 DPRINT1("Add new partition entry\n");
2675
2676 /* Insert and initialize a new partition entry */
2677 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2678 HEAP_ZERO_MEMORY,
2679 sizeof(PARTENTRY));
2680 if (NewPartEntry == NULL)
2681 return;
2682
2683 /* Insert the new entry into the list */
2684 InsertTailList(&PartEntry->ListEntry,
2685 &NewPartEntry->ListEntry);
2686
2687 NewPartEntry->DiskEntry = DiskEntry;
2688
2689 NewPartEntry->IsPartitioned = TRUE;
2690 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2691 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2692 NewPartEntry->StartSector.QuadPart;
2693 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2694
2695 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2696 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2697 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2698
2699 NewPartEntry->New = TRUE;
2700 NewPartEntry->FormatState = Unformatted;
2701 NewPartEntry->BootIndicator = FALSE;
2702 NewPartEntry->LogicalPartition = TRUE;
2703
2704 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2705 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2706 }
2707
2708 UpdateDiskLayout(DiskEntry);
2709
2710 DiskEntry->Dirty = TRUE;
2711
2712 UpdatePartitionNumbers(DiskEntry);
2713
2714 AssignDriveLetters(List);
2715 }
2716
2717
2718 VOID
2719 DeleteCurrentPartition(
2720 PPARTLIST List)
2721 {
2722 PDISKENTRY DiskEntry;
2723 PPARTENTRY PartEntry;
2724 PPARTENTRY PrevPartEntry;
2725 PPARTENTRY NextPartEntry;
2726 PPARTENTRY LogicalPartEntry;
2727 PLIST_ENTRY Entry;
2728
2729 if (List == NULL ||
2730 List->CurrentDisk == NULL ||
2731 List->CurrentPartition == NULL ||
2732 List->CurrentPartition->IsPartitioned == FALSE)
2733 {
2734 return;
2735 }
2736
2737 DiskEntry = List->CurrentDisk;
2738 PartEntry = List->CurrentPartition;
2739
2740 /* Delete all logical partiton entries if an extended partition will be deleted */
2741 if (DiskEntry->ExtendedPartition == PartEntry)
2742 {
2743 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2744 {
2745 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2746 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2747
2748 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2749 }
2750
2751 DiskEntry->ExtendedPartition = NULL;
2752 }
2753
2754 /* Adjust unpartitioned disk space entries */
2755
2756 /* Get pointer to previous and next unpartitioned entries */
2757 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2758 PartEntry);
2759
2760 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2761 PartEntry);
2762
2763 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2764 {
2765 /* Merge previous, current and next unpartitioned entry */
2766
2767 /* Adjust the previous entries length */
2768 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2769
2770 /* Remove the current entry */
2771 RemoveEntryList(&PartEntry->ListEntry);
2772 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2773
2774 /* Remove the next entry */
2775 RemoveEntryList (&NextPartEntry->ListEntry);
2776 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2777
2778 /* Update current partition */
2779 List->CurrentPartition = PrevPartEntry;
2780 }
2781 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2782 {
2783 /* Merge current and previous unpartitioned entry */
2784
2785 /* Adjust the previous entries length */
2786 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2787
2788 /* Remove the current entry */
2789 RemoveEntryList(&PartEntry->ListEntry);
2790 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2791
2792 /* Update current partition */
2793 List->CurrentPartition = PrevPartEntry;
2794 }
2795 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2796 {
2797 /* Merge current and next unpartitioned entry */
2798
2799 /* Adjust the next entries offset and length */
2800 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2801 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2802
2803 /* Remove the current entry */
2804 RemoveEntryList(&PartEntry->ListEntry);
2805 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2806
2807 /* Update current partition */
2808 List->CurrentPartition = NextPartEntry;
2809 }
2810 else
2811 {
2812 /* Nothing to merge but change current entry */
2813 PartEntry->IsPartitioned = FALSE;
2814 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2815 PartEntry->FormatState = Unformatted;
2816 PartEntry->DriveLetter = 0;
2817 }
2818
2819 UpdateDiskLayout(DiskEntry);
2820
2821 DiskEntry->Dirty = TRUE;
2822
2823 UpdatePartitionNumbers(DiskEntry);
2824
2825 AssignDriveLetters(List);
2826 }
2827
2828
2829 VOID
2830 CheckActiveBootPartition(
2831 PPARTLIST List)
2832 {
2833 PDISKENTRY DiskEntry;
2834 PPARTENTRY PartEntry;
2835 PLIST_ENTRY ListEntry;
2836
2837 /* Check for empty disk list */
2838 if (IsListEmpty (&List->DiskListHead))
2839 {
2840 List->BootDisk = NULL;
2841 List->BootPartition = NULL;
2842 return;
2843 }
2844
2845 #if 0
2846 if (List->BootDisk != NULL &&
2847 List->BootPartition != NULL)
2848 {
2849 /* We already have an active boot partition */
2850 return;
2851 }
2852 #endif
2853
2854 /* Choose the currently selected disk */
2855 DiskEntry = List->CurrentDisk;
2856
2857 /* Check for empty partition list */
2858 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2859 {
2860 List->BootDisk = NULL;
2861 List->BootPartition = NULL;
2862 return;
2863 }
2864
2865 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2866 PARTENTRY,
2867 ListEntry);
2868
2869 /* Set active boot partition */
2870 if ((DiskEntry->NewDisk == TRUE) ||
2871 (PartEntry->BootIndicator == FALSE))
2872 {
2873 PartEntry->BootIndicator = TRUE;
2874 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
2875 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2876 DiskEntry->Dirty = TRUE;
2877
2878 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2879 List->BootDisk = DiskEntry;
2880 List->BootPartition = PartEntry;
2881
2882 return;
2883 }
2884
2885 /* Disk is not new, scan all partitions to find a bootable one */
2886 List->BootDisk = NULL;
2887 List->BootPartition = NULL;
2888
2889 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2890 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2891 {
2892 PartEntry = CONTAINING_RECORD(ListEntry,
2893 PARTENTRY,
2894 ListEntry);
2895
2896 /* Check if it is partitioned */
2897 if (PartEntry->IsPartitioned)
2898 {
2899 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
2900 PartEntry->BootIndicator)
2901 {
2902 /* Yes, we found it */
2903 List->BootDisk = DiskEntry;
2904 List->BootPartition = PartEntry;
2905
2906 DPRINT("Found bootable partition disk %d, drive letter %c\n",
2907 DiskEntry->DiskNumber, PartEntry->DriveLetter);
2908 break;
2909 }
2910 }
2911
2912 /* Go to the next one */
2913 ListEntry = ListEntry->Flink;
2914 }
2915 }
2916
2917
2918 static
2919 NTSTATUS
2920 WritePartitions(
2921 IN PPARTLIST List,
2922 IN PDISKENTRY DiskEntry)
2923 {
2924 WCHAR DstPath[MAX_PATH];
2925 OBJECT_ATTRIBUTES ObjectAttributes;
2926 IO_STATUS_BLOCK Iosb;
2927 UNICODE_STRING Name;
2928 ULONG BufferSize;
2929 HANDLE FileHandle = NULL;
2930 NTSTATUS Status;
2931
2932 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2933
2934 swprintf(DstPath,
2935 L"\\Device\\Harddisk%d\\Partition0",
2936 DiskEntry->DiskNumber);
2937 RtlInitUnicodeString(&Name,
2938 DstPath);
2939 InitializeObjectAttributes(&ObjectAttributes,
2940 &Name,
2941 0,
2942 NULL,
2943 NULL);
2944
2945 Status = NtOpenFile(&FileHandle,
2946 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2947 &ObjectAttributes,
2948 &Iosb,
2949 0,
2950 FILE_SYNCHRONOUS_IO_NONALERT);
2951 if (!NT_SUCCESS(Status))
2952 {
2953 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2954 return Status;
2955 }
2956
2957 #ifdef DUMP_PARTITION_TABLE
2958 DumpPartitionTable(DiskEntry);
2959 #endif
2960
2961 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2962 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
2963 Status = NtDeviceIoControlFile(FileHandle,
2964 NULL,
2965 NULL,
2966 NULL,
2967 &Iosb,
2968 IOCTL_DISK_SET_DRIVE_LAYOUT,
2969 DiskEntry->LayoutBuffer,
2970 BufferSize,
2971 NULL,
2972 0);
2973 if (!NT_SUCCESS(Status))
2974 {
2975 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2976 }
2977
2978 if (FileHandle != NULL)
2979 NtClose(FileHandle);
2980
2981 return Status;
2982 }
2983
2984
2985 BOOLEAN
2986 WritePartitionsToDisk(
2987 PPARTLIST List)
2988 {
2989 PLIST_ENTRY Entry;
2990 PDISKENTRY DiskEntry;
2991
2992 if (List == NULL)
2993 return TRUE;
2994
2995 Entry = List->DiskListHead.Flink;
2996 while (Entry != &List->DiskListHead)
2997 {
2998 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2999
3000 if (DiskEntry->Dirty == TRUE)
3001 {
3002 WritePartitions(List, DiskEntry);
3003 DiskEntry->Dirty = FALSE;
3004 }
3005
3006 Entry = Entry->Flink;
3007 }
3008
3009 return TRUE;
3010 }
3011
3012
3013 BOOL
3014 SetMountedDeviceValues(
3015 PPARTLIST List)
3016 {
3017 PLIST_ENTRY Entry1, Entry2;
3018 PDISKENTRY DiskEntry;
3019 PPARTENTRY PartEntry;
3020 LARGE_INTEGER StartingOffset;
3021
3022 if (List == NULL)
3023 {
3024 return FALSE;
3025 }
3026
3027 Entry1 = List->DiskListHead.Flink;
3028 while (Entry1 != &List->DiskListHead)
3029 {
3030 DiskEntry = CONTAINING_RECORD(Entry1,
3031 DISKENTRY,
3032 ListEntry);
3033
3034 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3035 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3036 {
3037 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3038 if (PartEntry->IsPartitioned)
3039 {
3040 if (PartEntry->DriveLetter)
3041 {
3042 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3043 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3044 DiskEntry->LayoutBuffer->Signature,
3045 StartingOffset))
3046 {
3047 return FALSE;
3048 }
3049 }
3050 }
3051
3052 Entry2 = Entry2->Flink;
3053 }
3054
3055 Entry1 = Entry1->Flink;
3056 }
3057
3058 return TRUE;
3059 }
3060
3061
3062 static
3063 ULONG
3064 GetPrimaryPartitionCount(
3065 IN PDISKENTRY DiskEntry)
3066 {
3067 PLIST_ENTRY Entry;
3068 PPARTENTRY PartEntry;
3069 UINT nCount = 0;
3070
3071 Entry = DiskEntry->PrimaryPartListHead.Flink;
3072 while (Entry != &DiskEntry->PrimaryPartListHead)
3073 {
3074 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3075 if (PartEntry->IsPartitioned == TRUE)
3076 nCount++;
3077
3078 Entry = Entry->Flink;
3079 }
3080
3081 return nCount;
3082 }
3083
3084
3085 ULONG
3086 PrimaryPartitionCreationChecks(
3087 IN PPARTLIST List)
3088 {
3089 PDISKENTRY DiskEntry;
3090 PPARTENTRY PartEntry;
3091
3092 DiskEntry = List->CurrentDisk;
3093 PartEntry = List->CurrentPartition;
3094
3095 /* Fail if partition is already in use */
3096 if (PartEntry->IsPartitioned == TRUE)
3097 return ERROR_NEW_PARTITION;
3098
3099 /* Fail if there are more than 4 partitions in the list */
3100 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3101 return ERROR_PARTITION_TABLE_FULL;
3102
3103 return ERROR_SUCCESS;
3104 }
3105
3106
3107 ULONG
3108 ExtendedPartitionCreationChecks(
3109 IN PPARTLIST List)
3110 {
3111 PDISKENTRY DiskEntry;
3112 PPARTENTRY PartEntry;
3113
3114 DiskEntry = List->CurrentDisk;
3115 PartEntry = List->CurrentPartition;
3116
3117 /* Fail if partition is already in use */
3118 if (PartEntry->IsPartitioned == TRUE)
3119 return ERROR_NEW_PARTITION;
3120
3121 /* Fail if there are more than 4 partitions in the list */
3122 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3123 return ERROR_PARTITION_TABLE_FULL;
3124
3125 /* Fail if there is another extended partition in the list */
3126 if (DiskEntry->ExtendedPartition != NULL)
3127 return ERROR_ONLY_ONE_EXTENDED;
3128
3129 return ERROR_SUCCESS;
3130 }
3131
3132
3133 ULONG
3134 LogicalPartitionCreationChecks(
3135 IN PPARTLIST List)
3136 {
3137 // PDISKENTRY DiskEntry;
3138 PPARTENTRY PartEntry;
3139
3140 // DiskEntry = List->CurrentDisk;
3141 PartEntry = List->CurrentPartition;
3142
3143 /* Fail if partition is already in use */
3144 if (PartEntry->IsPartitioned == TRUE)
3145 return ERROR_NEW_PARTITION;
3146
3147 return ERROR_SUCCESS;
3148 }
3149
3150
3151 BOOL
3152 GetNextUnformattedPartition(
3153 IN PPARTLIST List,
3154 OUT PDISKENTRY *pDiskEntry,
3155 OUT PPARTENTRY *pPartEntry)
3156 {
3157 PLIST_ENTRY Entry1, Entry2;
3158 PDISKENTRY DiskEntry;
3159 PPARTENTRY PartEntry;
3160
3161 Entry1 = List->DiskListHead.Flink;
3162 while (Entry1 != &List->DiskListHead)
3163 {
3164 DiskEntry = CONTAINING_RECORD(Entry1,
3165 DISKENTRY,
3166 ListEntry);
3167
3168 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3169 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3170 {
3171 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3172 if (PartEntry->IsPartitioned && PartEntry->New)
3173 {
3174 *pDiskEntry = DiskEntry;
3175 *pPartEntry = PartEntry;
3176 return TRUE;
3177 }
3178
3179 Entry2 = Entry2->Flink;
3180 }
3181
3182 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3183 while (Entry2 != &DiskEntry->LogicalPartListHead)
3184 {
3185 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3186 if (PartEntry->IsPartitioned && PartEntry->New)
3187 {
3188 *pDiskEntry = DiskEntry;
3189 *pPartEntry = PartEntry;
3190 return TRUE;
3191 }
3192
3193 Entry2 = Entry2->Flink;
3194 }
3195
3196 Entry1 = Entry1->Flink;
3197 }
3198
3199 *pDiskEntry = NULL;
3200 *pPartEntry = NULL;
3201
3202 return FALSE;
3203 }
3204
3205
3206 BOOL
3207 GetNextUncheckedPartition(
3208 IN PPARTLIST List,
3209 OUT PDISKENTRY *pDiskEntry,
3210 OUT PPARTENTRY *pPartEntry)
3211 {
3212 PLIST_ENTRY Entry1, Entry2;
3213 PDISKENTRY DiskEntry;
3214 PPARTENTRY PartEntry;
3215
3216 Entry1 = List->DiskListHead.Flink;
3217 while (Entry1 != &List->DiskListHead)
3218 {
3219 DiskEntry = CONTAINING_RECORD(Entry1,
3220 DISKENTRY,
3221 ListEntry);
3222
3223 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3224 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3225 {
3226 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3227 if (PartEntry->NeedsCheck == TRUE)
3228 {
3229 *pDiskEntry = DiskEntry;
3230 *pPartEntry = PartEntry;
3231 return TRUE;
3232 }
3233
3234 Entry2 = Entry2->Flink;
3235 }
3236
3237 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3238 while (Entry2 != &DiskEntry->LogicalPartListHead)
3239 {
3240 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3241 if (PartEntry->NeedsCheck == TRUE)
3242 {
3243 *pDiskEntry = DiskEntry;
3244 *pPartEntry = PartEntry;
3245 return TRUE;
3246 }
3247
3248 Entry2 = Entry2->Flink;
3249 }
3250
3251 Entry1 = Entry1->Flink;
3252 }
3253
3254 *pDiskEntry = NULL;
3255 *pPartEntry = NULL;
3256
3257 return FALSE;
3258 }
3259
3260 /* EOF */