[USETUP]: Fix the primary/extended partitions creation checks introduced in r63392...
[reactos.git] / reactos / base / setup / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: 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 { 0x9F, "BSD/OS" },
130 { 0xA0, "Laptop hibernation" },
131 { 0xA1, "Laptop hibernation" },
132 { 0xA5, "BSD, NetBSD, FreeBSD" },
133 { 0xA6, "OpenBSD" },
134 { 0xA7, "NeXTSTEP" },
135 { 0xA8, "OS-X UFS" },
136 { 0xA9, "NetBSD" },
137 { 0xAB, "OS-X boot" },
138 { 0xAF, "OS-X HFS" },
139 { 0xB6, "NT corrupt mirror" },
140 { 0xB7, "BSDI" },
141 { 0xB8, "BSDI swap" },
142 { 0xBE, "Solaris 8 boot" },
143 { 0xBF, "Solaris x86" },
144 { 0xC0, "NTFT" },
145 { 0xC1, "DR-DOS FAT12" },
146 { 0xC2, "Hidden Linux" },
147 { 0xC3, "Hidden Linux swap" },
148 { 0xC4, "DR-DOS FAT16 (small)" },
149 { 0xC5, "DR-DOS Extended" },
150 { 0xC6, "DR-DOS FAT16" },
151 { 0xC7, "HPFS mirrored" },
152 { 0xCB, "DR-DOS FAT32" },
153 { 0xCC, "DR-DOS FAT32 (LBA)" },
154 { 0xCE, "DR-DOS FAT16 (LBA)" },
155 { 0xD0, "MDOS" },
156 { 0xD1, "MDOS FAT12" },
157 { 0xD4, "MDOS FAT16 (small)" },
158 { 0xD5, "MDOS Extended" },
159 { 0xD6, "MDOS FAT16" },
160 { 0xD8, "CP/M-86" },
161 { 0xDF, "BootIt EMBRM(FAT16/32)" },
162 { 0xEB, "BeOS BFS" },
163 { 0xEE, "EFI GPT protective" },
164 { 0xEF, "EFI filesystem" },
165 { 0xF0, "Linux/PA-RISC boot" },
166 { 0xF2, "DOS 3.3+ second" },
167 { 0xFA, "Bochs" },
168 { 0xFB, "VmWare" },
169 { 0xFC, "VmWare swap" },
170 { 0xFD, "Linux RAID" },
171 { 0xFE, "NT hidden" },
172 };
173
174 VOID
175 GetPartTypeStringFromPartitionType(
176 UCHAR partitionType,
177 PCHAR strPartType,
178 DWORD cchPartType)
179 {
180 /* Determine partition type */
181
182 if (IsContainerPartition(partitionType))
183 {
184 StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
185 }
186 else if (partitionType == PARTITION_ENTRY_UNUSED)
187 {
188 StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
189 }
190 else
191 {
192 UINT i;
193
194 /* Do the table lookup */
195 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
196 {
197 if (partitionType == PartitionTypes[i].Type)
198 {
199 StringCchCopy(strPartType, cchPartType, PartitionTypes[i].Description);
200 return;
201 }
202 }
203
204 /* We are here because the partition type is unknown */
205 StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
206 }
207 }
208
209 /* FUNCTIONS ****************************************************************/
210
211 #ifdef DUMP_PARTITION_TABLE
212 static
213 VOID
214 DumpPartitionTable(
215 PDISKENTRY DiskEntry)
216 {
217 PPARTITION_INFORMATION PartitionInfo;
218 ULONG i;
219
220 DbgPrint("\n");
221 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
222 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
223
224 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
225 {
226 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
227 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
228 i,
229 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
230 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
231 PartitionInfo->HiddenSectors,
232 PartitionInfo->PartitionNumber,
233 PartitionInfo->PartitionType,
234 PartitionInfo->BootIndicator ? '*': ' ',
235 PartitionInfo->RewritePartition ? 'Y': 'N');
236 }
237
238 DbgPrint("\n");
239 }
240 #endif
241
242
243 ULONGLONG
244 AlignDown(
245 IN ULONGLONG Value,
246 IN ULONG Alignment)
247 {
248 ULONGLONG Temp;
249
250 Temp = Value / Alignment;
251
252 return Temp * Alignment;
253 }
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 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 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 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 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 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 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 ULONG DiskNumber,
666 PDISKENTRY DiskEntry,
667 ULONG PartitionIndex,
668 BOOLEAN LogicalPartition)
669 {
670 PPARTITION_INFORMATION PartitionInfo;
671 PPARTENTRY PartEntry;
672
673 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
674 if (PartitionInfo->PartitionType == 0 ||
675 (LogicalPartition == TRUE && 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
704 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
705 DiskEntry->ExtendedPartition = PartEntry;
706 }
707 else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
708 (PartEntry->PartitionType == PARTITION_FAT_16) ||
709 (PartEntry->PartitionType == PARTITION_HUGE) ||
710 (PartEntry->PartitionType == PARTITION_XINT13) ||
711 (PartEntry->PartitionType == PARTITION_FAT32) ||
712 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
713 {
714 #if 0
715 if (CheckFatFormat())
716 {
717 PartEntry->FormatState = Preformatted;
718 }
719 else
720 {
721 PartEntry->FormatState = Unformatted;
722 }
723 #endif
724 PartEntry->FormatState = Preformatted;
725 }
726 else if (PartEntry->PartitionType == PARTITION_EXT2)
727 {
728 #if 0
729 if (CheckExt2Format())
730 {
731 PartEntry->FormatState = Preformatted;
732 }
733 else
734 {
735 PartEntry->FormatState = Unformatted;
736 }
737 #endif
738 PartEntry->FormatState = Preformatted;
739 }
740 else if (PartEntry->PartitionType == PARTITION_IFS)
741 {
742 #if 0
743 if (CheckNtfsFormat())
744 {
745 PartEntry->FormatState = Preformatted;
746 }
747 else if (CheckHpfsFormat())
748 {
749 PartEntry->FormatState = Preformatted;
750 }
751 else
752 {
753 PartEntry->FormatState = Unformatted;
754 }
755 #endif
756 PartEntry->FormatState = Preformatted;
757 }
758 else
759 {
760 PartEntry->FormatState = UnknownFormat;
761 }
762
763 if (LogicalPartition)
764 InsertTailList(&DiskEntry->LogicalPartListHead,
765 &PartEntry->ListEntry);
766 else
767 InsertTailList(&DiskEntry->PrimaryPartListHead,
768 &PartEntry->ListEntry);
769 }
770
771
772 static
773 VOID
774 ScanForUnpartitionedDiskSpace(
775 PDISKENTRY DiskEntry)
776 {
777 ULONGLONG LastStartSector;
778 ULONGLONG LastSectorCount;
779 ULONGLONG LastUnusedSectorCount;
780 PPARTENTRY PartEntry;
781 PPARTENTRY NewPartEntry;
782 PLIST_ENTRY Entry;
783
784 DPRINT("ScanForUnpartitionedDiskSpace()\n");
785
786 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
787 {
788 DPRINT1("No primary partition!\n");
789
790 /* Create a partition table that represents the empty disk */
791 NewPartEntry = RtlAllocateHeap(ProcessHeap,
792 HEAP_ZERO_MEMORY,
793 sizeof(PARTENTRY));
794 if (NewPartEntry == NULL)
795 return;
796
797 NewPartEntry->DiskEntry = DiskEntry;
798
799 NewPartEntry->IsPartitioned = FALSE;
800 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
801 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
802 NewPartEntry->StartSector.QuadPart;
803
804 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
805 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
806 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
807
808 NewPartEntry->FormatState = Unformatted;
809
810 InsertTailList(&DiskEntry->PrimaryPartListHead,
811 &NewPartEntry->ListEntry);
812
813 return;
814 }
815
816 /* Start partition at head 1, cylinder 0 */
817 LastStartSector = DiskEntry->SectorAlignment;
818 LastSectorCount = 0ULL;
819 LastUnusedSectorCount = 0ULL;
820
821 Entry = DiskEntry->PrimaryPartListHead.Flink;
822 while (Entry != &DiskEntry->PrimaryPartListHead)
823 {
824 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
825
826 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
827 PartEntry->SectorCount.QuadPart != 0ULL)
828 {
829 LastUnusedSectorCount =
830 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
831
832 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
833 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
834 {
835 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
836
837 NewPartEntry = RtlAllocateHeap(ProcessHeap,
838 HEAP_ZERO_MEMORY,
839 sizeof(PARTENTRY));
840 if (NewPartEntry == NULL)
841 return;
842
843 NewPartEntry->DiskEntry = DiskEntry;
844
845 NewPartEntry->IsPartitioned = FALSE;
846 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
847 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
848 NewPartEntry->StartSector.QuadPart;
849
850 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
851 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
852 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
853
854 NewPartEntry->FormatState = Unformatted;
855
856 /* Insert the table into the list */
857 InsertTailList(&PartEntry->ListEntry,
858 &NewPartEntry->ListEntry);
859 }
860
861 LastStartSector = PartEntry->StartSector.QuadPart;
862 LastSectorCount = PartEntry->SectorCount.QuadPart;
863 }
864
865 Entry = Entry->Flink;
866 }
867
868 /* Check for trailing unpartitioned disk space */
869 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
870 {
871 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
872
873 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
874 {
875 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
876
877 NewPartEntry = RtlAllocateHeap(ProcessHeap,
878 HEAP_ZERO_MEMORY,
879 sizeof(PARTENTRY));
880 if (NewPartEntry == NULL)
881 return;
882
883 NewPartEntry->DiskEntry = DiskEntry;
884
885 NewPartEntry->IsPartitioned = FALSE;
886 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
887 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
888 NewPartEntry->StartSector.QuadPart;
889
890 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
891 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
892 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
893
894 NewPartEntry->FormatState = Unformatted;
895
896 /* Append the table to the list */
897 InsertTailList(&DiskEntry->PrimaryPartListHead,
898 &NewPartEntry->ListEntry);
899 }
900 }
901
902 if (DiskEntry->ExtendedPartition != NULL)
903 {
904 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
905 {
906 DPRINT1("No logical partition!\n");
907
908 /* Create a partition table entry that represents the empty extended partition */
909 NewPartEntry = RtlAllocateHeap(ProcessHeap,
910 HEAP_ZERO_MEMORY,
911 sizeof(PARTENTRY));
912 if (NewPartEntry == NULL)
913 return;
914
915 NewPartEntry->DiskEntry = DiskEntry;
916 NewPartEntry->LogicalPartition = TRUE;
917
918 NewPartEntry->IsPartitioned = FALSE;
919 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
920 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
921
922 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
923 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
924 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
925
926 NewPartEntry->FormatState = Unformatted;
927
928 InsertTailList(&DiskEntry->LogicalPartListHead,
929 &NewPartEntry->ListEntry);
930
931 return;
932 }
933
934 /* Start partition at head 1, cylinder 0 */
935 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
936 LastSectorCount = 0ULL;
937 LastUnusedSectorCount = 0ULL;
938
939 Entry = DiskEntry->LogicalPartListHead.Flink;
940 while (Entry != &DiskEntry->LogicalPartListHead)
941 {
942 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
943
944 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
945 PartEntry->SectorCount.QuadPart != 0ULL)
946 {
947 LastUnusedSectorCount =
948 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
949
950 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
951 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
952 {
953 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
954
955 NewPartEntry = RtlAllocateHeap(ProcessHeap,
956 HEAP_ZERO_MEMORY,
957 sizeof(PARTENTRY));
958 if (NewPartEntry == NULL)
959 return;
960
961 NewPartEntry->DiskEntry = DiskEntry;
962 NewPartEntry->LogicalPartition = TRUE;
963
964 NewPartEntry->IsPartitioned = FALSE;
965 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
966 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
967 NewPartEntry->StartSector.QuadPart;
968
969 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
970 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
971 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
972
973 NewPartEntry->FormatState = Unformatted;
974
975 /* Insert the table into the list */
976 InsertTailList(&PartEntry->ListEntry,
977 &NewPartEntry->ListEntry);
978 }
979
980 LastStartSector = PartEntry->StartSector.QuadPart;
981 LastSectorCount = PartEntry->SectorCount.QuadPart;
982 }
983
984 Entry = Entry->Flink;
985 }
986
987 /* Check for trailing unpartitioned disk space */
988 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
989 {
990 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
991
992 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
993 {
994 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
995
996 NewPartEntry = RtlAllocateHeap(ProcessHeap,
997 HEAP_ZERO_MEMORY,
998 sizeof(PARTENTRY));
999 if (NewPartEntry == NULL)
1000 return;
1001
1002 NewPartEntry->DiskEntry = DiskEntry;
1003 NewPartEntry->LogicalPartition = TRUE;
1004
1005 NewPartEntry->IsPartitioned = FALSE;
1006 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
1007 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
1008 NewPartEntry->StartSector.QuadPart;
1009
1010 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1011 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1012 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1013
1014 NewPartEntry->FormatState = Unformatted;
1015
1016 /* Append the table to the list */
1017 InsertTailList(&DiskEntry->LogicalPartListHead,
1018 &NewPartEntry->ListEntry);
1019 }
1020 }
1021 }
1022
1023 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1024 }
1025
1026
1027 static
1028 VOID
1029 SetDiskSignature(
1030 IN PPARTLIST List,
1031 IN PDISKENTRY DiskEntry)
1032 {
1033 LARGE_INTEGER SystemTime;
1034 TIME_FIELDS TimeFields;
1035 PLIST_ENTRY Entry2;
1036 PDISKENTRY DiskEntry2;
1037 PUCHAR Buffer;
1038
1039 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1040
1041 while (1)
1042 {
1043 NtQuerySystemTime(&SystemTime);
1044 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1045
1046 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1047 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1048 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1049 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1050
1051 if (DiskEntry->LayoutBuffer->Signature == 0)
1052 {
1053 continue;
1054 }
1055
1056 /* check if the signature already exist */
1057 /* FIXME:
1058 * Check also signatures from disks, which are
1059 * not visible (bootable) by the bios.
1060 */
1061 Entry2 = List->DiskListHead.Flink;
1062 while (Entry2 != &List->DiskListHead)
1063 {
1064 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1065
1066 if (DiskEntry != DiskEntry2 &&
1067 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1068 break;
1069
1070 Entry2 = Entry2->Flink;
1071 }
1072
1073 if (Entry2 == &List->DiskListHead)
1074 break;
1075 }
1076 }
1077
1078
1079 static
1080 VOID
1081 UpdateDiskSignatures(
1082 PPARTLIST List)
1083 {
1084 PLIST_ENTRY Entry;
1085 PDISKENTRY DiskEntry;
1086
1087 /* Print partition lines*/
1088 Entry = List->DiskListHead.Flink;
1089 while (Entry != &List->DiskListHead)
1090 {
1091 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1092
1093 if (DiskEntry->LayoutBuffer &&
1094 DiskEntry->LayoutBuffer->Signature == 0)
1095 {
1096 SetDiskSignature(List, DiskEntry);
1097 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1098 }
1099
1100 Entry = Entry->Flink;
1101 }
1102 }
1103
1104
1105 static
1106 VOID
1107 AddDiskToList(
1108 HANDLE FileHandle,
1109 ULONG DiskNumber,
1110 PPARTLIST List)
1111 {
1112 DISK_GEOMETRY DiskGeometry;
1113 SCSI_ADDRESS ScsiAddress;
1114 PDISKENTRY DiskEntry;
1115 IO_STATUS_BLOCK Iosb;
1116 NTSTATUS Status;
1117 PPARTITION_SECTOR Mbr;
1118 PULONG Buffer;
1119 LARGE_INTEGER FileOffset;
1120 WCHAR Identifier[20];
1121 ULONG Checksum;
1122 ULONG Signature;
1123 ULONG i;
1124 PLIST_ENTRY ListEntry;
1125 PBIOSDISKENTRY BiosDiskEntry;
1126 ULONG LayoutBufferSize;
1127 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1128
1129 Status = NtDeviceIoControlFile(FileHandle,
1130 NULL,
1131 NULL,
1132 NULL,
1133 &Iosb,
1134 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1135 NULL,
1136 0,
1137 &DiskGeometry,
1138 sizeof(DISK_GEOMETRY));
1139 if (!NT_SUCCESS(Status))
1140 {
1141 return;
1142 }
1143
1144 if (DiskGeometry.MediaType != FixedMedia &&
1145 DiskGeometry.MediaType != RemovableMedia)
1146 {
1147 return;
1148 }
1149
1150 Status = NtDeviceIoControlFile(FileHandle,
1151 NULL,
1152 NULL,
1153 NULL,
1154 &Iosb,
1155 IOCTL_SCSI_GET_ADDRESS,
1156 NULL,
1157 0,
1158 &ScsiAddress,
1159 sizeof(SCSI_ADDRESS));
1160 if (!NT_SUCCESS(Status))
1161 {
1162 return;
1163 }
1164
1165 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1166 0,
1167 DiskGeometry.BytesPerSector);
1168 if (Mbr == NULL)
1169 {
1170 return;
1171 }
1172
1173 FileOffset.QuadPart = 0;
1174 Status = NtReadFile(FileHandle,
1175 NULL,
1176 NULL,
1177 NULL,
1178 &Iosb,
1179 (PVOID)Mbr,
1180 DiskGeometry.BytesPerSector,
1181 &FileOffset,
1182 NULL);
1183 if (!NT_SUCCESS(Status))
1184 {
1185 RtlFreeHeap(ProcessHeap, 0, Mbr);
1186 DPRINT1("NtReadFile failed, status=%x\n", Status);
1187 return;
1188 }
1189 Signature = Mbr->Signature;
1190
1191 /* Calculate the MBR checksum */
1192 Checksum = 0;
1193 Buffer = (PULONG)Mbr;
1194 for (i = 0; i < 128; i++)
1195 {
1196 Checksum += Buffer[i];
1197 }
1198 Checksum = ~Checksum + 1;
1199
1200 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
1201 DPRINT("Identifier: %S\n", Identifier);
1202
1203 DiskEntry = RtlAllocateHeap(ProcessHeap,
1204 HEAP_ZERO_MEMORY,
1205 sizeof(DISKENTRY));
1206 if (DiskEntry == NULL)
1207 {
1208 return;
1209 }
1210
1211 // DiskEntry->Checksum = Checksum;
1212 // DiskEntry->Signature = Signature;
1213 DiskEntry->BiosFound = FALSE;
1214
1215 /* Check if this disk has a valid MBR */
1216 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
1217 DiskEntry->NoMbr = TRUE;
1218 else
1219 DiskEntry->NoMbr = FALSE;
1220
1221 /* Free Mbr sector buffer */
1222 RtlFreeHeap(ProcessHeap, 0, Mbr);
1223
1224 ListEntry = List->BiosDiskListHead.Flink;
1225 while (ListEntry != &List->BiosDiskListHead)
1226 {
1227 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1228 /* FIXME:
1229 * Compare the size from bios and the reported size from driver.
1230 * If we have more than one disk with a zero or with the same signatur
1231 * we must create new signatures and reboot. After the reboot,
1232 * it is possible to identify the disks.
1233 */
1234 if (BiosDiskEntry->Signature == Signature &&
1235 BiosDiskEntry->Checksum == Checksum &&
1236 !BiosDiskEntry->Recognized)
1237 {
1238 if (!DiskEntry->BiosFound)
1239 {
1240 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1241 DiskEntry->BiosFound = TRUE;
1242 BiosDiskEntry->Recognized = TRUE;
1243 }
1244 else
1245 {
1246 }
1247 }
1248 ListEntry = ListEntry->Flink;
1249 }
1250
1251 if (!DiskEntry->BiosFound)
1252 {
1253 #if 0
1254 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1255 return;
1256 #else
1257 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1258 #endif
1259 }
1260
1261 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1262 InitializeListHead(&DiskEntry->LogicalPartListHead);
1263
1264 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1265 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1266 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1267 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1268
1269 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1270 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1271 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1272 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1273
1274 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1275 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1276 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1277
1278 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1279 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1280 DiskGeometry.SectorsPerTrack;
1281
1282 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1283 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1284
1285 DiskEntry->DiskNumber = DiskNumber;
1286 DiskEntry->Port = ScsiAddress.PortNumber;
1287 DiskEntry->Bus = ScsiAddress.PathId;
1288 DiskEntry->Id = ScsiAddress.TargetId;
1289
1290 GetDriverName(DiskEntry);
1291
1292 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1293
1294 /* Allocate a layout buffer with 4 partition entries first */
1295 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1296 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1297 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1298 HEAP_ZERO_MEMORY,
1299 LayoutBufferSize);
1300 if (DiskEntry->LayoutBuffer == NULL)
1301 {
1302 DPRINT1("Failed to allocate the disk layout buffer!\n");
1303 return;
1304 }
1305
1306 for (;;)
1307 {
1308 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1309 Status = NtDeviceIoControlFile(FileHandle,
1310 NULL,
1311 NULL,
1312 NULL,
1313 &Iosb,
1314 IOCTL_DISK_GET_DRIVE_LAYOUT,
1315 NULL,
1316 0,
1317 DiskEntry->LayoutBuffer,
1318 LayoutBufferSize);
1319 if (NT_SUCCESS(Status))
1320 break;
1321
1322 if (Status != STATUS_BUFFER_TOO_SMALL)
1323 {
1324 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1325 return;
1326 }
1327
1328 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1329 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1330 HEAP_ZERO_MEMORY,
1331 DiskEntry->LayoutBuffer,
1332 LayoutBufferSize);
1333 if (NewLayoutBuffer == NULL)
1334 {
1335 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1336 return;
1337 }
1338
1339 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1340 }
1341
1342 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1343
1344 #ifdef DUMP_PARTITION_TABLE
1345 DumpPartitionTable(DiskEntry);
1346 #endif
1347
1348 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1349 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1350 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
1351 {
1352 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1353 {
1354 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1355 }
1356 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1357 {
1358 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1359 }
1360 else
1361 {
1362 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1363 }
1364 }
1365 else
1366 {
1367 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1368 }
1369
1370
1371 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1372 {
1373 DiskEntry->NewDisk = TRUE;
1374 DiskEntry->LayoutBuffer->PartitionCount = 4;
1375
1376 for (i = 0; i < 4; i++)
1377 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1378 }
1379 else
1380 {
1381 for (i = 0; i < 4; i++)
1382 {
1383 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1384 }
1385
1386 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1387 {
1388 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1389 }
1390 }
1391
1392 ScanForUnpartitionedDiskSpace(DiskEntry);
1393 }
1394
1395
1396 PPARTLIST
1397 CreatePartitionList(
1398 SHORT Left,
1399 SHORT Top,
1400 SHORT Right,
1401 SHORT Bottom)
1402 {
1403 PPARTLIST List;
1404 OBJECT_ATTRIBUTES ObjectAttributes;
1405 SYSTEM_DEVICE_INFORMATION Sdi;
1406 IO_STATUS_BLOCK Iosb;
1407 ULONG ReturnSize;
1408 NTSTATUS Status;
1409 ULONG DiskNumber;
1410 WCHAR Buffer[MAX_PATH];
1411 UNICODE_STRING Name;
1412 HANDLE FileHandle;
1413
1414 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1415 0,
1416 sizeof (PARTLIST));
1417 if (List == NULL)
1418 return NULL;
1419
1420 List->Left = Left;
1421 List->Top = Top;
1422 List->Right = Right;
1423 List->Bottom = Bottom;
1424
1425 List->Line = 0;
1426 List->Offset = 0;
1427
1428 List->CurrentDisk = NULL;
1429 List->CurrentPartition = NULL;
1430
1431 List->SystemDisk = NULL;
1432 List->SystemPartition = NULL;
1433 List->OriginalSystemDisk = NULL;
1434 List->OriginalSystemPartition = NULL;
1435
1436 List->TempDisk = NULL;
1437 List->TempPartition = NULL;
1438 List->FormatState = Start;
1439
1440 InitializeListHead(&List->DiskListHead);
1441 InitializeListHead(&List->BiosDiskListHead);
1442
1443 EnumerateBiosDiskEntries(List);
1444
1445 Status = NtQuerySystemInformation(SystemDeviceInformation,
1446 &Sdi,
1447 sizeof(SYSTEM_DEVICE_INFORMATION),
1448 &ReturnSize);
1449 if (!NT_SUCCESS(Status))
1450 {
1451 RtlFreeHeap(ProcessHeap, 0, List);
1452 return NULL;
1453 }
1454
1455 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1456 {
1457 swprintf(Buffer,
1458 L"\\Device\\Harddisk%d\\Partition0",
1459 DiskNumber);
1460 RtlInitUnicodeString(&Name,
1461 Buffer);
1462
1463 InitializeObjectAttributes(&ObjectAttributes,
1464 &Name,
1465 0,
1466 NULL,
1467 NULL);
1468
1469 Status = NtOpenFile(&FileHandle,
1470 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1471 &ObjectAttributes,
1472 &Iosb,
1473 FILE_SHARE_READ,
1474 FILE_SYNCHRONOUS_IO_NONALERT);
1475 if (NT_SUCCESS(Status))
1476 {
1477 AddDiskToList(FileHandle, DiskNumber, List);
1478
1479 NtClose(FileHandle);
1480 }
1481 }
1482
1483 UpdateDiskSignatures(List);
1484
1485 AssignDriveLetters(List);
1486
1487 /* Search for first usable disk and partition */
1488 if (IsListEmpty(&List->DiskListHead))
1489 {
1490 List->CurrentDisk = NULL;
1491 List->CurrentPartition = NULL;
1492 }
1493 else
1494 {
1495 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1496 DISKENTRY,
1497 ListEntry);
1498
1499 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1500 {
1501 List->CurrentPartition = 0;
1502 }
1503 else
1504 {
1505 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1506 PARTENTRY,
1507 ListEntry);
1508 }
1509 }
1510
1511 return List;
1512 }
1513
1514
1515 VOID
1516 DestroyPartitionList(
1517 PPARTLIST List)
1518 {
1519 PDISKENTRY DiskEntry;
1520 PBIOSDISKENTRY BiosDiskEntry;
1521 PPARTENTRY PartEntry;
1522 PLIST_ENTRY Entry;
1523
1524 /* Release disk and partition info */
1525 while (!IsListEmpty(&List->DiskListHead))
1526 {
1527 Entry = RemoveHeadList(&List->DiskListHead);
1528 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1529
1530 /* Release driver name */
1531 RtlFreeUnicodeString(&DiskEntry->DriverName);
1532
1533 /* Release primary partition list */
1534 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1535 {
1536 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1537 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1538
1539 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1540 }
1541
1542 /* Release logical partition list */
1543 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1544 {
1545 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1546 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1547
1548 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1549 }
1550
1551 /* Release layout buffer */
1552 if (DiskEntry->LayoutBuffer != NULL)
1553 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1554
1555
1556 /* Release disk entry */
1557 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1558 }
1559
1560 /* Release the bios disk info */
1561 while (!IsListEmpty(&List->BiosDiskListHead))
1562 {
1563 Entry = RemoveHeadList(&List->BiosDiskListHead);
1564 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1565
1566 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1567 }
1568
1569 /* Release list head */
1570 RtlFreeHeap(ProcessHeap, 0, List);
1571 }
1572
1573
1574 static
1575 VOID
1576 PrintEmptyLine(
1577 PPARTLIST List)
1578 {
1579 COORD coPos;
1580 DWORD Written;
1581 USHORT Width;
1582 USHORT Height;
1583
1584 Width = List->Right - List->Left - 1;
1585 Height = List->Bottom - List->Top - 2;
1586
1587 coPos.X = List->Left + 1;
1588 coPos.Y = List->Top + 1 + List->Line;
1589
1590 if (List->Line >= 0 && List->Line <= Height)
1591 {
1592 FillConsoleOutputAttribute(StdOutput,
1593 FOREGROUND_WHITE | BACKGROUND_BLUE,
1594 Width,
1595 coPos,
1596 &Written);
1597
1598 FillConsoleOutputCharacterA(StdOutput,
1599 ' ',
1600 Width,
1601 coPos,
1602 &Written);
1603 }
1604
1605 List->Line++;
1606 }
1607
1608
1609 static
1610 VOID
1611 PrintPartitionData(
1612 PPARTLIST List,
1613 PDISKENTRY DiskEntry,
1614 PPARTENTRY PartEntry)
1615 {
1616 CHAR LineBuffer[128];
1617 COORD coPos;
1618 DWORD Written;
1619 USHORT Width;
1620 USHORT Height;
1621 LARGE_INTEGER PartSize;
1622 PCHAR Unit;
1623 UCHAR Attribute;
1624 CHAR PartTypeString[32];
1625 PCHAR PartType;
1626 PartType = PartTypeString;
1627
1628 Width = List->Right - List->Left - 1;
1629 Height = List->Bottom - List->Top - 2;
1630
1631 coPos.X = List->Left + 1;
1632 coPos.Y = List->Top + 1 + List->Line;
1633
1634 if (PartEntry->IsPartitioned == FALSE)
1635 {
1636 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1637 #if 0
1638 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1639 {
1640 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1641 Unit = MUIGetString(STRING_GB);
1642 }
1643 else
1644 #endif
1645 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1646 {
1647 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1648 Unit = MUIGetString(STRING_MB);
1649 }
1650 else
1651 {
1652 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1653 Unit = MUIGetString(STRING_KB);
1654 }
1655
1656 sprintf(LineBuffer,
1657 MUIGetString(STRING_UNPSPACE),
1658 PartEntry->LogicalPartition ? " " : "",
1659 PartEntry->LogicalPartition ? "" : " ",
1660 PartSize.u.LowPart,
1661 Unit);
1662 }
1663 else
1664 {
1665 /* Determine partition type */
1666 PartTypeString[0] = '\0';
1667 if (PartEntry->New == TRUE)
1668 {
1669 PartType = MUIGetString(STRING_UNFORMATTED);
1670 }
1671 else if (PartEntry->IsPartitioned == TRUE)
1672 {
1673 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
1674 PartTypeString,
1675 ARRAYSIZE(PartTypeString));
1676 PartType = PartTypeString;
1677 }
1678
1679 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1680 #if 0
1681 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1682 {
1683 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1684 Unit = MUIGetString(STRING_GB);
1685 }
1686 else
1687 #endif
1688 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1689 {
1690 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1691 Unit = MUIGetString(STRING_MB);
1692 }
1693 else
1694 {
1695 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1696 Unit = MUIGetString(STRING_KB);
1697 }
1698
1699 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
1700 {
1701 sprintf(LineBuffer,
1702 MUIGetString(STRING_HDDINFOUNK5),
1703 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1704 (PartEntry->DriveLetter == 0) ? '-' : ':',
1705 PartEntry->BootIndicator ? '*' : ' ',
1706 PartEntry->LogicalPartition ? " " : "",
1707 PartEntry->PartitionType,
1708 PartEntry->LogicalPartition ? "" : " ",
1709 PartSize.u.LowPart,
1710 Unit);
1711 }
1712 else
1713 {
1714 sprintf(LineBuffer,
1715 "%c%c %c %s%-24s%s %6lu %s",
1716 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1717 (PartEntry->DriveLetter == 0) ? '-' : ':',
1718 PartEntry->BootIndicator ? '*' : ' ',
1719 PartEntry->LogicalPartition ? " " : "",
1720 PartType,
1721 PartEntry->LogicalPartition ? "" : " ",
1722 PartSize.u.LowPart,
1723 Unit);
1724 }
1725 }
1726
1727 Attribute = (List->CurrentDisk == DiskEntry &&
1728 List->CurrentPartition == PartEntry) ?
1729 FOREGROUND_BLUE | BACKGROUND_WHITE :
1730 FOREGROUND_WHITE | BACKGROUND_BLUE;
1731
1732 if (List->Line >= 0 && List->Line <= Height)
1733 {
1734 FillConsoleOutputCharacterA(StdOutput,
1735 ' ',
1736 Width,
1737 coPos,
1738 &Written);
1739 }
1740 coPos.X += 4;
1741 Width -= 8;
1742 if (List->Line >= 0 && List->Line <= Height)
1743 {
1744 FillConsoleOutputAttribute(StdOutput,
1745 Attribute,
1746 Width,
1747 coPos,
1748 &Written);
1749 }
1750 coPos.X++;
1751 Width -= 2;
1752 if (List->Line >= 0 && List->Line <= Height)
1753 {
1754 WriteConsoleOutputCharacterA(StdOutput,
1755 LineBuffer,
1756 min(strlen(LineBuffer), Width),
1757 coPos,
1758 &Written);
1759 }
1760
1761 List->Line++;
1762 }
1763
1764
1765 static
1766 VOID
1767 PrintDiskData(
1768 PPARTLIST List,
1769 PDISKENTRY DiskEntry)
1770 {
1771 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1772 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1773 CHAR LineBuffer[128];
1774 COORD coPos;
1775 DWORD Written;
1776 USHORT Width;
1777 USHORT Height;
1778 ULARGE_INTEGER DiskSize;
1779 PCHAR Unit;
1780
1781 Width = List->Right - List->Left - 1;
1782 Height = List->Bottom - List->Top - 2;
1783
1784 coPos.X = List->Left + 1;
1785 coPos.Y = List->Top + 1 + List->Line;
1786
1787 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1788 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1789 {
1790 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1791 Unit = MUIGetString(STRING_GB);
1792 }
1793 else
1794 {
1795 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1796 if (DiskSize.QuadPart == 0)
1797 DiskSize.QuadPart = 1;
1798 Unit = MUIGetString(STRING_MB);
1799 }
1800
1801 if (DiskEntry->DriverName.Length > 0)
1802 {
1803 sprintf(LineBuffer,
1804 MUIGetString(STRING_HDINFOPARTSELECT),
1805 DiskSize.u.LowPart,
1806 Unit,
1807 DiskEntry->DiskNumber,
1808 DiskEntry->Port,
1809 DiskEntry->Bus,
1810 DiskEntry->Id,
1811 DiskEntry->DriverName.Buffer);
1812 }
1813 else
1814 {
1815 sprintf(LineBuffer,
1816 MUIGetString(STRING_HDDINFOUNK6),
1817 DiskSize.u.LowPart,
1818 Unit,
1819 DiskEntry->DiskNumber,
1820 DiskEntry->Port,
1821 DiskEntry->Bus,
1822 DiskEntry->Id);
1823 }
1824
1825 if (List->Line >= 0 && List->Line <= Height)
1826 {
1827 FillConsoleOutputAttribute(StdOutput,
1828 FOREGROUND_WHITE | BACKGROUND_BLUE,
1829 Width,
1830 coPos,
1831 &Written);
1832
1833 FillConsoleOutputCharacterA(StdOutput,
1834 ' ',
1835 Width,
1836 coPos,
1837 &Written);
1838 }
1839
1840 coPos.X++;
1841 if (List->Line >= 0 && List->Line <= Height)
1842 {
1843 WriteConsoleOutputCharacterA(StdOutput,
1844 LineBuffer,
1845 min((USHORT)strlen(LineBuffer), Width - 2),
1846 coPos,
1847 &Written);
1848 }
1849
1850 List->Line++;
1851
1852 /* Print separator line */
1853 PrintEmptyLine(List);
1854
1855 /* Print partition lines */
1856 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1857 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1858 {
1859 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1860
1861 PrintPartitionData(List,
1862 DiskEntry,
1863 PrimaryPartEntry);
1864
1865 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1866 {
1867 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1868 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1869 {
1870 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1871
1872 PrintPartitionData(List,
1873 DiskEntry,
1874 LogicalPartEntry);
1875
1876 LogicalEntry = LogicalEntry->Flink;
1877 }
1878 }
1879
1880 PrimaryEntry = PrimaryEntry->Flink;
1881 }
1882
1883 /* Print separator line */
1884 PrintEmptyLine(List);
1885 }
1886
1887
1888 VOID
1889 DrawPartitionList(
1890 PPARTLIST List)
1891 {
1892 PLIST_ENTRY Entry, Entry2;
1893 PDISKENTRY DiskEntry;
1894 PPARTENTRY PartEntry = NULL;
1895 COORD coPos;
1896 DWORD Written;
1897 SHORT i;
1898 SHORT CurrentDiskLine;
1899 SHORT CurrentPartLine;
1900 SHORT LastLine;
1901 BOOL CurrentPartLineFound = FALSE;
1902 BOOL CurrentDiskLineFound = FALSE;
1903
1904 /* Calculate the line of the current disk and partition */
1905 CurrentDiskLine = 0;
1906 CurrentPartLine = 0;
1907 LastLine = 0;
1908
1909 Entry = List->DiskListHead.Flink;
1910 while (Entry != &List->DiskListHead)
1911 {
1912 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1913
1914 LastLine += 2;
1915 if (CurrentPartLineFound == FALSE)
1916 {
1917 CurrentPartLine += 2;
1918 }
1919
1920 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1921 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1922 {
1923 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1924 if (PartEntry == List->CurrentPartition)
1925 {
1926 CurrentPartLineFound = TRUE;
1927 }
1928
1929 Entry2 = Entry2->Flink;
1930 if (CurrentPartLineFound == FALSE)
1931 {
1932 CurrentPartLine++;
1933 }
1934
1935 LastLine++;
1936 }
1937
1938 if (CurrentPartLineFound == FALSE)
1939 {
1940 Entry2 = DiskEntry->LogicalPartListHead.Flink;
1941 while (Entry2 != &DiskEntry->LogicalPartListHead)
1942 {
1943 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1944 if (PartEntry == List->CurrentPartition)
1945 {
1946 CurrentPartLineFound = TRUE;
1947 }
1948
1949 Entry2 = Entry2->Flink;
1950 if (CurrentPartLineFound == FALSE)
1951 {
1952 CurrentPartLine++;
1953 }
1954
1955 LastLine++;
1956 }
1957 }
1958
1959 if (DiskEntry == List->CurrentDisk)
1960 {
1961 CurrentDiskLineFound = TRUE;
1962 }
1963
1964 Entry = Entry->Flink;
1965 if (Entry != &List->DiskListHead)
1966 {
1967 if (CurrentDiskLineFound == FALSE)
1968 {
1969 CurrentPartLine ++;
1970 CurrentDiskLine = CurrentPartLine;
1971 }
1972
1973 LastLine++;
1974 }
1975 else
1976 {
1977 LastLine--;
1978 }
1979 }
1980
1981 /* If it possible, make the disk name visible */
1982 if (CurrentPartLine < List->Offset)
1983 {
1984 List->Offset = CurrentPartLine;
1985 }
1986 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1987 {
1988 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1989 }
1990
1991 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1992 {
1993 List->Offset = CurrentDiskLine;
1994 }
1995
1996 /* draw upper left corner */
1997 coPos.X = List->Left;
1998 coPos.Y = List->Top;
1999 FillConsoleOutputCharacterA(StdOutput,
2000 0xDA, // '+',
2001 1,
2002 coPos,
2003 &Written);
2004
2005 /* draw upper edge */
2006 coPos.X = List->Left + 1;
2007 coPos.Y = List->Top;
2008 if (List->Offset == 0)
2009 {
2010 FillConsoleOutputCharacterA(StdOutput,
2011 0xC4, // '-',
2012 List->Right - List->Left - 1,
2013 coPos,
2014 &Written);
2015 }
2016 else
2017 {
2018 FillConsoleOutputCharacterA(StdOutput,
2019 0xC4, // '-',
2020 List->Right - List->Left - 5,
2021 coPos,
2022 &Written);
2023 coPos.X = List->Right - 5;
2024 WriteConsoleOutputCharacterA(StdOutput,
2025 "(\x18)", // "(up)"
2026 3,
2027 coPos,
2028 &Written);
2029 coPos.X = List->Right - 2;
2030 FillConsoleOutputCharacterA(StdOutput,
2031 0xC4, // '-',
2032 2,
2033 coPos,
2034 &Written);
2035 }
2036
2037 /* draw upper right corner */
2038 coPos.X = List->Right;
2039 coPos.Y = List->Top;
2040 FillConsoleOutputCharacterA(StdOutput,
2041 0xBF, // '+',
2042 1,
2043 coPos,
2044 &Written);
2045
2046 /* draw left and right edge */
2047 for (i = List->Top + 1; i < List->Bottom; i++)
2048 {
2049 coPos.X = List->Left;
2050 coPos.Y = i;
2051 FillConsoleOutputCharacterA(StdOutput,
2052 0xB3, // '|',
2053 1,
2054 coPos,
2055 &Written);
2056
2057 coPos.X = List->Right;
2058 FillConsoleOutputCharacterA(StdOutput,
2059 0xB3, //'|',
2060 1,
2061 coPos,
2062 &Written);
2063 }
2064
2065 /* draw lower left corner */
2066 coPos.X = List->Left;
2067 coPos.Y = List->Bottom;
2068 FillConsoleOutputCharacterA(StdOutput,
2069 0xC0, // '+',
2070 1,
2071 coPos,
2072 &Written);
2073
2074 /* draw lower edge */
2075 coPos.X = List->Left + 1;
2076 coPos.Y = List->Bottom;
2077 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
2078 {
2079 FillConsoleOutputCharacterA(StdOutput,
2080 0xC4, // '-',
2081 List->Right - List->Left - 1,
2082 coPos,
2083 &Written);
2084 }
2085 else
2086 {
2087 FillConsoleOutputCharacterA(StdOutput,
2088 0xC4, // '-',
2089 List->Right - List->Left - 5,
2090 coPos,
2091 &Written);
2092 coPos.X = List->Right - 5;
2093 WriteConsoleOutputCharacterA(StdOutput,
2094 "(\x19)", // "(down)"
2095 3,
2096 coPos,
2097 &Written);
2098 coPos.X = List->Right - 2;
2099 FillConsoleOutputCharacterA(StdOutput,
2100 0xC4, // '-',
2101 2,
2102 coPos,
2103 &Written);
2104 }
2105
2106 /* draw lower right corner */
2107 coPos.X = List->Right;
2108 coPos.Y = List->Bottom;
2109 FillConsoleOutputCharacterA(StdOutput,
2110 0xD9, // '+',
2111 1,
2112 coPos,
2113 &Written);
2114
2115 /* print list entries */
2116 List->Line = - List->Offset;
2117
2118 Entry = List->DiskListHead.Flink;
2119 while (Entry != &List->DiskListHead)
2120 {
2121 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2122
2123 /* Print disk entry */
2124 PrintDiskData(List,
2125 DiskEntry);
2126
2127 Entry = Entry->Flink;
2128 }
2129 }
2130
2131
2132 DWORD
2133 SelectPartition(
2134 PPARTLIST List,
2135 ULONG DiskNumber,
2136 ULONG PartitionNumber)
2137 {
2138 PDISKENTRY DiskEntry;
2139 PPARTENTRY PartEntry;
2140 PLIST_ENTRY Entry1;
2141 PLIST_ENTRY Entry2;
2142
2143 /* Check for empty disks */
2144 if (IsListEmpty(&List->DiskListHead))
2145 return FALSE;
2146
2147 /* Check for first usable entry on next disk */
2148 Entry1 = List->CurrentDisk->ListEntry.Flink;
2149 while (Entry1 != &List->DiskListHead)
2150 {
2151 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
2152
2153 if (DiskEntry->DiskNumber == DiskNumber)
2154 {
2155 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2156 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2157 {
2158 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2159
2160 if (PartEntry->PartitionNumber == PartitionNumber)
2161 {
2162 List->CurrentDisk = DiskEntry;
2163 List->CurrentPartition = PartEntry;
2164 DrawPartitionList(List);
2165 return TRUE;
2166 }
2167
2168 Entry2 = Entry2->Flink;
2169 }
2170
2171 return FALSE;
2172 }
2173
2174 Entry1 = Entry1->Flink;
2175 }
2176
2177 return FALSE;
2178 }
2179
2180
2181 BOOL
2182 ScrollDownPartitionList(
2183 PPARTLIST List)
2184 {
2185 PLIST_ENTRY DiskListEntry;
2186 PLIST_ENTRY PartListEntry;
2187 PDISKENTRY DiskEntry;
2188 PPARTENTRY PartEntry;
2189
2190 /* Fail, if no disks are available */
2191 if (IsListEmpty(&List->DiskListHead))
2192 return FALSE;
2193
2194 /* Check for next usable entry on current disk */
2195 if (List->CurrentPartition != NULL)
2196 {
2197 if (List->CurrentPartition->LogicalPartition)
2198 {
2199 /* Logical partition */
2200
2201 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2202 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2203 {
2204 /* Next logical partition */
2205 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2206
2207 List->CurrentPartition = PartEntry;
2208 return TRUE;
2209 }
2210 else
2211 {
2212 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2213 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2214 {
2215 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2216
2217 List->CurrentPartition = PartEntry;
2218 return TRUE;
2219 }
2220 }
2221 }
2222 else
2223 {
2224 /* Primary or extended partition */
2225
2226 if (List->CurrentPartition->IsPartitioned == TRUE &&
2227 IsContainerPartition(List->CurrentPartition->PartitionType))
2228 {
2229 /* First logical partition */
2230 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2231 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2232 {
2233 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2234
2235 List->CurrentPartition = PartEntry;
2236 return TRUE;
2237 }
2238 }
2239 else
2240 {
2241 /* Next primary partition */
2242 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2243 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2244 {
2245 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2246
2247 List->CurrentPartition = PartEntry;
2248 return TRUE;
2249 }
2250 }
2251 }
2252 }
2253
2254 /* Search for the first partition entry on the next disk */
2255 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2256 while (DiskListEntry != &List->DiskListHead)
2257 {
2258 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2259
2260 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2261 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2262 {
2263 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2264
2265 List->CurrentDisk = DiskEntry;
2266 List->CurrentPartition = PartEntry;
2267 return TRUE;
2268 }
2269
2270 DiskListEntry = DiskListEntry->Flink;
2271 }
2272
2273 return FALSE;
2274 }
2275
2276
2277 BOOL
2278 ScrollUpPartitionList(
2279 PPARTLIST List)
2280 {
2281 PLIST_ENTRY DiskListEntry;
2282 PLIST_ENTRY PartListEntry;
2283 PDISKENTRY DiskEntry;
2284 PPARTENTRY PartEntry;
2285
2286 /* Fail, if no disks are available */
2287 if (IsListEmpty(&List->DiskListHead))
2288 return FALSE;
2289
2290 /* Check for previous usable entry on current disk */
2291 if (List->CurrentPartition != NULL)
2292 {
2293 if (List->CurrentPartition->LogicalPartition)
2294 {
2295 /* Logical partition */
2296 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2297 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2298 {
2299 /* Previous logical partition */
2300 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2301 }
2302 else
2303 {
2304 /* Extended partition*/
2305 PartEntry = List->CurrentDisk->ExtendedPartition;
2306 }
2307
2308 List->CurrentPartition = PartEntry;
2309 return TRUE;
2310 }
2311 else
2312 {
2313 /* Primary or extended partition */
2314
2315 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2316 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2317 {
2318 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2319
2320 if (PartEntry->IsPartitioned == TRUE &&
2321 IsContainerPartition(PartEntry->PartitionType))
2322 {
2323 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2324 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2325 }
2326
2327 List->CurrentPartition = PartEntry;
2328 return TRUE;
2329 }
2330
2331 }
2332 }
2333
2334 /* Search for the last partition entry on the previous disk */
2335 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2336 while (DiskListEntry != &List->DiskListHead)
2337 {
2338 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2339
2340 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2341 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2342 {
2343 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2344
2345 if (PartEntry->IsPartitioned == TRUE &&
2346 IsContainerPartition(PartEntry->PartitionType))
2347 {
2348 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2349 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2350 {
2351 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2352
2353 List->CurrentDisk = DiskEntry;
2354 List->CurrentPartition = PartEntry;
2355 return TRUE;
2356 }
2357 }
2358 else
2359 {
2360 List->CurrentDisk = DiskEntry;
2361 List->CurrentPartition = PartEntry;
2362 return TRUE;
2363 }
2364 }
2365
2366 DiskListEntry = DiskListEntry->Blink;
2367 }
2368
2369 return FALSE;
2370 }
2371
2372
2373 static
2374 BOOLEAN
2375 IsEmptyLayoutEntry(
2376 PPARTITION_INFORMATION PartitionInfo)
2377 {
2378 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2379 PartitionInfo->PartitionLength.QuadPart == 0)
2380 return TRUE;
2381
2382 return FALSE;
2383 }
2384
2385
2386 static
2387 BOOLEAN
2388 IsSamePrimaryLayoutEntry(
2389 IN PPARTITION_INFORMATION PartitionInfo,
2390 IN PDISKENTRY DiskEntry,
2391 IN PPARTENTRY PartEntry)
2392 {
2393 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2394 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2395 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2396 // PartitionInfo->PartitionType == PartEntry->PartitionType
2397 return TRUE;
2398
2399 return FALSE;
2400 }
2401
2402
2403 static
2404 ULONG
2405 GetPrimaryPartitionCount(
2406 IN PDISKENTRY DiskEntry)
2407 {
2408 PLIST_ENTRY Entry;
2409 PPARTENTRY PartEntry;
2410 ULONG Count = 0;
2411
2412 Entry = DiskEntry->PrimaryPartListHead.Flink;
2413 while (Entry != &DiskEntry->PrimaryPartListHead)
2414 {
2415 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2416 if (PartEntry->IsPartitioned == TRUE)
2417 Count++;
2418
2419 Entry = Entry->Flink;
2420 }
2421
2422 return Count;
2423 }
2424
2425
2426 static
2427 ULONG
2428 GetLogicalPartitionCount(
2429 PDISKENTRY DiskEntry)
2430 {
2431 PLIST_ENTRY ListEntry;
2432 PPARTENTRY PartEntry;
2433 ULONG Count = 0;
2434
2435 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2436 while (ListEntry != &DiskEntry->LogicalPartListHead)
2437 {
2438 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2439 if (PartEntry->IsPartitioned)
2440 Count++;
2441
2442 ListEntry = ListEntry->Flink;
2443 }
2444
2445 return Count;
2446 }
2447
2448
2449 static
2450 BOOL
2451 ReAllocateLayoutBuffer(
2452 PDISKENTRY DiskEntry)
2453 {
2454 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2455 ULONG NewPartitionCount;
2456 ULONG CurrentPartitionCount = 0;
2457 ULONG LayoutBufferSize;
2458 ULONG i;
2459
2460 DPRINT1("ReAllocateLayoutBuffer()\n");
2461
2462 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2463
2464 if (DiskEntry->LayoutBuffer)
2465 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2466
2467 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2468 CurrentPartitionCount, NewPartitionCount);
2469
2470 if (CurrentPartitionCount == NewPartitionCount)
2471 return TRUE;
2472
2473 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2474 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2475 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2476 HEAP_ZERO_MEMORY,
2477 DiskEntry->LayoutBuffer,
2478 LayoutBufferSize);
2479 if (NewLayoutBuffer == NULL)
2480 {
2481 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2482 return FALSE;
2483 }
2484
2485 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2486 if (NewPartitionCount > CurrentPartitionCount)
2487 {
2488 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2489 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2490 }
2491
2492 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2493 DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
2494
2495 return TRUE;
2496 }
2497
2498
2499 static
2500 VOID
2501 UpdateDiskLayout(
2502 IN PDISKENTRY DiskEntry)
2503 {
2504 PPARTITION_INFORMATION PartitionInfo;
2505 PPARTITION_INFORMATION LinkInfo = NULL;
2506 PLIST_ENTRY ListEntry;
2507 PPARTENTRY PartEntry;
2508 LARGE_INTEGER HiddenSectors64;
2509 ULONG Index;
2510 ULONG PartitionNumber = 1;
2511
2512 DPRINT1("UpdateDiskLayout()\n");
2513
2514 /* Resize the layout buffer if necessary */
2515 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2516 {
2517 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2518 return;
2519 }
2520
2521 /* Update the primary partition table */
2522 Index = 0;
2523 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2524 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2525 {
2526 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2527
2528 if (PartEntry->IsPartitioned == TRUE)
2529 {
2530 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2531
2532 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2533 {
2534 DPRINT1("Updating primary partition entry %lu\n", Index);
2535
2536 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2537 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2538 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2539 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2540 PartitionInfo->PartitionType = PartEntry->PartitionType;
2541 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2542 PartitionInfo->RecognizedPartition = FALSE;
2543 PartitionInfo->RewritePartition = TRUE;
2544 }
2545
2546 PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2547 PartEntry->PartitionIndex = Index;
2548
2549 if (!IsContainerPartition(PartEntry->PartitionType))
2550 PartitionNumber++;
2551
2552 Index++;
2553 }
2554
2555 ListEntry = ListEntry->Flink;
2556 }
2557
2558 /* Update the logical partition tables */
2559 Index = 4;
2560 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2561 while (ListEntry != &DiskEntry->LogicalPartListHead)
2562 {
2563 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2564
2565 if (PartEntry->IsPartitioned)
2566 {
2567 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2568
2569 DPRINT1("Updating logical partition entry %lu\n", Index);
2570
2571 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2572 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2573 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2574 PartitionInfo->PartitionNumber = PartitionNumber;
2575 PartitionInfo->PartitionType = PartEntry->PartitionType;
2576 PartitionInfo->BootIndicator = FALSE;
2577 PartitionInfo->RecognizedPartition = FALSE;
2578 PartitionInfo->RewritePartition = TRUE;
2579
2580 PartEntry->PartitionNumber = PartitionNumber;
2581 PartEntry->PartitionIndex = Index;
2582
2583 /* Fill the link entry of the previous partition table */
2584 if (LinkInfo != NULL)
2585 {
2586 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2587 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2588 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2589 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2590 LinkInfo->PartitionNumber = 0;
2591 LinkInfo->PartitionType = PARTITION_EXTENDED;
2592 LinkInfo->BootIndicator = FALSE;
2593 LinkInfo->RecognizedPartition = FALSE;
2594 LinkInfo->RewritePartition = TRUE;
2595 }
2596
2597 /* Save a pointer to the link entry of the current partition table */
2598 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2599
2600 PartitionNumber++;
2601 Index += 4;
2602 }
2603
2604 ListEntry = ListEntry->Flink;
2605 }
2606
2607 /* Wipe unused primary partition table entries */
2608 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2609 {
2610 DPRINT1("Primary partition entry %lu\n", Index);
2611
2612 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2613
2614 if (!IsEmptyLayoutEntry(PartitionInfo))
2615 {
2616 DPRINT1("Wiping primary partition entry %lu\n", Index);
2617
2618 PartitionInfo->StartingOffset.QuadPart = 0;
2619 PartitionInfo->PartitionLength.QuadPart = 0;
2620 PartitionInfo->HiddenSectors = 0;
2621 PartitionInfo->PartitionNumber = 0;
2622 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2623 PartitionInfo->BootIndicator = FALSE;
2624 PartitionInfo->RecognizedPartition = FALSE;
2625 PartitionInfo->RewritePartition = TRUE;
2626 }
2627 }
2628
2629 /* Wipe unused logical partition table entries */
2630 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2631 {
2632 if (Index % 4 >= 2)
2633 {
2634 DPRINT1("Logical partition entry %lu\n", Index);
2635
2636 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2637
2638 if (!IsEmptyLayoutEntry(PartitionInfo))
2639 {
2640 DPRINT1("Wiping partition entry %lu\n", Index);
2641
2642 PartitionInfo->StartingOffset.QuadPart = 0;
2643 PartitionInfo->PartitionLength.QuadPart = 0;
2644 PartitionInfo->HiddenSectors = 0;
2645 PartitionInfo->PartitionNumber = 0;
2646 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2647 PartitionInfo->BootIndicator = FALSE;
2648 PartitionInfo->RecognizedPartition = FALSE;
2649 PartitionInfo->RewritePartition = TRUE;
2650 }
2651 }
2652 }
2653
2654 #ifdef DUMP_PARTITION_TABLE
2655 DumpPartitionTable(DiskEntry);
2656 #endif
2657 }
2658
2659
2660 static
2661 PPARTENTRY
2662 GetPrevUnpartitionedEntry(
2663 PDISKENTRY DiskEntry,
2664 PPARTENTRY PartEntry)
2665 {
2666 PPARTENTRY PrevPartEntry;
2667 PLIST_ENTRY ListHead;
2668
2669 if (PartEntry->LogicalPartition)
2670 ListHead = &DiskEntry->LogicalPartListHead;
2671 else
2672 ListHead = &DiskEntry->PrimaryPartListHead;
2673
2674 if (PartEntry->ListEntry.Blink != ListHead)
2675 {
2676 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2677 PARTENTRY,
2678 ListEntry);
2679 if (PrevPartEntry->IsPartitioned == FALSE)
2680 return PrevPartEntry;
2681 }
2682
2683 return NULL;
2684 }
2685
2686
2687 static
2688 PPARTENTRY
2689 GetNextUnpartitionedEntry(
2690 PDISKENTRY DiskEntry,
2691 PPARTENTRY PartEntry)
2692 {
2693 PPARTENTRY NextPartEntry;
2694 PLIST_ENTRY ListHead;
2695
2696 if (PartEntry->LogicalPartition)
2697 ListHead = &DiskEntry->LogicalPartListHead;
2698 else
2699 ListHead = &DiskEntry->PrimaryPartListHead;
2700
2701 if (PartEntry->ListEntry.Flink != ListHead)
2702 {
2703 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2704 PARTENTRY,
2705 ListEntry);
2706 if (NextPartEntry->IsPartitioned == FALSE)
2707 return NextPartEntry;
2708 }
2709
2710 return NULL;
2711 }
2712
2713
2714 VOID
2715 CreatePrimaryPartition(
2716 PPARTLIST List,
2717 ULONGLONG SectorCount,
2718 BOOLEAN AutoCreate)
2719 {
2720 PDISKENTRY DiskEntry;
2721 PPARTENTRY PartEntry;
2722 PPARTENTRY NewPartEntry;
2723
2724 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2725
2726 if (List == NULL ||
2727 List->CurrentDisk == NULL ||
2728 List->CurrentPartition == NULL ||
2729 List->CurrentPartition->IsPartitioned == TRUE)
2730 {
2731 return;
2732 }
2733
2734 DiskEntry = List->CurrentDisk;
2735 PartEntry = List->CurrentPartition;
2736
2737 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2738
2739 if (AutoCreate == TRUE ||
2740 AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2741 {
2742 DPRINT1("Convert existing partition entry\n");
2743
2744 /* Convert current entry to 'new (unformatted)' */
2745 PartEntry->IsPartitioned = TRUE;
2746 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2747 PartEntry->FormatState = Unformatted;
2748 PartEntry->AutoCreate = AutoCreate;
2749 PartEntry->New = TRUE;
2750 PartEntry->BootIndicator = FALSE;
2751
2752 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2753 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2754 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2755 }
2756 else
2757 {
2758 DPRINT1("Add new partition entry\n");
2759
2760 /* Insert and initialize a new partition entry */
2761 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2762 HEAP_ZERO_MEMORY,
2763 sizeof(PARTENTRY));
2764 if (NewPartEntry == NULL)
2765 return;
2766
2767 /* Insert the new entry into the list */
2768 InsertTailList(&PartEntry->ListEntry,
2769 &NewPartEntry->ListEntry);
2770
2771 NewPartEntry->DiskEntry = DiskEntry;
2772
2773 NewPartEntry->IsPartitioned = TRUE;
2774 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2775 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2776 NewPartEntry->StartSector.QuadPart;
2777 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2778
2779 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2780 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2781 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2782
2783 NewPartEntry->New = TRUE;
2784 NewPartEntry->FormatState = Unformatted;
2785 NewPartEntry->BootIndicator = FALSE;
2786
2787 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2788 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2789 }
2790
2791 UpdateDiskLayout(DiskEntry);
2792
2793 DiskEntry->Dirty = TRUE;
2794
2795 AssignDriveLetters(List);
2796 }
2797
2798
2799 static
2800 VOID
2801 AddLogicalDiskSpace(
2802 PDISKENTRY DiskEntry)
2803 {
2804 PPARTENTRY NewPartEntry;
2805
2806 DPRINT1("AddLogicalDiskSpace()\n");
2807
2808 /* Create a partition table entry that represents the empty space in the container partition */
2809 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2810 HEAP_ZERO_MEMORY,
2811 sizeof(PARTENTRY));
2812 if (NewPartEntry == NULL)
2813 return;
2814
2815 NewPartEntry->DiskEntry = DiskEntry;
2816 NewPartEntry->LogicalPartition = TRUE;
2817
2818 NewPartEntry->IsPartitioned = FALSE;
2819 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2820 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2821
2822 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2823 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2824 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2825
2826 NewPartEntry->FormatState = Unformatted;
2827
2828 InsertTailList(&DiskEntry->LogicalPartListHead,
2829 &NewPartEntry->ListEntry);
2830 }
2831
2832
2833 VOID
2834 CreateExtendedPartition(
2835 PPARTLIST List,
2836 ULONGLONG SectorCount)
2837 {
2838 PDISKENTRY DiskEntry;
2839 PPARTENTRY PartEntry;
2840 PPARTENTRY NewPartEntry;
2841
2842 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2843
2844 if (List == NULL ||
2845 List->CurrentDisk == NULL ||
2846 List->CurrentPartition == NULL ||
2847 List->CurrentPartition->IsPartitioned == TRUE)
2848 {
2849 return;
2850 }
2851
2852 DiskEntry = List->CurrentDisk;
2853 PartEntry = List->CurrentPartition;
2854
2855 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2856
2857 if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2858 {
2859 DPRINT1("Convert existing partition entry\n");
2860
2861 /* Convert current entry to 'new (unformatted)' */
2862 PartEntry->IsPartitioned = TRUE;
2863 PartEntry->FormatState = Formatted;
2864 PartEntry->AutoCreate = FALSE;
2865 PartEntry->New = FALSE;
2866 PartEntry->BootIndicator = FALSE;
2867
2868 if (PartEntry->StartSector.QuadPart < 1450560)
2869 {
2870 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2871 PartEntry->PartitionType = PARTITION_EXTENDED;
2872 }
2873 else
2874 {
2875 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2876 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2877 }
2878
2879 DiskEntry->ExtendedPartition = PartEntry;
2880
2881 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2882 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2883 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2884 }
2885 else
2886 {
2887 DPRINT1("Add new partition entry\n");
2888
2889 /* Insert and initialize a new partition entry */
2890 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2891 HEAP_ZERO_MEMORY,
2892 sizeof(PARTENTRY));
2893 if (NewPartEntry == NULL)
2894 return;
2895
2896 /* Insert the new entry into the list */
2897 InsertTailList(&PartEntry->ListEntry,
2898 &NewPartEntry->ListEntry);
2899
2900 NewPartEntry->DiskEntry = DiskEntry;
2901
2902 NewPartEntry->IsPartitioned = TRUE;
2903 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2904 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2905 NewPartEntry->StartSector.QuadPart;
2906
2907 NewPartEntry->New = FALSE;
2908 NewPartEntry->FormatState = Formatted;
2909 NewPartEntry->BootIndicator = FALSE;
2910
2911 if (NewPartEntry->StartSector.QuadPart < 1450560)
2912 {
2913 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2914 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2915 }
2916 else
2917 {
2918 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2919 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2920 }
2921
2922 DiskEntry->ExtendedPartition = NewPartEntry;
2923
2924 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2925 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2926
2927 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2928 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2929 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2930 }
2931
2932 AddLogicalDiskSpace(DiskEntry);
2933
2934 UpdateDiskLayout(DiskEntry);
2935
2936 DiskEntry->Dirty = TRUE;
2937
2938 AssignDriveLetters(List);
2939 }
2940
2941
2942 VOID
2943 CreateLogicalPartition(
2944 PPARTLIST List,
2945 ULONGLONG SectorCount,
2946 BOOLEAN AutoCreate)
2947 {
2948 PDISKENTRY DiskEntry;
2949 PPARTENTRY PartEntry;
2950 PPARTENTRY NewPartEntry;
2951
2952 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2953
2954 if (List == NULL ||
2955 List->CurrentDisk == NULL ||
2956 List->CurrentPartition == NULL ||
2957 List->CurrentPartition->IsPartitioned == TRUE)
2958 {
2959 return;
2960 }
2961
2962 DiskEntry = List->CurrentDisk;
2963 PartEntry = List->CurrentPartition;
2964
2965 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2966
2967 if (AutoCreate == TRUE ||
2968 AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2969 {
2970 DPRINT1("Convert existing partition entry\n");
2971
2972 /* Convert current entry to 'new (unformatted)' */
2973 PartEntry->IsPartitioned = TRUE;
2974 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2975 PartEntry->FormatState = Unformatted;
2976 PartEntry->AutoCreate = FALSE;
2977 PartEntry->New = TRUE;
2978 PartEntry->BootIndicator = FALSE;
2979 PartEntry->LogicalPartition = TRUE;
2980
2981 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2982 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2983 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2984 }
2985 else
2986 {
2987 DPRINT1("Add new partition entry\n");
2988
2989 /* Insert and initialize a new partition entry */
2990 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2991 HEAP_ZERO_MEMORY,
2992 sizeof(PARTENTRY));
2993 if (NewPartEntry == NULL)
2994 return;
2995
2996 /* Insert the new entry into the list */
2997 InsertTailList(&PartEntry->ListEntry,
2998 &NewPartEntry->ListEntry);
2999
3000 NewPartEntry->DiskEntry = DiskEntry;
3001
3002 NewPartEntry->IsPartitioned = TRUE;
3003 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3004 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
3005 NewPartEntry->StartSector.QuadPart;
3006 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3007
3008 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
3009 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
3010 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
3011
3012 NewPartEntry->New = TRUE;
3013 NewPartEntry->FormatState = Unformatted;
3014 NewPartEntry->BootIndicator = FALSE;
3015 NewPartEntry->LogicalPartition = TRUE;
3016
3017 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
3018 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
3019 }
3020
3021 UpdateDiskLayout(DiskEntry);
3022
3023 DiskEntry->Dirty = TRUE;
3024
3025 AssignDriveLetters(List);
3026 }
3027
3028
3029 VOID
3030 DeleteCurrentPartition(
3031 PPARTLIST List)
3032 {
3033 PDISKENTRY DiskEntry;
3034 PPARTENTRY PartEntry;
3035 PPARTENTRY PrevPartEntry;
3036 PPARTENTRY NextPartEntry;
3037 PPARTENTRY LogicalPartEntry;
3038 PLIST_ENTRY Entry;
3039
3040 if (List == NULL ||
3041 List->CurrentDisk == NULL ||
3042 List->CurrentPartition == NULL ||
3043 List->CurrentPartition->IsPartitioned == FALSE)
3044 {
3045 return;
3046 }
3047
3048 /* Clear the system disk and partition pointers if the system partition will be deleted */
3049 if (List->SystemPartition == List->CurrentPartition)
3050 {
3051 List->SystemDisk = NULL;
3052 List->SystemPartition = NULL;
3053 }
3054
3055 DiskEntry = List->CurrentDisk;
3056 PartEntry = List->CurrentPartition;
3057
3058 /* Delete all logical partition entries if an extended partition will be deleted */
3059 if (DiskEntry->ExtendedPartition == PartEntry)
3060 {
3061 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
3062 {
3063 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
3064 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3065
3066 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
3067 }
3068
3069 DiskEntry->ExtendedPartition = NULL;
3070 }
3071
3072 /* Adjust unpartitioned disk space entries */
3073
3074 /* Get pointer to previous and next unpartitioned entries */
3075 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
3076 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
3077
3078 if (PrevPartEntry != NULL && NextPartEntry != NULL)
3079 {
3080 /* Merge previous, current and next unpartitioned entry */
3081
3082 /* Adjust the previous entries length */
3083 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
3084
3085 /* Remove the current entry */
3086 RemoveEntryList(&PartEntry->ListEntry);
3087 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3088
3089 /* Remove the next entry */
3090 RemoveEntryList (&NextPartEntry->ListEntry);
3091 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
3092
3093 /* Update current partition */
3094 List->CurrentPartition = PrevPartEntry;
3095 }
3096 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
3097 {
3098 /* Merge current and previous unpartitioned entry */
3099
3100 /* Adjust the previous entries length */
3101 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3102
3103 /* Remove the current entry */
3104 RemoveEntryList(&PartEntry->ListEntry);
3105 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3106
3107 /* Update current partition */
3108 List->CurrentPartition = PrevPartEntry;
3109 }
3110 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
3111 {
3112 /* Merge current and next unpartitioned entry */
3113
3114 /* Adjust the next entries offset and length */
3115 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3116 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3117
3118 /* Remove the current entry */
3119 RemoveEntryList(&PartEntry->ListEntry);
3120 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3121
3122 /* Update current partition */
3123 List->CurrentPartition = NextPartEntry;
3124 }
3125 else
3126 {
3127 /* Nothing to merge but change current entry */
3128 PartEntry->IsPartitioned = FALSE;
3129 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3130 PartEntry->FormatState = Unformatted;
3131 PartEntry->DriveLetter = 0;
3132 }
3133
3134 UpdateDiskLayout(DiskEntry);
3135
3136 DiskEntry->Dirty = TRUE;
3137
3138 AssignDriveLetters(List);
3139 }
3140
3141
3142 VOID
3143 CheckActiveSystemPartition(
3144 IN PPARTLIST List,
3145 IN PFILE_SYSTEM_LIST FileSystemList /* Needed for checking the FS of the candidate system partition */
3146 )
3147 {
3148 PDISKENTRY DiskEntry;
3149 PPARTENTRY PartEntry;
3150 PLIST_ENTRY ListEntry;
3151
3152 PFILE_SYSTEM_ITEM FileSystem;
3153
3154 /* Check for empty disk list */
3155 if (IsListEmpty(&List->DiskListHead))
3156 {
3157 List->SystemDisk = NULL;
3158 List->SystemPartition = NULL;
3159 List->OriginalSystemDisk = NULL;
3160 List->OriginalSystemPartition = NULL;
3161 return;
3162 }
3163
3164 /* Choose the currently selected disk */
3165 DiskEntry = List->CurrentDisk;
3166
3167 /* Check for empty partition list */
3168 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
3169 {
3170 List->SystemDisk = NULL;
3171 List->SystemPartition = NULL;
3172 List->OriginalSystemDisk = NULL;
3173 List->OriginalSystemPartition = NULL;
3174 return;
3175 }
3176
3177 if (List->SystemDisk != NULL && List->SystemPartition != NULL)
3178 {
3179 /* We already have an active system partition */
3180 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n",
3181 List->SystemPartition->PartitionNumber,
3182 List->SystemDisk->DiskNumber,
3183 (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
3184 return;
3185 }
3186
3187 DPRINT1("We are here (1)!\n");
3188
3189 List->SystemDisk = NULL;
3190 List->SystemPartition = NULL;
3191 List->OriginalSystemDisk = NULL;
3192 List->OriginalSystemPartition = NULL;
3193
3194 /* Retrieve the first partition of the disk */
3195 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3196 PARTENTRY,
3197 ListEntry);
3198 List->SystemDisk = DiskEntry;
3199 List->SystemPartition = PartEntry;
3200
3201 //
3202 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3203 //
3204
3205 /* Check if the disk is new and if so, use its first partition as the active system partition */
3206 if (DiskEntry->NewDisk)
3207 {
3208 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
3209 {
3210 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
3211 List->SystemDisk = DiskEntry;
3212 List->SystemPartition = PartEntry;
3213
3214 List->OriginalSystemDisk = List->SystemDisk;
3215 List->OriginalSystemPartition = List->SystemPartition;
3216
3217 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %c\n",
3218 List->SystemPartition->PartitionNumber,
3219 List->SystemDisk->DiskNumber,
3220 (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
3221
3222 goto SetSystemPartition;
3223 }
3224
3225 // FIXME: What to do??
3226 DPRINT1("NewDisk TRUE but first partition is used?\n");
3227 }
3228
3229 DPRINT1("We are here (2)!\n");
3230
3231 /*
3232 * The disk is not new, check if any partition is initialized;
3233 * if not, the first one becomes the system partition.
3234 */
3235 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3236 while (ListEntry != &DiskEntry->PrimaryPartListHead)
3237 {
3238 /* Retrieve the partition and go to the next one */
3239 PartEntry = CONTAINING_RECORD(ListEntry,
3240 PARTENTRY,
3241 ListEntry);
3242
3243 /* Check if the partition is partitioned and is used */
3244 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
3245 {
3246 break;
3247 }
3248
3249 /* Go to the next one */
3250 ListEntry = ListEntry->Flink;
3251 }
3252 if (ListEntry == &DiskEntry->PrimaryPartListHead)
3253 {
3254 /*
3255 * OK we haven't encountered any used and active partition,
3256 * so use the first one as the system partition.
3257 */
3258
3259 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
3260 List->OriginalSystemDisk = List->SystemDisk; // DiskEntry
3261 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
3262
3263 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %c\n",
3264 List->SystemPartition->PartitionNumber,
3265 List->SystemDisk->DiskNumber,
3266 (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
3267
3268 goto SetSystemPartition;
3269 }
3270
3271 List->SystemDisk = NULL;
3272 List->SystemPartition = NULL;
3273 List->OriginalSystemDisk = NULL;
3274 List->OriginalSystemPartition = NULL;
3275
3276 DPRINT1("We are here (3)!\n");
3277
3278 /* The disk is not new, scan all partitions to find the (active) system partition */
3279 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3280 while (ListEntry != &DiskEntry->PrimaryPartListHead)
3281 {
3282 /* Retrieve the partition and go to the next one */
3283 PartEntry = CONTAINING_RECORD(ListEntry,
3284 PARTENTRY,
3285 ListEntry);
3286 ListEntry = ListEntry->Flink;
3287
3288 /* Check if the partition is partitioned and used */
3289 if (PartEntry->IsPartitioned &&
3290 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
3291 {
3292 /* Check if the partition is active */
3293 if (PartEntry->BootIndicator)
3294 {
3295 /* Yes, we found it */
3296 List->SystemDisk = DiskEntry;
3297 List->SystemPartition = PartEntry;
3298
3299 DPRINT1("Found active system partition %lu in disk %lu, drive letter %c\n",
3300 PartEntry->PartitionNumber,
3301 DiskEntry->DiskNumber,
3302 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter);
3303 break;
3304 }
3305 }
3306 }
3307
3308 /* Check if we have found the system partition */
3309 if (List->SystemDisk == NULL || List->SystemPartition == NULL)
3310 {
3311 /* Nothing, use the alternative system partition */
3312 DPRINT1("No system partition found, use the alternative partition!\n");
3313 goto UseAlternativeSystemPartition;
3314 }
3315
3316 /* Save them */
3317 List->OriginalSystemDisk = List->SystemDisk;
3318 List->OriginalSystemPartition = List->SystemPartition;
3319
3320 /*
3321 * ADDITIONAL CHECKS / BIG HACK:
3322 *
3323 * Retrieve its file system and check whether we have
3324 * write support for it. If that is the case we are fine
3325 * and we can use it directly. However if we don't have
3326 * write support we will need to change the active system
3327 * partition.
3328 *
3329 * NOTE that this is completely useless on architectures
3330 * where a real system partition is required, as on these
3331 * architectures the partition uses the FAT FS, for which
3332 * we do have write support.
3333 * NOTE also that for those architectures looking for a
3334 * partition boot indicator is insufficient.
3335 */
3336 FileSystem = GetFileSystem(FileSystemList, List->OriginalSystemPartition);
3337 if (FileSystem == NULL)
3338 {
3339 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
3340 List->OriginalSystemPartition->PartitionNumber,
3341 List->OriginalSystemDisk->DiskNumber);
3342 goto FindAndUseAlternativeSystemPartition;
3343 }
3344 // HACK: WARNING: We cannot write on this FS yet!
3345 // See fslist.c:GetFileSystem()
3346 if (List->OriginalSystemPartition->PartitionType == PARTITION_EXT2 ||
3347 List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
3348 {
3349 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
3350 FileSystem->FileSystemName);
3351 goto FindAndUseAlternativeSystemPartition;
3352 }
3353
3354 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %c\n",
3355 List->SystemPartition->PartitionNumber,
3356 List->SystemDisk->DiskNumber,
3357 (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
3358
3359 return;
3360
3361 FindAndUseAlternativeSystemPartition:
3362 /*
3363 * We are here because we have not found any (active) candidate
3364 * system partition that we know how to support. What we are going
3365 * to do is to change the existing system partition and use the
3366 * partition on which we install ReactOS as the new system partition,
3367 * and then we will need to add in FreeLdr's entry a boot entry to boot
3368 * from the original system partition.
3369 */
3370
3371 /* Unset the old system partition */
3372 List->SystemPartition->BootIndicator = FALSE;
3373 List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
3374 List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3375 List->SystemDisk->Dirty = TRUE;
3376
3377 UseAlternativeSystemPartition:
3378 List->SystemDisk = List->CurrentDisk;
3379 List->SystemPartition = List->CurrentPartition;
3380
3381 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %c\n",
3382 List->SystemPartition->PartitionNumber,
3383 List->SystemDisk->DiskNumber,
3384 (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
3385
3386 SetSystemPartition:
3387 /* Set the new active system partition */
3388 List->SystemPartition->BootIndicator = TRUE;
3389 List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3390 List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3391 List->SystemDisk->Dirty = TRUE;
3392 }
3393
3394
3395 static
3396 NTSTATUS
3397 WritePartitions(
3398 IN PPARTLIST List,
3399 IN PDISKENTRY DiskEntry)
3400 {
3401 WCHAR DstPath[MAX_PATH];
3402 OBJECT_ATTRIBUTES ObjectAttributes;
3403 IO_STATUS_BLOCK Iosb;
3404 UNICODE_STRING Name;
3405 ULONG BufferSize;
3406 HANDLE FileHandle = NULL;
3407 NTSTATUS Status;
3408
3409 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3410
3411 swprintf(DstPath,
3412 L"\\Device\\Harddisk%d\\Partition0",
3413 DiskEntry->DiskNumber);
3414 RtlInitUnicodeString(&Name,
3415 DstPath);
3416 InitializeObjectAttributes(&ObjectAttributes,
3417 &Name,
3418 0,
3419 NULL,
3420 NULL);
3421
3422 Status = NtOpenFile(&FileHandle,
3423 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3424 &ObjectAttributes,
3425 &Iosb,
3426 0,
3427 FILE_SYNCHRONOUS_IO_NONALERT);
3428 if (!NT_SUCCESS(Status))
3429 {
3430 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3431 return Status;
3432 }
3433
3434 #ifdef DUMP_PARTITION_TABLE
3435 DumpPartitionTable(DiskEntry);
3436 #endif
3437
3438 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3439 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3440 Status = NtDeviceIoControlFile(FileHandle,
3441 NULL,
3442 NULL,
3443 NULL,
3444 &Iosb,
3445 IOCTL_DISK_SET_DRIVE_LAYOUT,
3446 DiskEntry->LayoutBuffer,
3447 BufferSize,
3448 NULL,
3449 0);
3450 if (!NT_SUCCESS(Status))
3451 {
3452 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3453 }
3454
3455 if (FileHandle != NULL)
3456 NtClose(FileHandle);
3457
3458 return Status;
3459 }
3460
3461
3462 BOOLEAN
3463 WritePartitionsToDisk(
3464 PPARTLIST List)
3465 {
3466 PLIST_ENTRY Entry;
3467 PDISKENTRY DiskEntry;
3468
3469 if (List == NULL)
3470 return TRUE;
3471
3472 Entry = List->DiskListHead.Flink;
3473 while (Entry != &List->DiskListHead)
3474 {
3475 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3476
3477 if (DiskEntry->Dirty == TRUE)
3478 {
3479 WritePartitions(List, DiskEntry);
3480 DiskEntry->Dirty = FALSE;
3481 }
3482
3483 Entry = Entry->Flink;
3484 }
3485
3486 return TRUE;
3487 }
3488
3489
3490 BOOL
3491 SetMountedDeviceValues(
3492 PPARTLIST List)
3493 {
3494 PLIST_ENTRY Entry1, Entry2;
3495 PDISKENTRY DiskEntry;
3496 PPARTENTRY PartEntry;
3497 LARGE_INTEGER StartingOffset;
3498
3499 if (List == NULL)
3500 {
3501 return FALSE;
3502 }
3503
3504 Entry1 = List->DiskListHead.Flink;
3505 while (Entry1 != &List->DiskListHead)
3506 {
3507 DiskEntry = CONTAINING_RECORD(Entry1,
3508 DISKENTRY,
3509 ListEntry);
3510
3511 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3512 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3513 {
3514 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3515 if (PartEntry->IsPartitioned)
3516 {
3517 if (PartEntry->DriveLetter)
3518 {
3519 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3520 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3521 DiskEntry->LayoutBuffer->Signature,
3522 StartingOffset))
3523 {
3524 return FALSE;
3525 }
3526 }
3527 }
3528
3529 Entry2 = Entry2->Flink;
3530 }
3531
3532 Entry1 = Entry1->Flink;
3533 }
3534
3535 return TRUE;
3536 }
3537
3538
3539 ULONG
3540 PrimaryPartitionCreationChecks(
3541 IN PPARTLIST List)
3542 {
3543 PDISKENTRY DiskEntry;
3544 PPARTENTRY PartEntry;
3545
3546 DiskEntry = List->CurrentDisk;
3547 PartEntry = List->CurrentPartition;
3548
3549 /* Fail if partition is already in use */
3550 if (PartEntry->IsPartitioned == TRUE)
3551 return ERROR_NEW_PARTITION;
3552
3553 /* Fail if there are already 4 primary partitions in the list */
3554 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3555 return ERROR_PARTITION_TABLE_FULL;
3556
3557 return ERROR_SUCCESS;
3558 }
3559
3560
3561 ULONG
3562 ExtendedPartitionCreationChecks(
3563 IN PPARTLIST List)
3564 {
3565 PDISKENTRY DiskEntry;
3566 PPARTENTRY PartEntry;
3567
3568 DiskEntry = List->CurrentDisk;
3569 PartEntry = List->CurrentPartition;
3570
3571 /* Fail if partition is already in use */
3572 if (PartEntry->IsPartitioned == TRUE)
3573 return ERROR_NEW_PARTITION;
3574
3575 /* Fail if there are already 4 primary partitions in the list */
3576 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3577 return ERROR_PARTITION_TABLE_FULL;
3578
3579 /* Fail if there is another extended partition in the list */
3580 if (DiskEntry->ExtendedPartition != NULL)
3581 return ERROR_ONLY_ONE_EXTENDED;
3582
3583 return ERROR_SUCCESS;
3584 }
3585
3586
3587 ULONG
3588 LogicalPartitionCreationChecks(
3589 IN PPARTLIST List)
3590 {
3591 // PDISKENTRY DiskEntry;
3592 PPARTENTRY PartEntry;
3593
3594 // DiskEntry = List->CurrentDisk;
3595 PartEntry = List->CurrentPartition;
3596
3597 /* Fail if partition is already in use */
3598 if (PartEntry->IsPartitioned == TRUE)
3599 return ERROR_NEW_PARTITION;
3600
3601 return ERROR_SUCCESS;
3602 }
3603
3604
3605 BOOL
3606 GetNextUnformattedPartition(
3607 IN PPARTLIST List,
3608 OUT PDISKENTRY *pDiskEntry,
3609 OUT PPARTENTRY *pPartEntry)
3610 {
3611 PLIST_ENTRY Entry1, Entry2;
3612 PDISKENTRY DiskEntry;
3613 PPARTENTRY PartEntry;
3614
3615 Entry1 = List->DiskListHead.Flink;
3616 while (Entry1 != &List->DiskListHead)
3617 {
3618 DiskEntry = CONTAINING_RECORD(Entry1,
3619 DISKENTRY,
3620 ListEntry);
3621
3622 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3623 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3624 {
3625 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3626 if (PartEntry->IsPartitioned && PartEntry->New)
3627 {
3628 *pDiskEntry = DiskEntry;
3629 *pPartEntry = PartEntry;
3630 return TRUE;
3631 }
3632
3633 Entry2 = Entry2->Flink;
3634 }
3635
3636 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3637 while (Entry2 != &DiskEntry->LogicalPartListHead)
3638 {
3639 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3640 if (PartEntry->IsPartitioned && PartEntry->New)
3641 {
3642 *pDiskEntry = DiskEntry;
3643 *pPartEntry = PartEntry;
3644 return TRUE;
3645 }
3646
3647 Entry2 = Entry2->Flink;
3648 }
3649
3650 Entry1 = Entry1->Flink;
3651 }
3652
3653 *pDiskEntry = NULL;
3654 *pPartEntry = NULL;
3655
3656 return FALSE;
3657 }
3658
3659
3660 BOOL
3661 GetNextUncheckedPartition(
3662 IN PPARTLIST List,
3663 OUT PDISKENTRY *pDiskEntry,
3664 OUT PPARTENTRY *pPartEntry)
3665 {
3666 PLIST_ENTRY Entry1, Entry2;
3667 PDISKENTRY DiskEntry;
3668 PPARTENTRY PartEntry;
3669
3670 Entry1 = List->DiskListHead.Flink;
3671 while (Entry1 != &List->DiskListHead)
3672 {
3673 DiskEntry = CONTAINING_RECORD(Entry1,
3674 DISKENTRY,
3675 ListEntry);
3676
3677 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3678 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3679 {
3680 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3681 if (PartEntry->NeedsCheck == TRUE)
3682 {
3683 *pDiskEntry = DiskEntry;
3684 *pPartEntry = PartEntry;
3685 return TRUE;
3686 }
3687
3688 Entry2 = Entry2->Flink;
3689 }
3690
3691 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3692 while (Entry2 != &DiskEntry->LogicalPartListHead)
3693 {
3694 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3695 if (PartEntry->NeedsCheck == TRUE)
3696 {
3697 *pDiskEntry = DiskEntry;
3698 *pPartEntry = PartEntry;
3699 return TRUE;
3700 }
3701
3702 Entry2 = Entry2->Flink;
3703 }
3704
3705 Entry1 = Entry1->Flink;
3706 }
3707
3708 *pDiskEntry = NULL;
3709 *pPartEntry = NULL;
3710
3711 return FALSE;
3712 }
3713
3714 /* EOF */