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