[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 static
2196 BOOLEAN
2197 IsEmptyLayoutEntry(
2198 PPARTITION_INFORMATION PartitionInfo)
2199 {
2200 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2201 PartitionInfo->PartitionLength.QuadPart == 0)
2202 return TRUE;
2203
2204 return FALSE;
2205 }
2206
2207
2208 static
2209 BOOLEAN
2210 IsSamePrimaryLayoutEntry(
2211 IN PPARTITION_INFORMATION PartitionInfo,
2212 IN PDISKENTRY DiskEntry,
2213 IN PPARTENTRY PartEntry)
2214 {
2215 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2216 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2217 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2218 // PartitionInfo->PartitionType == PartEntry->PartitionType
2219 return TRUE;
2220
2221 return FALSE;
2222 }
2223
2224
2225 static
2226 ULONG
2227 GetPrimaryPartitionCount(
2228 IN PDISKENTRY DiskEntry)
2229 {
2230 PLIST_ENTRY Entry;
2231 PPARTENTRY PartEntry;
2232 ULONG Count = 0;
2233
2234 Entry = DiskEntry->PrimaryPartListHead.Flink;
2235 while (Entry != &DiskEntry->PrimaryPartListHead)
2236 {
2237 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2238 if (PartEntry->IsPartitioned == TRUE)
2239 Count++;
2240
2241 Entry = Entry->Flink;
2242 }
2243
2244 return Count;
2245 }
2246
2247
2248 static
2249 ULONG
2250 GetLogicalPartitionCount(
2251 PDISKENTRY DiskEntry)
2252 {
2253 PLIST_ENTRY ListEntry;
2254 PPARTENTRY PartEntry;
2255 ULONG Count = 0;
2256
2257 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2258 while (ListEntry != &DiskEntry->LogicalPartListHead)
2259 {
2260 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2261 if (PartEntry->IsPartitioned)
2262 Count++;
2263
2264 ListEntry = ListEntry->Flink;
2265 }
2266
2267 return Count;
2268 }
2269
2270
2271 static
2272 BOOL
2273 ReAllocateLayoutBuffer(
2274 PDISKENTRY DiskEntry)
2275 {
2276 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2277 ULONG NewPartitionCount;
2278 ULONG CurrentPartitionCount = 0;
2279 ULONG LayoutBufferSize;
2280 ULONG i;
2281
2282 DPRINT1("ReAllocateLayoutBuffer()\n");
2283
2284 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2285
2286 if (DiskEntry->LayoutBuffer)
2287 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2288
2289 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2290 CurrentPartitionCount, NewPartitionCount);
2291
2292 if (CurrentPartitionCount == NewPartitionCount)
2293 return TRUE;
2294
2295 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2296 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2297 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2298 HEAP_ZERO_MEMORY,
2299 DiskEntry->LayoutBuffer,
2300 LayoutBufferSize);
2301 if (NewLayoutBuffer == NULL)
2302 {
2303 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2304 return FALSE;
2305 }
2306
2307 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2308 if (NewPartitionCount > CurrentPartitionCount)
2309 {
2310 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2311 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2312 }
2313
2314 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2315 DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
2316
2317 return TRUE;
2318 }
2319
2320
2321 static
2322 VOID
2323 UpdateDiskLayout(
2324 IN PDISKENTRY DiskEntry)
2325 {
2326 PPARTITION_INFORMATION PartitionInfo;
2327 PPARTITION_INFORMATION LinkInfo = NULL;
2328 PLIST_ENTRY ListEntry;
2329 PPARTENTRY PartEntry;
2330 ULONG Index;
2331 ULONG PartitionNumber = 1;
2332
2333 DPRINT1("UpdateDiskLayout()\n");
2334
2335 /* Resize the layout buffer if necessary */
2336 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2337 {
2338 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2339 return;
2340 }
2341
2342 /* Update the primary partition table */
2343 Index = 0;
2344 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2345 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2346 {
2347 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2348
2349 if (PartEntry->IsPartitioned == TRUE)
2350 {
2351 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2352
2353 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2354 {
2355 DPRINT1("Updating primary partition entry %lu\n", Index);
2356
2357 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2358 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2359 PartitionInfo->HiddenSectors = (ULONG)PartEntry->StartSector.QuadPart;
2360 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2361 PartitionInfo->PartitionType = PartEntry->PartitionType;
2362 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2363 PartitionInfo->RecognizedPartition = FALSE;
2364 PartitionInfo->RewritePartition = TRUE;
2365 }
2366
2367 PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2368 PartEntry->PartitionIndex = Index;
2369
2370 if (!IsContainerPartition(PartEntry->PartitionType))
2371 PartitionNumber++;
2372
2373 Index++;
2374 }
2375
2376 ListEntry = ListEntry->Flink;
2377 }
2378
2379 /* Update the logical partition tables */
2380 Index = 4;
2381 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2382 while (ListEntry != &DiskEntry->LogicalPartListHead)
2383 {
2384 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2385
2386 if (PartEntry->IsPartitioned)
2387 {
2388 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2389
2390 DPRINT1("Updating logical partition entry %lu\n", Index);
2391
2392 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2393 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2394 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2395 PartitionInfo->PartitionNumber = PartitionNumber;
2396 PartitionInfo->PartitionType = PartEntry->PartitionType;
2397 PartitionInfo->BootIndicator = FALSE;
2398 PartitionInfo->RecognizedPartition = FALSE;
2399 PartitionInfo->RewritePartition = TRUE;
2400
2401 PartEntry->PartitionNumber = PartitionNumber;
2402 PartEntry->PartitionIndex = Index;
2403
2404 /* Fill the link entry of the previous partition table */
2405 if (LinkInfo != NULL)
2406 {
2407 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2408 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2409 LinkInfo->HiddenSectors = (ULONG)(PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart);
2410 LinkInfo->PartitionNumber = 0;
2411 LinkInfo->PartitionType = PARTITION_EXTENDED;
2412 LinkInfo->BootIndicator = FALSE;
2413 LinkInfo->RecognizedPartition = FALSE;
2414 LinkInfo->RewritePartition = TRUE;
2415 }
2416
2417 /* Save a pointer to the link entry of the current partition table */
2418 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2419
2420 PartitionNumber++;
2421 Index += 4;
2422 }
2423
2424 ListEntry = ListEntry->Flink;
2425 }
2426
2427 /* Wipe unused primary partition table entries */
2428 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2429 {
2430 DPRINT1("Primary partition entry %lu\n", Index);
2431
2432 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2433
2434 if (!IsEmptyLayoutEntry(PartitionInfo))
2435 {
2436 DPRINT1("Wiping primary partition entry %lu\n", Index);
2437
2438 PartitionInfo->StartingOffset.QuadPart = 0;
2439 PartitionInfo->PartitionLength.QuadPart = 0;
2440 PartitionInfo->HiddenSectors = 0;
2441 PartitionInfo->PartitionNumber = 0;
2442 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2443 PartitionInfo->BootIndicator = FALSE;
2444 PartitionInfo->RecognizedPartition = FALSE;
2445 PartitionInfo->RewritePartition = TRUE;
2446 }
2447 }
2448
2449 /* Wipe unused logical partition table entries */
2450 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2451 {
2452 if (Index % 4 >= 2)
2453 {
2454 DPRINT1("Logical partition entry %lu\n", Index);
2455
2456 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2457
2458 if (!IsEmptyLayoutEntry(PartitionInfo))
2459 {
2460 DPRINT1("Wiping partition entry %lu\n", Index);
2461
2462 PartitionInfo->StartingOffset.QuadPart = 0;
2463 PartitionInfo->PartitionLength.QuadPart = 0;
2464 PartitionInfo->HiddenSectors = 0;
2465 PartitionInfo->PartitionNumber = 0;
2466 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2467 PartitionInfo->BootIndicator = FALSE;
2468 PartitionInfo->RecognizedPartition = FALSE;
2469 PartitionInfo->RewritePartition = TRUE;
2470 }
2471 }
2472 }
2473
2474 #ifdef DUMP_PARTITION_TABLE
2475 DumpPartitionTable(DiskEntry);
2476 #endif
2477 }
2478
2479
2480 static
2481 PPARTENTRY
2482 GetPrevUnpartitionedEntry(
2483 PDISKENTRY DiskEntry,
2484 PPARTENTRY PartEntry)
2485 {
2486 PPARTENTRY PrevPartEntry;
2487 PLIST_ENTRY ListHead;
2488
2489 if (PartEntry->LogicalPartition)
2490 ListHead = &DiskEntry->LogicalPartListHead;
2491 else
2492 ListHead = &DiskEntry->PrimaryPartListHead;
2493
2494 if (PartEntry->ListEntry.Blink != ListHead)
2495 {
2496 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2497 PARTENTRY,
2498 ListEntry);
2499 if (PrevPartEntry->IsPartitioned == FALSE)
2500 return PrevPartEntry;
2501 }
2502
2503 return NULL;
2504 }
2505
2506
2507 static
2508 PPARTENTRY
2509 GetNextUnpartitionedEntry(
2510 PDISKENTRY DiskEntry,
2511 PPARTENTRY PartEntry)
2512 {
2513 PPARTENTRY NextPartEntry;
2514 PLIST_ENTRY ListHead;
2515
2516 if (PartEntry->LogicalPartition)
2517 ListHead = &DiskEntry->LogicalPartListHead;
2518 else
2519 ListHead = &DiskEntry->PrimaryPartListHead;
2520
2521 if (PartEntry->ListEntry.Flink != ListHead)
2522 {
2523 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2524 PARTENTRY,
2525 ListEntry);
2526 if (NextPartEntry->IsPartitioned == FALSE)
2527 return NextPartEntry;
2528 }
2529
2530 return NULL;
2531 }
2532
2533
2534 VOID
2535 CreatePrimaryPartition(
2536 PPARTLIST List,
2537 ULONGLONG SectorCount,
2538 BOOLEAN AutoCreate)
2539 {
2540 PDISKENTRY DiskEntry;
2541 PPARTENTRY PartEntry;
2542 PPARTENTRY NewPartEntry;
2543
2544 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2545
2546 if (List == NULL ||
2547 List->CurrentDisk == NULL ||
2548 List->CurrentPartition == NULL ||
2549 List->CurrentPartition->IsPartitioned == TRUE)
2550 {
2551 return;
2552 }
2553
2554 DiskEntry = List->CurrentDisk;
2555 PartEntry = List->CurrentPartition;
2556
2557 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2558
2559 if (AutoCreate == TRUE ||
2560 Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2561 {
2562 DPRINT1("Convert existing partition entry\n");
2563
2564 /* Convert current entry to 'new (unformatted)' */
2565 PartEntry->IsPartitioned = TRUE;
2566 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2567 PartEntry->FormatState = Unformatted;
2568 PartEntry->AutoCreate = AutoCreate;
2569 PartEntry->New = TRUE;
2570 PartEntry->BootIndicator = FALSE;
2571
2572 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2573 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2574 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2575 }
2576 else
2577 {
2578 DPRINT1("Add new partition entry\n");
2579
2580 /* Insert and initialize a new partition entry */
2581 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2582 HEAP_ZERO_MEMORY,
2583 sizeof(PARTENTRY));
2584 if (NewPartEntry == NULL)
2585 return;
2586
2587 /* Insert the new entry into the list */
2588 InsertTailList(&PartEntry->ListEntry,
2589 &NewPartEntry->ListEntry);
2590
2591 NewPartEntry->DiskEntry = DiskEntry;
2592
2593 NewPartEntry->IsPartitioned = TRUE;
2594 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2595 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2596 NewPartEntry->StartSector.QuadPart;
2597 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2598
2599 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2600 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2601 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2602
2603 NewPartEntry->New = TRUE;
2604 NewPartEntry->FormatState = Unformatted;
2605 NewPartEntry->BootIndicator = FALSE;
2606
2607 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2608 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2609 }
2610
2611 UpdateDiskLayout(DiskEntry);
2612
2613 DiskEntry->Dirty = TRUE;
2614
2615 AssignDriveLetters(List);
2616 }
2617
2618
2619 static
2620 VOID
2621 AddLogicalDiskSpace(
2622 PDISKENTRY DiskEntry)
2623 {
2624 PPARTENTRY NewPartEntry;
2625
2626 DPRINT1("AddLogicalDiskSpace()\n");
2627
2628 /* Create a partition table entry that represents the empty space in the container partition */
2629 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2630 HEAP_ZERO_MEMORY,
2631 sizeof(PARTENTRY));
2632 if (NewPartEntry == NULL)
2633 return;
2634
2635 NewPartEntry->DiskEntry = DiskEntry;
2636 NewPartEntry->LogicalPartition = TRUE;
2637
2638 NewPartEntry->IsPartitioned = FALSE;
2639 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2640 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2641
2642 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2643 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2644 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2645
2646 NewPartEntry->FormatState = Unformatted;
2647
2648 InsertTailList(&DiskEntry->LogicalPartListHead,
2649 &NewPartEntry->ListEntry);
2650 }
2651
2652
2653 VOID
2654 CreateExtendedPartition(
2655 PPARTLIST List,
2656 ULONGLONG SectorCount)
2657 {
2658 PDISKENTRY DiskEntry;
2659 PPARTENTRY PartEntry;
2660 PPARTENTRY NewPartEntry;
2661
2662 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2663
2664 if (List == NULL ||
2665 List->CurrentDisk == NULL ||
2666 List->CurrentPartition == NULL ||
2667 List->CurrentPartition->IsPartitioned == TRUE)
2668 {
2669 return;
2670 }
2671
2672 DiskEntry = List->CurrentDisk;
2673 PartEntry = List->CurrentPartition;
2674
2675 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2676
2677 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2678 {
2679 DPRINT1("Convert existing partition entry\n");
2680
2681 /* Convert current entry to 'new (unformatted)' */
2682 PartEntry->IsPartitioned = TRUE;
2683 PartEntry->FormatState = Formatted;
2684 PartEntry->AutoCreate = FALSE;
2685 PartEntry->New = FALSE;
2686 PartEntry->BootIndicator = FALSE;
2687
2688 if (PartEntry->StartSector.QuadPart < 1450560)
2689 {
2690 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2691 PartEntry->PartitionType = PARTITION_EXTENDED;
2692 }
2693 else
2694 {
2695 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2696 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2697 }
2698
2699 DiskEntry->ExtendedPartition = PartEntry;
2700
2701 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2702 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2703 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2704 }
2705 else
2706 {
2707 DPRINT1("Add new partition entry\n");
2708
2709 /* Insert and initialize a new partition entry */
2710 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2711 HEAP_ZERO_MEMORY,
2712 sizeof(PARTENTRY));
2713 if (NewPartEntry == NULL)
2714 return;
2715
2716 /* Insert the new entry into the list */
2717 InsertTailList(&PartEntry->ListEntry,
2718 &NewPartEntry->ListEntry);
2719
2720 NewPartEntry->DiskEntry = DiskEntry;
2721
2722 NewPartEntry->IsPartitioned = TRUE;
2723 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2724 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2725 NewPartEntry->StartSector.QuadPart;
2726
2727 NewPartEntry->New = FALSE;
2728 NewPartEntry->FormatState = Formatted;
2729 NewPartEntry->BootIndicator = FALSE;
2730
2731 if (NewPartEntry->StartSector.QuadPart < 1450560)
2732 {
2733 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2734 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2735 }
2736 else
2737 {
2738 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2739 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2740 }
2741
2742 DiskEntry->ExtendedPartition = NewPartEntry;
2743
2744 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2745 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2746
2747 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2748 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2749 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2750 }
2751
2752 AddLogicalDiskSpace(DiskEntry);
2753
2754 UpdateDiskLayout(DiskEntry);
2755
2756 DiskEntry->Dirty = TRUE;
2757
2758 AssignDriveLetters(List);
2759 }
2760
2761
2762 VOID
2763 CreateLogicalPartition(
2764 PPARTLIST List,
2765 ULONGLONG SectorCount)
2766 {
2767 PDISKENTRY DiskEntry;
2768 PPARTENTRY PartEntry;
2769 PPARTENTRY NewPartEntry;
2770
2771 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2772
2773 if (List == NULL ||
2774 List->CurrentDisk == NULL ||
2775 List->CurrentPartition == NULL ||
2776 List->CurrentPartition->IsPartitioned == TRUE)
2777 {
2778 return;
2779 }
2780
2781 DiskEntry = List->CurrentDisk;
2782 PartEntry = List->CurrentPartition;
2783
2784 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2785
2786 if (Align(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2787 {
2788 DPRINT1("Convert existing partition entry\n");
2789
2790 /* Convert current entry to 'new (unformatted)' */
2791 PartEntry->IsPartitioned = TRUE;
2792 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2793 PartEntry->FormatState = Unformatted;
2794 PartEntry->AutoCreate = FALSE;
2795 PartEntry->New = TRUE;
2796 PartEntry->BootIndicator = FALSE;
2797 PartEntry->LogicalPartition = TRUE;
2798
2799 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2800 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2801 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2802 }
2803 else
2804 {
2805 DPRINT1("Add new partition entry\n");
2806
2807 /* Insert and initialize a new partition entry */
2808 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2809 HEAP_ZERO_MEMORY,
2810 sizeof(PARTENTRY));
2811 if (NewPartEntry == NULL)
2812 return;
2813
2814 /* Insert the new entry into the list */
2815 InsertTailList(&PartEntry->ListEntry,
2816 &NewPartEntry->ListEntry);
2817
2818 NewPartEntry->DiskEntry = DiskEntry;
2819
2820 NewPartEntry->IsPartitioned = TRUE;
2821 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2822 NewPartEntry->SectorCount.QuadPart = Align(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2823 NewPartEntry->StartSector.QuadPart;
2824 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2825
2826 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2827 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2828 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2829
2830 NewPartEntry->New = TRUE;
2831 NewPartEntry->FormatState = Unformatted;
2832 NewPartEntry->BootIndicator = FALSE;
2833 NewPartEntry->LogicalPartition = TRUE;
2834
2835 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2836 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2837 }
2838
2839 UpdateDiskLayout(DiskEntry);
2840
2841 DiskEntry->Dirty = TRUE;
2842
2843 AssignDriveLetters(List);
2844 }
2845
2846
2847 VOID
2848 DeleteCurrentPartition(
2849 PPARTLIST List)
2850 {
2851 PDISKENTRY DiskEntry;
2852 PPARTENTRY PartEntry;
2853 PPARTENTRY PrevPartEntry;
2854 PPARTENTRY NextPartEntry;
2855 PPARTENTRY LogicalPartEntry;
2856 PLIST_ENTRY Entry;
2857
2858 if (List == NULL ||
2859 List->CurrentDisk == NULL ||
2860 List->CurrentPartition == NULL ||
2861 List->CurrentPartition->IsPartitioned == FALSE)
2862 {
2863 return;
2864 }
2865
2866 DiskEntry = List->CurrentDisk;
2867 PartEntry = List->CurrentPartition;
2868
2869 /* Delete all logical partiton entries if an extended partition will be deleted */
2870 if (DiskEntry->ExtendedPartition == PartEntry)
2871 {
2872 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2873 {
2874 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2875 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2876
2877 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2878 }
2879
2880 DiskEntry->ExtendedPartition = NULL;
2881 }
2882
2883 /* Adjust unpartitioned disk space entries */
2884
2885 /* Get pointer to previous and next unpartitioned entries */
2886 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
2887 PartEntry);
2888
2889 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
2890 PartEntry);
2891
2892 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2893 {
2894 /* Merge previous, current and next unpartitioned entry */
2895
2896 /* Adjust the previous entries length */
2897 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2898
2899 /* Remove the current entry */
2900 RemoveEntryList(&PartEntry->ListEntry);
2901 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2902
2903 /* Remove the next entry */
2904 RemoveEntryList (&NextPartEntry->ListEntry);
2905 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2906
2907 /* Update current partition */
2908 List->CurrentPartition = PrevPartEntry;
2909 }
2910 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2911 {
2912 /* Merge current and previous unpartitioned entry */
2913
2914 /* Adjust the previous entries length */
2915 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2916
2917 /* Remove the current entry */
2918 RemoveEntryList(&PartEntry->ListEntry);
2919 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2920
2921 /* Update current partition */
2922 List->CurrentPartition = PrevPartEntry;
2923 }
2924 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2925 {
2926 /* Merge current and next unpartitioned entry */
2927
2928 /* Adjust the next entries offset and length */
2929 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2930 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2931
2932 /* Remove the current entry */
2933 RemoveEntryList(&PartEntry->ListEntry);
2934 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2935
2936 /* Update current partition */
2937 List->CurrentPartition = NextPartEntry;
2938 }
2939 else
2940 {
2941 /* Nothing to merge but change current entry */
2942 PartEntry->IsPartitioned = FALSE;
2943 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2944 PartEntry->FormatState = Unformatted;
2945 PartEntry->DriveLetter = 0;
2946 }
2947
2948 UpdateDiskLayout(DiskEntry);
2949
2950 DiskEntry->Dirty = TRUE;
2951
2952 AssignDriveLetters(List);
2953 }
2954
2955
2956 VOID
2957 CheckActiveBootPartition(
2958 PPARTLIST List)
2959 {
2960 PDISKENTRY DiskEntry;
2961 PPARTENTRY PartEntry;
2962 PLIST_ENTRY ListEntry;
2963
2964 /* Check for empty disk list */
2965 if (IsListEmpty (&List->DiskListHead))
2966 {
2967 List->BootDisk = NULL;
2968 List->BootPartition = NULL;
2969 return;
2970 }
2971
2972 #if 0
2973 if (List->BootDisk != NULL &&
2974 List->BootPartition != NULL)
2975 {
2976 /* We already have an active boot partition */
2977 return;
2978 }
2979 #endif
2980
2981 /* Choose the currently selected disk */
2982 DiskEntry = List->CurrentDisk;
2983
2984 /* Check for empty partition list */
2985 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
2986 {
2987 List->BootDisk = NULL;
2988 List->BootPartition = NULL;
2989 return;
2990 }
2991
2992 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2993 PARTENTRY,
2994 ListEntry);
2995
2996 /* Set active boot partition */
2997 if ((DiskEntry->NewDisk == TRUE) ||
2998 (PartEntry->BootIndicator == FALSE))
2999 {
3000 PartEntry->BootIndicator = TRUE;
3001 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
3002 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3003 DiskEntry->Dirty = TRUE;
3004
3005 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
3006 List->BootDisk = DiskEntry;
3007 List->BootPartition = PartEntry;
3008
3009 return;
3010 }
3011
3012 /* Disk is not new, scan all partitions to find a bootable one */
3013 List->BootDisk = NULL;
3014 List->BootPartition = NULL;
3015
3016 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3017 while (ListEntry != &DiskEntry->PrimaryPartListHead)
3018 {
3019 PartEntry = CONTAINING_RECORD(ListEntry,
3020 PARTENTRY,
3021 ListEntry);
3022
3023 /* Check if it is partitioned */
3024 if (PartEntry->IsPartitioned)
3025 {
3026 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
3027 PartEntry->BootIndicator)
3028 {
3029 /* Yes, we found it */
3030 List->BootDisk = DiskEntry;
3031 List->BootPartition = PartEntry;
3032
3033 DPRINT("Found bootable partition disk %d, drive letter %c\n",
3034 DiskEntry->DiskNumber, PartEntry->DriveLetter);
3035 break;
3036 }
3037 }
3038
3039 /* Go to the next one */
3040 ListEntry = ListEntry->Flink;
3041 }
3042 }
3043
3044
3045 static
3046 NTSTATUS
3047 WritePartitions(
3048 IN PPARTLIST List,
3049 IN PDISKENTRY DiskEntry)
3050 {
3051 WCHAR DstPath[MAX_PATH];
3052 OBJECT_ATTRIBUTES ObjectAttributes;
3053 IO_STATUS_BLOCK Iosb;
3054 UNICODE_STRING Name;
3055 ULONG BufferSize;
3056 HANDLE FileHandle = NULL;
3057 NTSTATUS Status;
3058
3059 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3060
3061 swprintf(DstPath,
3062 L"\\Device\\Harddisk%d\\Partition0",
3063 DiskEntry->DiskNumber);
3064 RtlInitUnicodeString(&Name,
3065 DstPath);
3066 InitializeObjectAttributes(&ObjectAttributes,
3067 &Name,
3068 0,
3069 NULL,
3070 NULL);
3071
3072 Status = NtOpenFile(&FileHandle,
3073 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3074 &ObjectAttributes,
3075 &Iosb,
3076 0,
3077 FILE_SYNCHRONOUS_IO_NONALERT);
3078 if (!NT_SUCCESS(Status))
3079 {
3080 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3081 return Status;
3082 }
3083
3084 #ifdef DUMP_PARTITION_TABLE
3085 DumpPartitionTable(DiskEntry);
3086 #endif
3087
3088 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3089 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3090 Status = NtDeviceIoControlFile(FileHandle,
3091 NULL,
3092 NULL,
3093 NULL,
3094 &Iosb,
3095 IOCTL_DISK_SET_DRIVE_LAYOUT,
3096 DiskEntry->LayoutBuffer,
3097 BufferSize,
3098 NULL,
3099 0);
3100 if (!NT_SUCCESS(Status))
3101 {
3102 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3103 }
3104
3105 if (FileHandle != NULL)
3106 NtClose(FileHandle);
3107
3108 return Status;
3109 }
3110
3111
3112 BOOLEAN
3113 WritePartitionsToDisk(
3114 PPARTLIST List)
3115 {
3116 PLIST_ENTRY Entry;
3117 PDISKENTRY DiskEntry;
3118
3119 if (List == NULL)
3120 return TRUE;
3121
3122 Entry = List->DiskListHead.Flink;
3123 while (Entry != &List->DiskListHead)
3124 {
3125 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3126
3127 if (DiskEntry->Dirty == TRUE)
3128 {
3129 WritePartitions(List, DiskEntry);
3130 DiskEntry->Dirty = FALSE;
3131 }
3132
3133 Entry = Entry->Flink;
3134 }
3135
3136 return TRUE;
3137 }
3138
3139
3140 BOOL
3141 SetMountedDeviceValues(
3142 PPARTLIST List)
3143 {
3144 PLIST_ENTRY Entry1, Entry2;
3145 PDISKENTRY DiskEntry;
3146 PPARTENTRY PartEntry;
3147 LARGE_INTEGER StartingOffset;
3148
3149 if (List == NULL)
3150 {
3151 return FALSE;
3152 }
3153
3154 Entry1 = List->DiskListHead.Flink;
3155 while (Entry1 != &List->DiskListHead)
3156 {
3157 DiskEntry = CONTAINING_RECORD(Entry1,
3158 DISKENTRY,
3159 ListEntry);
3160
3161 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3162 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3163 {
3164 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3165 if (PartEntry->IsPartitioned)
3166 {
3167 if (PartEntry->DriveLetter)
3168 {
3169 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3170 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3171 DiskEntry->LayoutBuffer->Signature,
3172 StartingOffset))
3173 {
3174 return FALSE;
3175 }
3176 }
3177 }
3178
3179 Entry2 = Entry2->Flink;
3180 }
3181
3182 Entry1 = Entry1->Flink;
3183 }
3184
3185 return TRUE;
3186 }
3187
3188
3189 ULONG
3190 PrimaryPartitionCreationChecks(
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 /* Fail if there are more than 4 partitions in the list */
3204 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3205 return ERROR_PARTITION_TABLE_FULL;
3206
3207 return ERROR_SUCCESS;
3208 }
3209
3210
3211 ULONG
3212 ExtendedPartitionCreationChecks(
3213 IN PPARTLIST List)
3214 {
3215 PDISKENTRY DiskEntry;
3216 PPARTENTRY PartEntry;
3217
3218 DiskEntry = List->CurrentDisk;
3219 PartEntry = List->CurrentPartition;
3220
3221 /* Fail if partition is already in use */
3222 if (PartEntry->IsPartitioned == TRUE)
3223 return ERROR_NEW_PARTITION;
3224
3225 /* Fail if there are more than 4 partitions in the list */
3226 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3227 return ERROR_PARTITION_TABLE_FULL;
3228
3229 /* Fail if there is another extended partition in the list */
3230 if (DiskEntry->ExtendedPartition != NULL)
3231 return ERROR_ONLY_ONE_EXTENDED;
3232
3233 return ERROR_SUCCESS;
3234 }
3235
3236
3237 ULONG
3238 LogicalPartitionCreationChecks(
3239 IN PPARTLIST List)
3240 {
3241 // PDISKENTRY DiskEntry;
3242 PPARTENTRY PartEntry;
3243
3244 // DiskEntry = List->CurrentDisk;
3245 PartEntry = List->CurrentPartition;
3246
3247 /* Fail if partition is already in use */
3248 if (PartEntry->IsPartitioned == TRUE)
3249 return ERROR_NEW_PARTITION;
3250
3251 return ERROR_SUCCESS;
3252 }
3253
3254
3255 BOOL
3256 GetNextUnformattedPartition(
3257 IN PPARTLIST List,
3258 OUT PDISKENTRY *pDiskEntry,
3259 OUT PPARTENTRY *pPartEntry)
3260 {
3261 PLIST_ENTRY Entry1, Entry2;
3262 PDISKENTRY DiskEntry;
3263 PPARTENTRY PartEntry;
3264
3265 Entry1 = List->DiskListHead.Flink;
3266 while (Entry1 != &List->DiskListHead)
3267 {
3268 DiskEntry = CONTAINING_RECORD(Entry1,
3269 DISKENTRY,
3270 ListEntry);
3271
3272 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3273 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3274 {
3275 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3276 if (PartEntry->IsPartitioned && PartEntry->New)
3277 {
3278 *pDiskEntry = DiskEntry;
3279 *pPartEntry = PartEntry;
3280 return TRUE;
3281 }
3282
3283 Entry2 = Entry2->Flink;
3284 }
3285
3286 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3287 while (Entry2 != &DiskEntry->LogicalPartListHead)
3288 {
3289 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3290 if (PartEntry->IsPartitioned && PartEntry->New)
3291 {
3292 *pDiskEntry = DiskEntry;
3293 *pPartEntry = PartEntry;
3294 return TRUE;
3295 }
3296
3297 Entry2 = Entry2->Flink;
3298 }
3299
3300 Entry1 = Entry1->Flink;
3301 }
3302
3303 *pDiskEntry = NULL;
3304 *pPartEntry = NULL;
3305
3306 return FALSE;
3307 }
3308
3309
3310 BOOL
3311 GetNextUncheckedPartition(
3312 IN PPARTLIST List,
3313 OUT PDISKENTRY *pDiskEntry,
3314 OUT PPARTENTRY *pPartEntry)
3315 {
3316 PLIST_ENTRY Entry1, Entry2;
3317 PDISKENTRY DiskEntry;
3318 PPARTENTRY PartEntry;
3319
3320 Entry1 = List->DiskListHead.Flink;
3321 while (Entry1 != &List->DiskListHead)
3322 {
3323 DiskEntry = CONTAINING_RECORD(Entry1,
3324 DISKENTRY,
3325 ListEntry);
3326
3327 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3328 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3329 {
3330 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3331 if (PartEntry->NeedsCheck == TRUE)
3332 {
3333 *pDiskEntry = DiskEntry;
3334 *pPartEntry = PartEntry;
3335 return TRUE;
3336 }
3337
3338 Entry2 = Entry2->Flink;
3339 }
3340
3341 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3342 while (Entry2 != &DiskEntry->LogicalPartListHead)
3343 {
3344 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3345 if (PartEntry->NeedsCheck == TRUE)
3346 {
3347 *pDiskEntry = DiskEntry;
3348 *pPartEntry = PartEntry;
3349 return TRUE;
3350 }
3351
3352 Entry2 = Entry2->Flink;
3353 }
3354
3355 Entry1 = Entry1->Flink;
3356 }
3357
3358 *pDiskEntry = NULL;
3359 *pPartEntry = NULL;
3360
3361 return FALSE;
3362 }
3363
3364 /* EOF */