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