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