[USETUP]
[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 partiton 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! Partiton 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1366 }
1367 }
1368 else
1369 {
1370 DPRINT1("No valid partiton 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->TopDisk = (ULONG)-1;
1438 List->TopPartition = (ULONG)-1;
1439
1440 List->CurrentDisk = NULL;
1441 List->CurrentPartition = NULL;
1442
1443 List->BootDisk = NULL;
1444 List->BootPartition = NULL;
1445
1446 List->TempDisk = NULL;
1447 List->TempPartition = NULL;
1448 List->FormatState = Start;
1449
1450 InitializeListHead(&List->DiskListHead);
1451 InitializeListHead(&List->BiosDiskListHead);
1452
1453 EnumerateBiosDiskEntries(List);
1454
1455 Status = NtQuerySystemInformation(SystemDeviceInformation,
1456 &Sdi,
1457 sizeof(SYSTEM_DEVICE_INFORMATION),
1458 &ReturnSize);
1459 if (!NT_SUCCESS(Status))
1460 {
1461 RtlFreeHeap(ProcessHeap, 0, List);
1462 return NULL;
1463 }
1464
1465 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1466 {
1467 swprintf(Buffer,
1468 L"\\Device\\Harddisk%d\\Partition0",
1469 DiskNumber);
1470 RtlInitUnicodeString(&Name,
1471 Buffer);
1472
1473 InitializeObjectAttributes(&ObjectAttributes,
1474 &Name,
1475 0,
1476 NULL,
1477 NULL);
1478
1479 Status = NtOpenFile(&FileHandle,
1480 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1481 &ObjectAttributes,
1482 &Iosb,
1483 FILE_SHARE_READ,
1484 FILE_SYNCHRONOUS_IO_NONALERT);
1485 if (NT_SUCCESS(Status))
1486 {
1487 AddDiskToList(FileHandle,
1488 DiskNumber,
1489 List);
1490
1491 NtClose(FileHandle);
1492 }
1493 }
1494
1495 UpdateDiskSignatures(List);
1496
1497 AssignDriveLetters(List);
1498
1499 List->TopDisk = 0;
1500 List->TopPartition = 0;
1501
1502 /* Search for first usable disk and partition */
1503 if (IsListEmpty(&List->DiskListHead))
1504 {
1505 List->CurrentDisk = NULL;
1506 List->CurrentPartition = NULL;
1507 }
1508 else
1509 {
1510 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1511 DISKENTRY,
1512 ListEntry);
1513
1514 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1515 {
1516 List->CurrentPartition = 0;
1517 }
1518 else
1519 {
1520 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1521 PARTENTRY,
1522 ListEntry);
1523 }
1524 }
1525
1526 return List;
1527 }
1528
1529
1530 VOID
1531 DestroyPartitionList(
1532 PPARTLIST List)
1533 {
1534 PDISKENTRY DiskEntry;
1535 PBIOSDISKENTRY BiosDiskEntry;
1536 PPARTENTRY PartEntry;
1537 PLIST_ENTRY Entry;
1538
1539 /* Release disk and partition info */
1540 while (!IsListEmpty(&List->DiskListHead))
1541 {
1542 Entry = RemoveHeadList(&List->DiskListHead);
1543 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1544
1545 /* Release driver name */
1546 RtlFreeUnicodeString(&DiskEntry->DriverName);
1547
1548 /* Release primary partition list */
1549 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1550 {
1551 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1552 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1553
1554 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1555 }
1556
1557 /* Release logical partition list */
1558 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1559 {
1560 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1561 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1562
1563 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1564 }
1565
1566 /* Release layout buffer */
1567 if (DiskEntry->LayoutBuffer != NULL)
1568 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1569
1570
1571 /* Release disk entry */
1572 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1573 }
1574
1575 /* release the bios disk info */
1576 while(!IsListEmpty(&List->BiosDiskListHead))
1577 {
1578 Entry = RemoveHeadList(&List->BiosDiskListHead);
1579 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1580
1581 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1582 }
1583
1584 /* Release list head */
1585 RtlFreeHeap(ProcessHeap, 0, List);
1586 }
1587
1588
1589 static
1590 VOID
1591 PrintEmptyLine(
1592 PPARTLIST List)
1593 {
1594 COORD coPos;
1595 DWORD Written;
1596 USHORT Width;
1597 USHORT Height;
1598
1599 Width = List->Right - List->Left - 1;
1600 Height = List->Bottom - List->Top - 2;
1601
1602 coPos.X = List->Left + 1;
1603 coPos.Y = List->Top + 1 + List->Line;
1604
1605 if (List->Line >= 0 && List->Line <= Height)
1606 {
1607 FillConsoleOutputAttribute(StdOutput,
1608 FOREGROUND_WHITE | BACKGROUND_BLUE,
1609 Width,
1610 coPos,
1611 &Written);
1612
1613 FillConsoleOutputCharacterA(StdOutput,
1614 ' ',
1615 Width,
1616 coPos,
1617 &Written);
1618 }
1619
1620 List->Line++;
1621 }
1622
1623
1624 static
1625 VOID
1626 PrintPartitionData(
1627 PPARTLIST List,
1628 PDISKENTRY DiskEntry,
1629 PPARTENTRY PartEntry)
1630 {
1631 CHAR LineBuffer[128];
1632 COORD coPos;
1633 DWORD Written;
1634 USHORT Width;
1635 USHORT Height;
1636 LARGE_INTEGER PartSize;
1637 PCHAR Unit;
1638 UCHAR Attribute;
1639 CHAR PartTypeString[32];
1640 PCHAR PartType;
1641 PartType = PartTypeString;
1642
1643 Width = List->Right - List->Left - 1;
1644 Height = List->Bottom - List->Top - 2;
1645
1646 coPos.X = List->Left + 1;
1647 coPos.Y = List->Top + 1 + List->Line;
1648
1649 if (PartEntry->IsPartitioned == FALSE)
1650 {
1651 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1652 #if 0
1653 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1654 {
1655 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1656 Unit = MUIGetString(STRING_GB);
1657 }
1658 else
1659 #endif
1660 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1661 {
1662 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1663 Unit = MUIGetString(STRING_MB);
1664 }
1665 else
1666 {
1667 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1668 Unit = MUIGetString(STRING_KB);
1669 }
1670
1671 sprintf(LineBuffer,
1672 MUIGetString(STRING_UNPSPACE),
1673 PartEntry->LogicalPartition ? " " : "",
1674 PartEntry->LogicalPartition ? "" : " ",
1675 PartSize.u.LowPart,
1676 Unit);
1677 }
1678 else
1679 {
1680 /* Determine partition type */
1681 PartTypeString[0] = '\0';
1682 if (PartEntry->New == TRUE)
1683 {
1684 PartType = MUIGetString(STRING_UNFORMATTED);
1685 }
1686 else if (PartEntry->IsPartitioned == TRUE)
1687 {
1688 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
1689 PartTypeString,
1690 30);
1691 PartType = PartTypeString;
1692 }
1693
1694 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1695 #if 0
1696 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
1697 {
1698 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
1699 Unit = MUIGetString(STRING_GB);
1700 }
1701 else
1702 #endif
1703 if (PartSize.QuadPart >= 10485760) /* 10 MB */
1704 {
1705 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
1706 Unit = MUIGetString(STRING_MB);
1707 }
1708 else
1709 {
1710 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
1711 Unit = MUIGetString(STRING_KB);
1712 }
1713
1714 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
1715 {
1716 sprintf(LineBuffer,
1717 MUIGetString(STRING_HDDINFOUNK5),
1718 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1719 (PartEntry->DriveLetter == 0) ? '-' : ':',
1720 PartEntry->BootIndicator ? '*' : ' ',
1721 PartEntry->LogicalPartition ? " " : "",
1722 PartEntry->PartitionType,
1723 PartEntry->LogicalPartition ? "" : " ",
1724 PartSize.u.LowPart,
1725 Unit);
1726 }
1727 else
1728 {
1729 sprintf(LineBuffer,
1730 "%c%c %c %s%-24s%s %6lu %s",
1731 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1732 (PartEntry->DriveLetter == 0) ? '-' : ':',
1733 PartEntry->BootIndicator ? '*' : ' ',
1734 PartEntry->LogicalPartition ? " " : "",
1735 PartType,
1736 PartEntry->LogicalPartition ? "" : " ",
1737 PartSize.u.LowPart,
1738 Unit);
1739 }
1740 }
1741
1742 Attribute = (List->CurrentDisk == DiskEntry &&
1743 List->CurrentPartition == PartEntry) ?
1744 FOREGROUND_BLUE | BACKGROUND_WHITE :
1745 FOREGROUND_WHITE | BACKGROUND_BLUE;
1746
1747 if (List->Line >= 0 && List->Line <= Height)
1748 {
1749 FillConsoleOutputCharacterA(StdOutput,
1750 ' ',
1751 Width,
1752 coPos,
1753 &Written);
1754 }
1755 coPos.X += 4;
1756 Width -= 8;
1757 if (List->Line >= 0 && List->Line <= Height)
1758 {
1759 FillConsoleOutputAttribute(StdOutput,
1760 Attribute,
1761 Width,
1762 coPos,
1763 &Written);
1764 }
1765 coPos.X++;
1766 Width -= 2;
1767 if (List->Line >= 0 && List->Line <= Height)
1768 {
1769 WriteConsoleOutputCharacterA(StdOutput,
1770 LineBuffer,
1771 min(strlen(LineBuffer), Width),
1772 coPos,
1773 &Written);
1774 }
1775
1776 List->Line++;
1777 }
1778
1779
1780 static
1781 VOID
1782 PrintDiskData(
1783 PPARTLIST List,
1784 PDISKENTRY DiskEntry)
1785 {
1786 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
1787 PLIST_ENTRY PrimaryEntry, LogicalEntry;
1788 CHAR LineBuffer[128];
1789 COORD coPos;
1790 DWORD Written;
1791 USHORT Width;
1792 USHORT Height;
1793 ULARGE_INTEGER DiskSize;
1794 PCHAR Unit;
1795
1796 Width = List->Right - List->Left - 1;
1797 Height = List->Bottom - List->Top - 2;
1798
1799 coPos.X = List->Left + 1;
1800 coPos.Y = List->Top + 1 + List->Line;
1801
1802 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1803 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
1804 {
1805 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
1806 Unit = MUIGetString(STRING_GB);
1807 }
1808 else
1809 {
1810 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
1811 if (DiskSize.QuadPart == 0)
1812 DiskSize.QuadPart = 1;
1813 Unit = MUIGetString(STRING_MB);
1814 }
1815
1816 if (DiskEntry->DriverName.Length > 0)
1817 {
1818 sprintf(LineBuffer,
1819 MUIGetString(STRING_HDINFOPARTSELECT),
1820 DiskSize.u.LowPart,
1821 Unit,
1822 DiskEntry->DiskNumber,
1823 DiskEntry->Port,
1824 DiskEntry->Bus,
1825 DiskEntry->Id,
1826 DiskEntry->DriverName.Buffer);
1827 }
1828 else
1829 {
1830 sprintf(LineBuffer,
1831 MUIGetString(STRING_HDDINFOUNK6),
1832 DiskSize.u.LowPart,
1833 Unit,
1834 DiskEntry->DiskNumber,
1835 DiskEntry->Port,
1836 DiskEntry->Bus,
1837 DiskEntry->Id);
1838 }
1839
1840 if (List->Line >= 0 && List->Line <= Height)
1841 {
1842 FillConsoleOutputAttribute(StdOutput,
1843 FOREGROUND_WHITE | BACKGROUND_BLUE,
1844 Width,
1845 coPos,
1846 &Written);
1847
1848 FillConsoleOutputCharacterA(StdOutput,
1849 ' ',
1850 Width,
1851 coPos,
1852 &Written);
1853 }
1854
1855 coPos.X++;
1856 if (List->Line >= 0 && List->Line <= Height)
1857 {
1858 WriteConsoleOutputCharacterA(StdOutput,
1859 LineBuffer,
1860 min((USHORT)strlen(LineBuffer), Width - 2),
1861 coPos,
1862 &Written);
1863 }
1864
1865 List->Line++;
1866
1867 /* Print separator line */
1868 PrintEmptyLine(List);
1869
1870 /* Print partition lines*/
1871 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
1872 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
1873 {
1874 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
1875
1876 PrintPartitionData(List,
1877 DiskEntry,
1878 PrimaryPartEntry);
1879
1880 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
1881 {
1882 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
1883 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
1884 {
1885 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
1886
1887 PrintPartitionData(List,
1888 DiskEntry,
1889 LogicalPartEntry);
1890
1891 LogicalEntry = LogicalEntry->Flink;
1892 }
1893 }
1894
1895 PrimaryEntry = PrimaryEntry->Flink;
1896 }
1897
1898 /* Print separator line */
1899 PrintEmptyLine(List);
1900 }
1901
1902
1903 VOID
1904 DrawPartitionList(
1905 PPARTLIST List)
1906 {
1907 PLIST_ENTRY Entry, Entry2;
1908 PDISKENTRY DiskEntry;
1909 PPARTENTRY PartEntry = NULL;
1910 COORD coPos;
1911 DWORD Written;
1912 SHORT i;
1913 SHORT CurrentDiskLine;
1914 SHORT CurrentPartLine;
1915 SHORT LastLine;
1916 BOOL CurrentPartLineFound = FALSE;
1917 BOOL CurrentDiskLineFound = FALSE;
1918
1919 /* Calculate the line of the current disk and partition */
1920 CurrentDiskLine = 0;
1921 CurrentPartLine = 0;
1922 LastLine = 0;
1923
1924 Entry = List->DiskListHead.Flink;
1925 while (Entry != &List->DiskListHead)
1926 {
1927 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1928
1929 LastLine += 2;
1930 if (CurrentPartLineFound == FALSE)
1931 {
1932 CurrentPartLine += 2;
1933 }
1934
1935 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1936 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1937 {
1938 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1939 if (PartEntry == List->CurrentPartition)
1940 {
1941 CurrentPartLineFound = TRUE;
1942 }
1943
1944 Entry2 = Entry2->Flink;
1945 if (CurrentPartLineFound == FALSE)
1946 {
1947 CurrentPartLine++;
1948 }
1949
1950 LastLine++;
1951 }
1952
1953 if (DiskEntry == List->CurrentDisk)
1954 {
1955 CurrentDiskLineFound = TRUE;
1956 }
1957
1958 Entry = Entry->Flink;
1959 if (Entry != &List->DiskListHead)
1960 {
1961 if (CurrentDiskLineFound == FALSE)
1962 {
1963 CurrentPartLine ++;
1964 CurrentDiskLine = CurrentPartLine;
1965 }
1966
1967 LastLine++;
1968 }
1969 else
1970 {
1971 LastLine--;
1972 }
1973 }
1974
1975 /* If it possible, make the disk name visible */
1976 if (CurrentPartLine < List->Offset)
1977 {
1978 List->Offset = CurrentPartLine;
1979 }
1980 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1981 {
1982 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1983 }
1984
1985 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1986 {
1987 List->Offset = CurrentDiskLine;
1988 }
1989
1990 /* draw upper left corner */
1991 coPos.X = List->Left;
1992 coPos.Y = List->Top;
1993 FillConsoleOutputCharacterA(StdOutput,
1994 0xDA, // '+',
1995 1,
1996 coPos,
1997 &Written);
1998
1999 /* draw upper edge */
2000 coPos.X = List->Left + 1;
2001 coPos.Y = List->Top;
2002 if (List->Offset == 0)
2003 {
2004 FillConsoleOutputCharacterA(StdOutput,
2005 0xC4, // '-',
2006 List->Right - List->Left - 1,
2007 coPos,
2008 &Written);
2009 }
2010 else
2011 {
2012 FillConsoleOutputCharacterA(StdOutput,
2013 0xC4, // '-',
2014 List->Right - List->Left - 5,
2015 coPos,
2016 &Written);
2017 coPos.X = List->Right - 5;
2018 WriteConsoleOutputCharacterA(StdOutput,
2019 "(\x18)", // "(up)"
2020 3,
2021 coPos,
2022 &Written);
2023 coPos.X = List->Right - 2;
2024 FillConsoleOutputCharacterA(StdOutput,
2025 0xC4, // '-',
2026 2,
2027 coPos,
2028 &Written);
2029 }
2030
2031 /* draw upper right corner */
2032 coPos.X = List->Right;
2033 coPos.Y = List->Top;
2034 FillConsoleOutputCharacterA(StdOutput,
2035 0xBF, // '+',
2036 1,
2037 coPos,
2038 &Written);
2039
2040 /* draw left and right edge */
2041 for (i = List->Top + 1; i < List->Bottom; i++)
2042 {
2043 coPos.X = List->Left;
2044 coPos.Y = i;
2045 FillConsoleOutputCharacterA(StdOutput,
2046 0xB3, // '|',
2047 1,
2048 coPos,
2049 &Written);
2050
2051 coPos.X = List->Right;
2052 FillConsoleOutputCharacterA(StdOutput,
2053 0xB3, //'|',
2054 1,
2055 coPos,
2056 &Written);
2057 }
2058
2059 /* draw lower left corner */
2060 coPos.X = List->Left;
2061 coPos.Y = List->Bottom;
2062 FillConsoleOutputCharacterA(StdOutput,
2063 0xC0, // '+',
2064 1,
2065 coPos,
2066 &Written);
2067
2068 /* draw lower edge */
2069 coPos.X = List->Left + 1;
2070 coPos.Y = List->Bottom;
2071 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
2072 {
2073 FillConsoleOutputCharacterA(StdOutput,
2074 0xC4, // '-',
2075 List->Right - List->Left - 1,
2076 coPos,
2077 &Written);
2078 }
2079 else
2080 {
2081 FillConsoleOutputCharacterA(StdOutput,
2082 0xC4, // '-',
2083 List->Right - List->Left - 5,
2084 coPos,
2085 &Written);
2086 coPos.X = List->Right - 5;
2087 WriteConsoleOutputCharacterA(StdOutput,
2088 "(\x19)", // "(down)"
2089 3,
2090 coPos,
2091 &Written);
2092 coPos.X = List->Right - 2;
2093 FillConsoleOutputCharacterA(StdOutput,
2094 0xC4, // '-',
2095 2,
2096 coPos,
2097 &Written);
2098 }
2099
2100 /* draw lower right corner */
2101 coPos.X = List->Right;
2102 coPos.Y = List->Bottom;
2103 FillConsoleOutputCharacterA(StdOutput,
2104 0xD9, // '+',
2105 1,
2106 coPos,
2107 &Written);
2108
2109 /* print list entries */
2110 List->Line = - List->Offset;
2111
2112 Entry = List->DiskListHead.Flink;
2113 while (Entry != &List->DiskListHead)
2114 {
2115 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2116
2117 /* Print disk entry */
2118 PrintDiskData(List,
2119 DiskEntry);
2120
2121 Entry = Entry->Flink;
2122 }
2123 }
2124
2125
2126 DWORD
2127 SelectPartition(
2128 PPARTLIST List,
2129 ULONG DiskNumber,
2130 ULONG PartitionNumber)
2131 {
2132 PDISKENTRY DiskEntry;
2133 PPARTENTRY PartEntry;
2134 PLIST_ENTRY Entry1;
2135 PLIST_ENTRY Entry2;
2136
2137 /* Check for empty disks */
2138 if (IsListEmpty(&List->DiskListHead))
2139 return FALSE;
2140
2141 /* Check for first usable entry on next disk */
2142 Entry1 = List->CurrentDisk->ListEntry.Flink;
2143 while (Entry1 != &List->DiskListHead)
2144 {
2145 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
2146
2147 if (DiskEntry->DiskNumber == DiskNumber)
2148 {
2149 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
2150 while (Entry2 != &DiskEntry->PrimaryPartListHead)
2151 {
2152 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2153
2154 if (PartEntry->PartitionNumber == PartitionNumber)
2155 {
2156 List->CurrentDisk = DiskEntry;
2157 List->CurrentPartition = PartEntry;
2158 DrawPartitionList(List);
2159 return TRUE;
2160 }
2161
2162 Entry2 = Entry2->Flink;
2163 }
2164
2165 return FALSE;
2166 }
2167
2168 Entry1 = Entry1->Flink;
2169 }
2170
2171 return FALSE;
2172 }
2173
2174
2175 BOOL
2176 ScrollDownPartitionList(
2177 PPARTLIST List)
2178 {
2179 PLIST_ENTRY DiskListEntry;
2180 PLIST_ENTRY PartListEntry;
2181 PDISKENTRY DiskEntry;
2182 PPARTENTRY PartEntry;
2183
2184 /* Fail, if no disks are available */
2185 if (IsListEmpty(&List->DiskListHead))
2186 return FALSE;
2187
2188 /* Check for next usable entry on current disk */
2189 if (List->CurrentPartition != NULL)
2190 {
2191 if (List->CurrentPartition->LogicalPartition)
2192 {
2193 /* Logical partition */
2194
2195 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2196 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2197 {
2198 /* Next logical partition */
2199 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2200
2201 List->CurrentPartition = PartEntry;
2202 return TRUE;
2203 }
2204 else
2205 {
2206 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2207 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2208 {
2209 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2210
2211 List->CurrentPartition = PartEntry;
2212 return TRUE;
2213 }
2214 }
2215 }
2216 else
2217 {
2218 /* Primary or extended partition */
2219
2220 if (List->CurrentPartition->IsPartitioned == TRUE &&
2221 IsContainerPartition(List->CurrentPartition->PartitionType))
2222 {
2223 /* First logical partition */
2224 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2225 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2226 {
2227 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2228
2229 List->CurrentPartition = PartEntry;
2230 return TRUE;
2231 }
2232 }
2233 else
2234 {
2235 /* Next primary partition */
2236 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2237 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2238 {
2239 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2240
2241 List->CurrentPartition = PartEntry;
2242 return TRUE;
2243 }
2244 }
2245 }
2246 }
2247
2248 /* Search for the first partition entry on the next disk */
2249 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2250 while (DiskListEntry != &List->DiskListHead)
2251 {
2252 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2253
2254 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2255 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2256 {
2257 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2258
2259 List->CurrentDisk = DiskEntry;
2260 List->CurrentPartition = PartEntry;
2261 return TRUE;
2262 }
2263
2264 DiskListEntry = DiskListEntry->Flink;
2265 }
2266
2267 return FALSE;
2268 }
2269
2270
2271 BOOL
2272 ScrollUpPartitionList(
2273 PPARTLIST List)
2274 {
2275 PLIST_ENTRY DiskListEntry;
2276 PLIST_ENTRY PartListEntry;
2277 PDISKENTRY DiskEntry;
2278 PPARTENTRY PartEntry;
2279
2280 /* Fail, if no disks are available */
2281 if (IsListEmpty(&List->DiskListHead))
2282 return FALSE;
2283
2284 /* Check for previous usable entry on current disk */
2285 if (List->CurrentPartition != NULL)
2286 {
2287 if (List->CurrentPartition->LogicalPartition)
2288 {
2289 /* Logical partition */
2290 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2291 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2292 {
2293 /* Previous logical partition */
2294 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2295 }
2296 else
2297 {
2298 /* Extended partition*/
2299 PartEntry = List->CurrentDisk->ExtendedPartition;
2300 }
2301
2302 List->CurrentPartition = PartEntry;
2303 return TRUE;
2304 }
2305 else
2306 {
2307 /* Primary or extended partition */
2308
2309 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2310 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2311 {
2312 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2313
2314 if (PartEntry->IsPartitioned == TRUE &&
2315 IsContainerPartition(PartEntry->PartitionType))
2316 {
2317 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2318 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2319 }
2320
2321 List->CurrentPartition = PartEntry;
2322 return TRUE;
2323 }
2324
2325 }
2326 }
2327
2328 /* Search for the last partition entry on the previous disk */
2329 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2330 while (DiskListEntry != &List->DiskListHead)
2331 {
2332 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2333
2334 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2335 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2336 {
2337 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2338
2339 if (PartEntry->IsPartitioned == TRUE &&
2340 IsContainerPartition(PartEntry->PartitionType))
2341 {
2342 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2343 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2344 {
2345 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2346
2347 List->CurrentDisk = DiskEntry;
2348 List->CurrentPartition = PartEntry;
2349 return TRUE;
2350 }
2351 }
2352 else
2353 {
2354 List->CurrentDisk = DiskEntry;
2355 List->CurrentPartition = PartEntry;
2356 return TRUE;
2357 }
2358 }
2359
2360 DiskListEntry = DiskListEntry->Blink;
2361 }
2362
2363 return FALSE;
2364 }
2365
2366
2367 static
2368 BOOLEAN
2369 IsEmptyLayoutEntry(
2370 PPARTITION_INFORMATION PartitionInfo)
2371 {
2372 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2373 PartitionInfo->PartitionLength.QuadPart == 0)
2374 return TRUE;
2375
2376 return FALSE;
2377 }
2378
2379
2380 static
2381 BOOLEAN
2382 IsSamePrimaryLayoutEntry(
2383 IN PPARTITION_INFORMATION PartitionInfo,
2384 IN PDISKENTRY DiskEntry,
2385 IN PPARTENTRY PartEntry)
2386 {
2387 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2388 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2389 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2390 // PartitionInfo->PartitionType == PartEntry->PartitionType
2391 return TRUE;
2392
2393 return FALSE;
2394 }
2395
2396
2397 static
2398 ULONG
2399 GetPrimaryPartitionCount(
2400 IN PDISKENTRY DiskEntry)
2401 {
2402 PLIST_ENTRY Entry;
2403 PPARTENTRY PartEntry;
2404 ULONG Count = 0;
2405
2406 Entry = DiskEntry->PrimaryPartListHead.Flink;
2407 while (Entry != &DiskEntry->PrimaryPartListHead)
2408 {
2409 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2410 if (PartEntry->IsPartitioned == TRUE)
2411 Count++;
2412
2413 Entry = Entry->Flink;
2414 }
2415
2416 return Count;
2417 }
2418
2419
2420 static
2421 ULONG
2422 GetLogicalPartitionCount(
2423 PDISKENTRY DiskEntry)
2424 {
2425 PLIST_ENTRY ListEntry;
2426 PPARTENTRY PartEntry;
2427 ULONG Count = 0;
2428
2429 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2430 while (ListEntry != &DiskEntry->LogicalPartListHead)
2431 {
2432 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2433 if (PartEntry->IsPartitioned)
2434 Count++;
2435
2436 ListEntry = ListEntry->Flink;
2437 }
2438
2439 return Count;
2440 }
2441
2442
2443 static
2444 BOOL
2445 ReAllocateLayoutBuffer(
2446 PDISKENTRY DiskEntry)
2447 {
2448 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2449 ULONG NewPartitionCount;
2450 ULONG CurrentPartitionCount = 0;
2451 ULONG LayoutBufferSize;
2452 ULONG i;
2453
2454 DPRINT1("ReAllocateLayoutBuffer()\n");
2455
2456 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2457
2458 if (DiskEntry->LayoutBuffer)
2459 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2460
2461 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2462 CurrentPartitionCount, NewPartitionCount);
2463
2464 if (CurrentPartitionCount == NewPartitionCount)
2465 return TRUE;
2466
2467 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2468 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2469 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2470 HEAP_ZERO_MEMORY,
2471 DiskEntry->LayoutBuffer,
2472 LayoutBufferSize);
2473 if (NewLayoutBuffer == NULL)
2474 {
2475 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2476 return FALSE;
2477 }
2478
2479 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2480 if (NewPartitionCount > CurrentPartitionCount)
2481 {
2482 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2483 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2484 }
2485
2486 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2487 DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
2488
2489 return TRUE;
2490 }
2491
2492
2493 static
2494 VOID
2495 UpdateDiskLayout(
2496 IN PDISKENTRY DiskEntry)
2497 {
2498 PPARTITION_INFORMATION PartitionInfo;
2499 PPARTITION_INFORMATION LinkInfo = NULL;
2500 PLIST_ENTRY ListEntry;
2501 PPARTENTRY PartEntry;
2502 LARGE_INTEGER HiddenSectors64;
2503 ULONG Index;
2504 ULONG PartitionNumber = 1;
2505
2506 DPRINT1("UpdateDiskLayout()\n");
2507
2508 /* Resize the layout buffer if necessary */
2509 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2510 {
2511 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2512 return;
2513 }
2514
2515 /* Update the primary partition table */
2516 Index = 0;
2517 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2518 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2519 {
2520 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2521
2522 if (PartEntry->IsPartitioned == TRUE)
2523 {
2524 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2525
2526 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2527 {
2528 DPRINT1("Updating primary partition entry %lu\n", Index);
2529
2530 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2531 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2532 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2533 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2534 PartitionInfo->PartitionType = PartEntry->PartitionType;
2535 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2536 PartitionInfo->RecognizedPartition = FALSE;
2537 PartitionInfo->RewritePartition = TRUE;
2538 }
2539
2540 PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2541 PartEntry->PartitionIndex = Index;
2542
2543 if (!IsContainerPartition(PartEntry->PartitionType))
2544 PartitionNumber++;
2545
2546 Index++;
2547 }
2548
2549 ListEntry = ListEntry->Flink;
2550 }
2551
2552 /* Update the logical partition tables */
2553 Index = 4;
2554 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2555 while (ListEntry != &DiskEntry->LogicalPartListHead)
2556 {
2557 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2558
2559 if (PartEntry->IsPartitioned)
2560 {
2561 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2562
2563 DPRINT1("Updating logical partition entry %lu\n", Index);
2564
2565 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2566 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2567 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2568 PartitionInfo->PartitionNumber = PartitionNumber;
2569 PartitionInfo->PartitionType = PartEntry->PartitionType;
2570 PartitionInfo->BootIndicator = FALSE;
2571 PartitionInfo->RecognizedPartition = FALSE;
2572 PartitionInfo->RewritePartition = TRUE;
2573
2574 PartEntry->PartitionNumber = PartitionNumber;
2575 PartEntry->PartitionIndex = Index;
2576
2577 /* Fill the link entry of the previous partition table */
2578 if (LinkInfo != NULL)
2579 {
2580 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2581 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2582 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2583 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2584 LinkInfo->PartitionNumber = 0;
2585 LinkInfo->PartitionType = PARTITION_EXTENDED;
2586 LinkInfo->BootIndicator = FALSE;
2587 LinkInfo->RecognizedPartition = FALSE;
2588 LinkInfo->RewritePartition = TRUE;
2589 }
2590
2591 /* Save a pointer to the link entry of the current partition table */
2592 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2593
2594 PartitionNumber++;
2595 Index += 4;
2596 }
2597
2598 ListEntry = ListEntry->Flink;
2599 }
2600
2601 /* Wipe unused primary partition table entries */
2602 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2603 {
2604 DPRINT1("Primary partition entry %lu\n", Index);
2605
2606 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2607
2608 if (!IsEmptyLayoutEntry(PartitionInfo))
2609 {
2610 DPRINT1("Wiping primary partition entry %lu\n", Index);
2611
2612 PartitionInfo->StartingOffset.QuadPart = 0;
2613 PartitionInfo->PartitionLength.QuadPart = 0;
2614 PartitionInfo->HiddenSectors = 0;
2615 PartitionInfo->PartitionNumber = 0;
2616 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2617 PartitionInfo->BootIndicator = FALSE;
2618 PartitionInfo->RecognizedPartition = FALSE;
2619 PartitionInfo->RewritePartition = TRUE;
2620 }
2621 }
2622
2623 /* Wipe unused logical partition table entries */
2624 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2625 {
2626 if (Index % 4 >= 2)
2627 {
2628 DPRINT1("Logical partition entry %lu\n", Index);
2629
2630 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2631
2632 if (!IsEmptyLayoutEntry(PartitionInfo))
2633 {
2634 DPRINT1("Wiping partition entry %lu\n", Index);
2635
2636 PartitionInfo->StartingOffset.QuadPart = 0;
2637 PartitionInfo->PartitionLength.QuadPart = 0;
2638 PartitionInfo->HiddenSectors = 0;
2639 PartitionInfo->PartitionNumber = 0;
2640 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2641 PartitionInfo->BootIndicator = FALSE;
2642 PartitionInfo->RecognizedPartition = FALSE;
2643 PartitionInfo->RewritePartition = TRUE;
2644 }
2645 }
2646 }
2647
2648 #ifdef DUMP_PARTITION_TABLE
2649 DumpPartitionTable(DiskEntry);
2650 #endif
2651 }
2652
2653
2654 static
2655 PPARTENTRY
2656 GetPrevUnpartitionedEntry(
2657 PDISKENTRY DiskEntry,
2658 PPARTENTRY PartEntry)
2659 {
2660 PPARTENTRY PrevPartEntry;
2661 PLIST_ENTRY ListHead;
2662
2663 if (PartEntry->LogicalPartition)
2664 ListHead = &DiskEntry->LogicalPartListHead;
2665 else
2666 ListHead = &DiskEntry->PrimaryPartListHead;
2667
2668 if (PartEntry->ListEntry.Blink != ListHead)
2669 {
2670 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2671 PARTENTRY,
2672 ListEntry);
2673 if (PrevPartEntry->IsPartitioned == FALSE)
2674 return PrevPartEntry;
2675 }
2676
2677 return NULL;
2678 }
2679
2680
2681 static
2682 PPARTENTRY
2683 GetNextUnpartitionedEntry(
2684 PDISKENTRY DiskEntry,
2685 PPARTENTRY PartEntry)
2686 {
2687 PPARTENTRY NextPartEntry;
2688 PLIST_ENTRY ListHead;
2689
2690 if (PartEntry->LogicalPartition)
2691 ListHead = &DiskEntry->LogicalPartListHead;
2692 else
2693 ListHead = &DiskEntry->PrimaryPartListHead;
2694
2695 if (PartEntry->ListEntry.Flink != ListHead)
2696 {
2697 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2698 PARTENTRY,
2699 ListEntry);
2700 if (NextPartEntry->IsPartitioned == FALSE)
2701 return NextPartEntry;
2702 }
2703
2704 return NULL;
2705 }
2706
2707
2708 VOID
2709 CreatePrimaryPartition(
2710 PPARTLIST List,
2711 ULONGLONG SectorCount,
2712 BOOLEAN AutoCreate)
2713 {
2714 PDISKENTRY DiskEntry;
2715 PPARTENTRY PartEntry;
2716 PPARTENTRY NewPartEntry;
2717
2718 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2719
2720 if (List == NULL ||
2721 List->CurrentDisk == NULL ||
2722 List->CurrentPartition == NULL ||
2723 List->CurrentPartition->IsPartitioned == TRUE)
2724 {
2725 return;
2726 }
2727
2728 DiskEntry = List->CurrentDisk;
2729 PartEntry = List->CurrentPartition;
2730
2731 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2732
2733 if (AutoCreate == TRUE ||
2734 AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2735 {
2736 DPRINT1("Convert existing partition entry\n");
2737
2738 /* Convert current entry to 'new (unformatted)' */
2739 PartEntry->IsPartitioned = TRUE;
2740 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2741 PartEntry->FormatState = Unformatted;
2742 PartEntry->AutoCreate = AutoCreate;
2743 PartEntry->New = TRUE;
2744 PartEntry->BootIndicator = FALSE;
2745
2746 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2747 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2748 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2749 }
2750 else
2751 {
2752 DPRINT1("Add new partition entry\n");
2753
2754 /* Insert and initialize a new partition entry */
2755 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2756 HEAP_ZERO_MEMORY,
2757 sizeof(PARTENTRY));
2758 if (NewPartEntry == NULL)
2759 return;
2760
2761 /* Insert the new entry into the list */
2762 InsertTailList(&PartEntry->ListEntry,
2763 &NewPartEntry->ListEntry);
2764
2765 NewPartEntry->DiskEntry = DiskEntry;
2766
2767 NewPartEntry->IsPartitioned = TRUE;
2768 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2769 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2770 NewPartEntry->StartSector.QuadPart;
2771 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2772
2773 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2774 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2775 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2776
2777 NewPartEntry->New = TRUE;
2778 NewPartEntry->FormatState = Unformatted;
2779 NewPartEntry->BootIndicator = FALSE;
2780
2781 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2782 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2783 }
2784
2785 UpdateDiskLayout(DiskEntry);
2786
2787 DiskEntry->Dirty = TRUE;
2788
2789 AssignDriveLetters(List);
2790 }
2791
2792
2793 static
2794 VOID
2795 AddLogicalDiskSpace(
2796 PDISKENTRY DiskEntry)
2797 {
2798 PPARTENTRY NewPartEntry;
2799
2800 DPRINT1("AddLogicalDiskSpace()\n");
2801
2802 /* Create a partition table entry that represents the empty space in the container partition */
2803 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2804 HEAP_ZERO_MEMORY,
2805 sizeof(PARTENTRY));
2806 if (NewPartEntry == NULL)
2807 return;
2808
2809 NewPartEntry->DiskEntry = DiskEntry;
2810 NewPartEntry->LogicalPartition = TRUE;
2811
2812 NewPartEntry->IsPartitioned = FALSE;
2813 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2814 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2815
2816 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2817 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2818 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2819
2820 NewPartEntry->FormatState = Unformatted;
2821
2822 InsertTailList(&DiskEntry->LogicalPartListHead,
2823 &NewPartEntry->ListEntry);
2824 }
2825
2826
2827 VOID
2828 CreateExtendedPartition(
2829 PPARTLIST List,
2830 ULONGLONG SectorCount)
2831 {
2832 PDISKENTRY DiskEntry;
2833 PPARTENTRY PartEntry;
2834 PPARTENTRY NewPartEntry;
2835
2836 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2837
2838 if (List == NULL ||
2839 List->CurrentDisk == NULL ||
2840 List->CurrentPartition == NULL ||
2841 List->CurrentPartition->IsPartitioned == TRUE)
2842 {
2843 return;
2844 }
2845
2846 DiskEntry = List->CurrentDisk;
2847 PartEntry = List->CurrentPartition;
2848
2849 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2850
2851 if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2852 {
2853 DPRINT1("Convert existing partition entry\n");
2854
2855 /* Convert current entry to 'new (unformatted)' */
2856 PartEntry->IsPartitioned = TRUE;
2857 PartEntry->FormatState = Formatted;
2858 PartEntry->AutoCreate = FALSE;
2859 PartEntry->New = FALSE;
2860 PartEntry->BootIndicator = FALSE;
2861
2862 if (PartEntry->StartSector.QuadPart < 1450560)
2863 {
2864 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2865 PartEntry->PartitionType = PARTITION_EXTENDED;
2866 }
2867 else
2868 {
2869 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2870 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2871 }
2872
2873 DiskEntry->ExtendedPartition = PartEntry;
2874
2875 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2876 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2877 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2878 }
2879 else
2880 {
2881 DPRINT1("Add new partition entry\n");
2882
2883 /* Insert and initialize a new partition entry */
2884 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2885 HEAP_ZERO_MEMORY,
2886 sizeof(PARTENTRY));
2887 if (NewPartEntry == NULL)
2888 return;
2889
2890 /* Insert the new entry into the list */
2891 InsertTailList(&PartEntry->ListEntry,
2892 &NewPartEntry->ListEntry);
2893
2894 NewPartEntry->DiskEntry = DiskEntry;
2895
2896 NewPartEntry->IsPartitioned = TRUE;
2897 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2898 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2899 NewPartEntry->StartSector.QuadPart;
2900
2901 NewPartEntry->New = FALSE;
2902 NewPartEntry->FormatState = Formatted;
2903 NewPartEntry->BootIndicator = FALSE;
2904
2905 if (NewPartEntry->StartSector.QuadPart < 1450560)
2906 {
2907 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2908 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2909 }
2910 else
2911 {
2912 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2913 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2914 }
2915
2916 DiskEntry->ExtendedPartition = NewPartEntry;
2917
2918 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2919 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2920
2921 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2922 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2923 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2924 }
2925
2926 AddLogicalDiskSpace(DiskEntry);
2927
2928 UpdateDiskLayout(DiskEntry);
2929
2930 DiskEntry->Dirty = TRUE;
2931
2932 AssignDriveLetters(List);
2933 }
2934
2935
2936 VOID
2937 CreateLogicalPartition(
2938 PPARTLIST List,
2939 ULONGLONG SectorCount,
2940 BOOLEAN AutoCreate)
2941 {
2942 PDISKENTRY DiskEntry;
2943 PPARTENTRY PartEntry;
2944 PPARTENTRY NewPartEntry;
2945
2946 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2947
2948 if (List == NULL ||
2949 List->CurrentDisk == NULL ||
2950 List->CurrentPartition == NULL ||
2951 List->CurrentPartition->IsPartitioned == TRUE)
2952 {
2953 return;
2954 }
2955
2956 DiskEntry = List->CurrentDisk;
2957 PartEntry = List->CurrentPartition;
2958
2959 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2960
2961 if (AutoCreate == TRUE ||
2962 AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2963 {
2964 DPRINT1("Convert existing partition entry\n");
2965
2966 /* Convert current entry to 'new (unformatted)' */
2967 PartEntry->IsPartitioned = TRUE;
2968 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2969 PartEntry->FormatState = Unformatted;
2970 PartEntry->AutoCreate = FALSE;
2971 PartEntry->New = TRUE;
2972 PartEntry->BootIndicator = FALSE;
2973 PartEntry->LogicalPartition = TRUE;
2974
2975 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2976 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2977 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2978 }
2979 else
2980 {
2981 DPRINT1("Add new partition entry\n");
2982
2983 /* Insert and initialize a new partition entry */
2984 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2985 HEAP_ZERO_MEMORY,
2986 sizeof(PARTENTRY));
2987 if (NewPartEntry == NULL)
2988 return;
2989
2990 /* Insert the new entry into the list */
2991 InsertTailList(&PartEntry->ListEntry,
2992 &NewPartEntry->ListEntry);
2993
2994 NewPartEntry->DiskEntry = DiskEntry;
2995
2996 NewPartEntry->IsPartitioned = TRUE;
2997 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2998 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2999 NewPartEntry->StartSector.QuadPart;
3000 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3001
3002 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
3003 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
3004 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
3005
3006 NewPartEntry->New = TRUE;
3007 NewPartEntry->FormatState = Unformatted;
3008 NewPartEntry->BootIndicator = FALSE;
3009 NewPartEntry->LogicalPartition = TRUE;
3010
3011 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
3012 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
3013 }
3014
3015 UpdateDiskLayout(DiskEntry);
3016
3017 DiskEntry->Dirty = TRUE;
3018
3019 AssignDriveLetters(List);
3020 }
3021
3022
3023 VOID
3024 DeleteCurrentPartition(
3025 PPARTLIST List)
3026 {
3027 PDISKENTRY DiskEntry;
3028 PPARTENTRY PartEntry;
3029 PPARTENTRY PrevPartEntry;
3030 PPARTENTRY NextPartEntry;
3031 PPARTENTRY LogicalPartEntry;
3032 PLIST_ENTRY Entry;
3033
3034 if (List == NULL ||
3035 List->CurrentDisk == NULL ||
3036 List->CurrentPartition == NULL ||
3037 List->CurrentPartition->IsPartitioned == FALSE)
3038 {
3039 return;
3040 }
3041
3042 DiskEntry = List->CurrentDisk;
3043 PartEntry = List->CurrentPartition;
3044
3045 /* Delete all logical partiton entries if an extended partition will be deleted */
3046 if (DiskEntry->ExtendedPartition == PartEntry)
3047 {
3048 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
3049 {
3050 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
3051 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3052
3053 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
3054 }
3055
3056 DiskEntry->ExtendedPartition = NULL;
3057 }
3058
3059 /* Adjust unpartitioned disk space entries */
3060
3061 /* Get pointer to previous and next unpartitioned entries */
3062 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry,
3063 PartEntry);
3064
3065 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry,
3066 PartEntry);
3067
3068 if (PrevPartEntry != NULL && NextPartEntry != NULL)
3069 {
3070 /* Merge previous, current and next unpartitioned entry */
3071
3072 /* Adjust the previous entries length */
3073 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
3074
3075 /* Remove the current entry */
3076 RemoveEntryList(&PartEntry->ListEntry);
3077 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3078
3079 /* Remove the next entry */
3080 RemoveEntryList (&NextPartEntry->ListEntry);
3081 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
3082
3083 /* Update current partition */
3084 List->CurrentPartition = PrevPartEntry;
3085 }
3086 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
3087 {
3088 /* Merge current and previous unpartitioned entry */
3089
3090 /* Adjust the previous entries length */
3091 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3092
3093 /* Remove the current entry */
3094 RemoveEntryList(&PartEntry->ListEntry);
3095 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3096
3097 /* Update current partition */
3098 List->CurrentPartition = PrevPartEntry;
3099 }
3100 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
3101 {
3102 /* Merge current and next unpartitioned entry */
3103
3104 /* Adjust the next entries offset and length */
3105 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3106 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3107
3108 /* Remove the current entry */
3109 RemoveEntryList(&PartEntry->ListEntry);
3110 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3111
3112 /* Update current partition */
3113 List->CurrentPartition = NextPartEntry;
3114 }
3115 else
3116 {
3117 /* Nothing to merge but change current entry */
3118 PartEntry->IsPartitioned = FALSE;
3119 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3120 PartEntry->FormatState = Unformatted;
3121 PartEntry->DriveLetter = 0;
3122 }
3123
3124 UpdateDiskLayout(DiskEntry);
3125
3126 DiskEntry->Dirty = TRUE;
3127
3128 AssignDriveLetters(List);
3129 }
3130
3131
3132 VOID
3133 CheckActiveBootPartition(
3134 PPARTLIST List)
3135 {
3136 PDISKENTRY DiskEntry;
3137 PPARTENTRY PartEntry;
3138 PLIST_ENTRY ListEntry;
3139
3140 /* Check for empty disk list */
3141 if (IsListEmpty (&List->DiskListHead))
3142 {
3143 List->BootDisk = NULL;
3144 List->BootPartition = NULL;
3145 return;
3146 }
3147
3148 #if 0
3149 if (List->BootDisk != NULL &&
3150 List->BootPartition != NULL)
3151 {
3152 /* We already have an active boot partition */
3153 return;
3154 }
3155 #endif
3156
3157 /* Choose the currently selected disk */
3158 DiskEntry = List->CurrentDisk;
3159
3160 /* Check for empty partition list */
3161 if (IsListEmpty (&DiskEntry->PrimaryPartListHead))
3162 {
3163 List->BootDisk = NULL;
3164 List->BootPartition = NULL;
3165 return;
3166 }
3167
3168 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3169 PARTENTRY,
3170 ListEntry);
3171
3172 /* Set active boot partition */
3173 if ((DiskEntry->NewDisk == TRUE) ||
3174 (PartEntry->BootIndicator == FALSE))
3175 {
3176 PartEntry->BootIndicator = TRUE;
3177 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
3178 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3179 DiskEntry->Dirty = TRUE;
3180
3181 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
3182 List->BootDisk = DiskEntry;
3183 List->BootPartition = PartEntry;
3184
3185 return;
3186 }
3187
3188 /* Disk is not new, scan all partitions to find a bootable one */
3189 List->BootDisk = NULL;
3190 List->BootPartition = NULL;
3191
3192 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3193 while (ListEntry != &DiskEntry->PrimaryPartListHead)
3194 {
3195 PartEntry = CONTAINING_RECORD(ListEntry,
3196 PARTENTRY,
3197 ListEntry);
3198
3199 /* Check if it is partitioned */
3200 if (PartEntry->IsPartitioned)
3201 {
3202 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED &&
3203 PartEntry->BootIndicator)
3204 {
3205 /* Yes, we found it */
3206 List->BootDisk = DiskEntry;
3207 List->BootPartition = PartEntry;
3208
3209 DPRINT("Found bootable partition disk %d, drive letter %c\n",
3210 DiskEntry->DiskNumber, PartEntry->DriveLetter);
3211 break;
3212 }
3213 }
3214
3215 /* Go to the next one */
3216 ListEntry = ListEntry->Flink;
3217 }
3218 }
3219
3220
3221 static
3222 NTSTATUS
3223 WritePartitions(
3224 IN PPARTLIST List,
3225 IN PDISKENTRY DiskEntry)
3226 {
3227 WCHAR DstPath[MAX_PATH];
3228 OBJECT_ATTRIBUTES ObjectAttributes;
3229 IO_STATUS_BLOCK Iosb;
3230 UNICODE_STRING Name;
3231 ULONG BufferSize;
3232 HANDLE FileHandle = NULL;
3233 NTSTATUS Status;
3234
3235 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3236
3237 swprintf(DstPath,
3238 L"\\Device\\Harddisk%d\\Partition0",
3239 DiskEntry->DiskNumber);
3240 RtlInitUnicodeString(&Name,
3241 DstPath);
3242 InitializeObjectAttributes(&ObjectAttributes,
3243 &Name,
3244 0,
3245 NULL,
3246 NULL);
3247
3248 Status = NtOpenFile(&FileHandle,
3249 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3250 &ObjectAttributes,
3251 &Iosb,
3252 0,
3253 FILE_SYNCHRONOUS_IO_NONALERT);
3254 if (!NT_SUCCESS(Status))
3255 {
3256 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3257 return Status;
3258 }
3259
3260 #ifdef DUMP_PARTITION_TABLE
3261 DumpPartitionTable(DiskEntry);
3262 #endif
3263
3264 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3265 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3266 Status = NtDeviceIoControlFile(FileHandle,
3267 NULL,
3268 NULL,
3269 NULL,
3270 &Iosb,
3271 IOCTL_DISK_SET_DRIVE_LAYOUT,
3272 DiskEntry->LayoutBuffer,
3273 BufferSize,
3274 NULL,
3275 0);
3276 if (!NT_SUCCESS(Status))
3277 {
3278 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3279 }
3280
3281 if (FileHandle != NULL)
3282 NtClose(FileHandle);
3283
3284 return Status;
3285 }
3286
3287
3288 BOOLEAN
3289 WritePartitionsToDisk(
3290 PPARTLIST List)
3291 {
3292 PLIST_ENTRY Entry;
3293 PDISKENTRY DiskEntry;
3294
3295 if (List == NULL)
3296 return TRUE;
3297
3298 Entry = List->DiskListHead.Flink;
3299 while (Entry != &List->DiskListHead)
3300 {
3301 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3302
3303 if (DiskEntry->Dirty == TRUE)
3304 {
3305 WritePartitions(List, DiskEntry);
3306 DiskEntry->Dirty = FALSE;
3307 }
3308
3309 Entry = Entry->Flink;
3310 }
3311
3312 return TRUE;
3313 }
3314
3315
3316 BOOL
3317 SetMountedDeviceValues(
3318 PPARTLIST List)
3319 {
3320 PLIST_ENTRY Entry1, Entry2;
3321 PDISKENTRY DiskEntry;
3322 PPARTENTRY PartEntry;
3323 LARGE_INTEGER StartingOffset;
3324
3325 if (List == NULL)
3326 {
3327 return FALSE;
3328 }
3329
3330 Entry1 = List->DiskListHead.Flink;
3331 while (Entry1 != &List->DiskListHead)
3332 {
3333 DiskEntry = CONTAINING_RECORD(Entry1,
3334 DISKENTRY,
3335 ListEntry);
3336
3337 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3338 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3339 {
3340 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3341 if (PartEntry->IsPartitioned)
3342 {
3343 if (PartEntry->DriveLetter)
3344 {
3345 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3346 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3347 DiskEntry->LayoutBuffer->Signature,
3348 StartingOffset))
3349 {
3350 return FALSE;
3351 }
3352 }
3353 }
3354
3355 Entry2 = Entry2->Flink;
3356 }
3357
3358 Entry1 = Entry1->Flink;
3359 }
3360
3361 return TRUE;
3362 }
3363
3364
3365 ULONG
3366 PrimaryPartitionCreationChecks(
3367 IN PPARTLIST List)
3368 {
3369 PDISKENTRY DiskEntry;
3370 PPARTENTRY PartEntry;
3371
3372 DiskEntry = List->CurrentDisk;
3373 PartEntry = List->CurrentPartition;
3374
3375 /* Fail if partition is already in use */
3376 if (PartEntry->IsPartitioned == TRUE)
3377 return ERROR_NEW_PARTITION;
3378
3379 /* Fail if there are more than 4 partitions in the list */
3380 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3381 return ERROR_PARTITION_TABLE_FULL;
3382
3383 return ERROR_SUCCESS;
3384 }
3385
3386
3387 ULONG
3388 ExtendedPartitionCreationChecks(
3389 IN PPARTLIST List)
3390 {
3391 PDISKENTRY DiskEntry;
3392 PPARTENTRY PartEntry;
3393
3394 DiskEntry = List->CurrentDisk;
3395 PartEntry = List->CurrentPartition;
3396
3397 /* Fail if partition is already in use */
3398 if (PartEntry->IsPartitioned == TRUE)
3399 return ERROR_NEW_PARTITION;
3400
3401 /* Fail if there are more than 4 partitions in the list */
3402 if (GetPrimaryPartitionCount(DiskEntry) > 4)
3403 return ERROR_PARTITION_TABLE_FULL;
3404
3405 /* Fail if there is another extended partition in the list */
3406 if (DiskEntry->ExtendedPartition != NULL)
3407 return ERROR_ONLY_ONE_EXTENDED;
3408
3409 return ERROR_SUCCESS;
3410 }
3411
3412
3413 ULONG
3414 LogicalPartitionCreationChecks(
3415 IN PPARTLIST List)
3416 {
3417 // PDISKENTRY DiskEntry;
3418 PPARTENTRY PartEntry;
3419
3420 // DiskEntry = List->CurrentDisk;
3421 PartEntry = List->CurrentPartition;
3422
3423 /* Fail if partition is already in use */
3424 if (PartEntry->IsPartitioned == TRUE)
3425 return ERROR_NEW_PARTITION;
3426
3427 return ERROR_SUCCESS;
3428 }
3429
3430
3431 BOOL
3432 GetNextUnformattedPartition(
3433 IN PPARTLIST List,
3434 OUT PDISKENTRY *pDiskEntry,
3435 OUT PPARTENTRY *pPartEntry)
3436 {
3437 PLIST_ENTRY Entry1, Entry2;
3438 PDISKENTRY DiskEntry;
3439 PPARTENTRY PartEntry;
3440
3441 Entry1 = List->DiskListHead.Flink;
3442 while (Entry1 != &List->DiskListHead)
3443 {
3444 DiskEntry = CONTAINING_RECORD(Entry1,
3445 DISKENTRY,
3446 ListEntry);
3447
3448 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3449 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3450 {
3451 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3452 if (PartEntry->IsPartitioned && PartEntry->New)
3453 {
3454 *pDiskEntry = DiskEntry;
3455 *pPartEntry = PartEntry;
3456 return TRUE;
3457 }
3458
3459 Entry2 = Entry2->Flink;
3460 }
3461
3462 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3463 while (Entry2 != &DiskEntry->LogicalPartListHead)
3464 {
3465 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3466 if (PartEntry->IsPartitioned && PartEntry->New)
3467 {
3468 *pDiskEntry = DiskEntry;
3469 *pPartEntry = PartEntry;
3470 return TRUE;
3471 }
3472
3473 Entry2 = Entry2->Flink;
3474 }
3475
3476 Entry1 = Entry1->Flink;
3477 }
3478
3479 *pDiskEntry = NULL;
3480 *pPartEntry = NULL;
3481
3482 return FALSE;
3483 }
3484
3485
3486 BOOL
3487 GetNextUncheckedPartition(
3488 IN PPARTLIST List,
3489 OUT PDISKENTRY *pDiskEntry,
3490 OUT PPARTENTRY *pPartEntry)
3491 {
3492 PLIST_ENTRY Entry1, Entry2;
3493 PDISKENTRY DiskEntry;
3494 PPARTENTRY PartEntry;
3495
3496 Entry1 = List->DiskListHead.Flink;
3497 while (Entry1 != &List->DiskListHead)
3498 {
3499 DiskEntry = CONTAINING_RECORD(Entry1,
3500 DISKENTRY,
3501 ListEntry);
3502
3503 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3504 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3505 {
3506 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3507 if (PartEntry->NeedsCheck == TRUE)
3508 {
3509 *pDiskEntry = DiskEntry;
3510 *pPartEntry = PartEntry;
3511 return TRUE;
3512 }
3513
3514 Entry2 = Entry2->Flink;
3515 }
3516
3517 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3518 while (Entry2 != &DiskEntry->LogicalPartListHead)
3519 {
3520 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3521 if (PartEntry->NeedsCheck == TRUE)
3522 {
3523 *pDiskEntry = DiskEntry;
3524 *pPartEntry = PartEntry;
3525 return TRUE;
3526 }
3527
3528 Entry2 = Entry2->Flink;
3529 }
3530
3531 Entry1 = Entry1->Flink;
3532 }
3533
3534 *pDiskEntry = NULL;
3535 *pPartEntry = NULL;
3536
3537 return FALSE;
3538 }
3539
3540 /* EOF */