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