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