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