Cleanup in .inf file handling of 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/partlist.c
23 * PURPOSE: Partition list functions
24 * PROGRAMMER: Eric Kohl
25 * Casper S. Hornstrup (chorns@users.sourceforge.net)
26 */
27
28 #include "usetup.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 static VOID
36 GetDriverName (PDISKENTRY DiskEntry)
37 {
38 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
39 WCHAR KeyName[32];
40 NTSTATUS Status;
41
42 RtlInitUnicodeString (&DiskEntry->DriverName,
43 NULL);
44
45 swprintf (KeyName,
46 L"\\Scsi\\Scsi Port %lu",
47 DiskEntry->Port);
48
49 RtlZeroMemory (&QueryTable,
50 sizeof(QueryTable));
51
52 QueryTable[0].Name = L"Driver";
53 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
54 QueryTable[0].EntryContext = &DiskEntry->DriverName;
55
56 Status = RtlQueryRegistryValues (RTL_REGISTRY_DEVICEMAP,
57 KeyName,
58 QueryTable,
59 NULL,
60 NULL);
61 if (!NT_SUCCESS (Status))
62 {
63 DPRINT1 ("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
64 }
65 }
66
67
68 static VOID
69 AssignDriverLetters (PPARTLIST List)
70 {
71 PDISKENTRY DiskEntry;
72 PPARTENTRY PartEntry;
73 PLIST_ENTRY Entry1;
74 PLIST_ENTRY Entry2;
75 CHAR Letter;
76
77 Letter = 'C';
78
79 /* Assign drive letters to primary partitions */
80 Entry1 = List->DiskListHead.Flink;
81 while (Entry1 != &List->DiskListHead)
82 {
83 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
84
85 if (!IsListEmpty (&DiskEntry->PartListHead))
86 {
87 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
88 PARTENTRY,
89 ListEntry);
90
91 PartEntry->DriveLetter = 0;
92
93 if (PartEntry->Unpartitioned == FALSE &&
94 !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
95 {
96 if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
97 (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
98 PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
99 {
100 if (Letter <= 'Z')
101 {
102 PartEntry->DriveLetter = Letter;
103 Letter++;
104 }
105 }
106 }
107 }
108
109 Entry1 = Entry1->Flink;
110 }
111
112
113 /* Assign drive letters to logical drives */
114 Entry1 = List->DiskListHead.Flink;
115 while (Entry1 != &List->DiskListHead)
116 {
117 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
118
119 Entry2 = DiskEntry->PartListHead.Flink;
120 if (Entry2 != &DiskEntry->PartListHead)
121 {
122 Entry2 = Entry2->Flink;
123 while (Entry2 != &DiskEntry->PartListHead)
124 {
125 PartEntry = CONTAINING_RECORD (Entry2,
126 PARTENTRY,
127 ListEntry);
128
129 PartEntry->DriveLetter = 0;
130
131 if (PartEntry->Unpartitioned == FALSE &&
132 !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
133 {
134 if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
135 (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
136 PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
137 {
138 if (Letter <= 'Z')
139 {
140 PartEntry->DriveLetter = Letter;
141 Letter++;
142 }
143 }
144 }
145
146 Entry2 = Entry2->Flink;
147 }
148 }
149
150 Entry1 = Entry1->Flink;
151 }
152 }
153
154
155 static VOID
156 UpdatePartitionNumbers (PDISKENTRY DiskEntry)
157 {
158 PPARTENTRY PartEntry;
159 PLIST_ENTRY Entry;
160 ULONG PartNumber;
161 ULONG i;
162
163 PartNumber = 1;
164 Entry = DiskEntry->PartListHead.Flink;
165 while (Entry != &DiskEntry->PartListHead)
166 {
167 PartEntry = CONTAINING_RECORD (Entry,
168 PARTENTRY,
169 ListEntry);
170
171 if (PartEntry->Unpartitioned == TRUE)
172 {
173 for (i = 0; i < 4; i++)
174 {
175 PartEntry->PartInfo[i].PartitionNumber = 0;
176 }
177 }
178 else
179 {
180 for (i = 0; i < 4; i++)
181 {
182 if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
183 {
184 PartEntry->PartInfo[i].PartitionNumber = 0;
185 }
186 else if (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
187 PartEntry->PartInfo[i].PartitionLength.QuadPart == 0ULL)
188 {
189 PartEntry->PartInfo[i].PartitionNumber = 0;
190 }
191 else
192 {
193 PartEntry->PartInfo[i].PartitionNumber = PartNumber;
194 PartNumber++;
195 }
196 }
197 }
198
199 Entry = Entry->Flink;
200 }
201 }
202
203
204 static VOID
205 AddPartitionToList (ULONG DiskNumber,
206 PDISKENTRY DiskEntry,
207 DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
208 {
209 PPARTENTRY PartEntry;
210 ULONG i;
211 ULONG j;
212
213 for (i = 0; i < LayoutBuffer->PartitionCount; i += 4)
214 {
215 for (j = 0; j < 4; j++)
216 {
217 if (LayoutBuffer->PartitionEntry[j].PartitionType != PARTITION_ENTRY_UNUSED ||
218 LayoutBuffer->PartitionEntry[j].PartitionLength.QuadPart != 0ULL)
219 {
220 break;
221 }
222 }
223 if (j >= 4)
224 {
225 continue;
226 }
227
228 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
229 0,
230 sizeof(PARTENTRY));
231 if (PartEntry == NULL)
232 {
233 return;
234 }
235
236 RtlZeroMemory (PartEntry,
237 sizeof(PARTENTRY));
238
239 PartEntry->Unpartitioned = FALSE;
240
241 for (j = 0; j < 4; j++)
242 {
243 RtlCopyMemory (&PartEntry->PartInfo[j],
244 &LayoutBuffer->PartitionEntry[i+j],
245 sizeof(PARTITION_INFORMATION));
246 }
247
248 if (IsContainerPartition(PartEntry->PartInfo[0].PartitionType))
249 {
250 PartEntry->FormatState = Unformatted;
251 }
252 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
253 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
254 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
255 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13) ||
256 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
257 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
258 {
259 #if 0
260 if (CheckFatFormat())
261 {
262 PartEntry->FormatState = Preformatted;
263 }
264 else
265 {
266 PartEntry->FormatState = Unformatted;
267 }
268 #endif
269 PartEntry->FormatState = Preformatted;
270 }
271 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
272 {
273 #if 0
274 if (CheckNtfsFormat())
275 {
276 PartEntry->FormatState = Preformatted;
277 }
278 else if (CheckHpfsFormat())
279 {
280 PartEntry->FormatState = Preformatted;
281 }
282 else
283 {
284 PartEntry->FormatState = Unformatted;
285 }
286 #endif
287 PartEntry->FormatState = Preformatted;
288 }
289 else
290 {
291 PartEntry->FormatState = Unknown;
292 }
293
294 InsertTailList (&DiskEntry->PartListHead,
295 &PartEntry->ListEntry);
296 }
297 }
298
299
300 static VOID
301 ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
302 {
303 ULONGLONG LastStartingOffset;
304 ULONGLONG LastPartitionLength;
305 ULONGLONG LastUnusedPartitionLength;
306 PPARTENTRY PartEntry;
307 PPARTENTRY NewPartEntry;
308 PLIST_ENTRY Entry;
309 ULONG i;
310 ULONG j;
311
312 if (IsListEmpty (&DiskEntry->PartListHead))
313 {
314 /* Create a partition table that represents the empty disk */
315 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
316 0,
317 sizeof(PARTENTRY));
318 if (PartEntry == NULL)
319 return;
320
321 RtlZeroMemory (PartEntry,
322 sizeof(PARTENTRY));
323
324 PartEntry->Unpartitioned = TRUE;
325 PartEntry->UnpartitionedOffset = 0ULL;
326 PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
327
328 PartEntry->FormatState = Unformatted;
329
330 InsertTailList (&DiskEntry->PartListHead,
331 &PartEntry->ListEntry);
332 }
333 else
334 {
335 /* Start partition at head 1, cylinder 0 */
336 LastStartingOffset = DiskEntry->TrackSize;
337 LastPartitionLength = 0ULL;
338 LastUnusedPartitionLength = 0ULL;
339
340 i = 0;
341 Entry = DiskEntry->PartListHead.Flink;
342 while (Entry != &DiskEntry->PartListHead)
343 {
344 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
345
346 for (j = 0; j < 4; j++)
347 {
348 if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
349 (PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
350 PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
351 {
352 LastUnusedPartitionLength =
353 PartEntry->PartInfo[j].StartingOffset.QuadPart -
354 (LastStartingOffset + LastPartitionLength);
355
356 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
357 {
358 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
359
360 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
361 0,
362 sizeof(PARTENTRY));
363 if (NewPartEntry == NULL)
364 return;
365
366 RtlZeroMemory (NewPartEntry,
367 sizeof(PARTENTRY));
368
369 NewPartEntry->Unpartitioned = TRUE;
370 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
371 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
372 if (j == 0)
373 NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
374
375 NewPartEntry->FormatState = Unformatted;
376
377 /* Insert the table into the list */
378 InsertTailList (&PartEntry->ListEntry,
379 &NewPartEntry->ListEntry);
380 }
381
382 LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
383 LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
384 }
385 }
386
387 i += 4;
388 Entry = Entry->Flink;
389 }
390
391 /* Check for trailing unpartitioned disk space */
392 if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
393 {
394 /* Round-down to cylinder size */
395 LastUnusedPartitionLength =
396 ROUND_DOWN (DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength),
397 DiskEntry->CylinderSize);
398
399 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
400 {
401 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
402
403 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
404 0,
405 sizeof(PARTENTRY));
406 if (NewPartEntry == NULL)
407 return;
408
409 RtlZeroMemory (NewPartEntry,
410 sizeof(PARTENTRY));
411
412 NewPartEntry->Unpartitioned = TRUE;
413 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
414 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
415
416 /* Append the table to the list */
417 InsertTailList (&DiskEntry->PartListHead,
418 &NewPartEntry->ListEntry);
419 }
420 }
421 }
422 }
423
424 NTSTATUS
425 NTAPI
426 DiskIdentifierQueryRoutine(PWSTR ValueName,
427 ULONG ValueType,
428 PVOID ValueData,
429 ULONG ValueLength,
430 PVOID Context,
431 PVOID EntryContext)
432 {
433 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
434 UNICODE_STRING NameU;
435
436 if (ValueType == REG_SZ &&
437 ValueLength == 20 * sizeof(WCHAR))
438 {
439 NameU.Buffer = (PWCHAR)ValueData;
440 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
441 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
442
443 NameU.Buffer = (PWCHAR)ValueData + 9;
444 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
445
446 return STATUS_SUCCESS;
447 }
448 return STATUS_UNSUCCESSFUL;
449 }
450
451 NTSTATUS
452 NTAPI
453 DiskConfigurationDataQueryRoutine(PWSTR ValueName,
454 ULONG ValueType,
455 PVOID ValueData,
456 ULONG ValueLength,
457 PVOID Context,
458 PVOID EntryContext)
459 {
460 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
461 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
462 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
463
464 if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR &&
465 ValueLength == sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
466 {
467 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
468 /* FIXME:
469 * Is this 'paranoia' check correct ?
470 */
471 if (FullResourceDescriptor->InterfaceType != InterfaceTypeUndefined ||
472 FullResourceDescriptor->BusNumber != 0 ||
473 FullResourceDescriptor->PartialResourceList.Count != 1 ||
474 FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != CmResourceTypeDeviceSpecific ||
475 FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
476 {
477 return STATUS_UNSUCCESSFUL;
478 }
479 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)(FullResourceDescriptor + 1);
480 BiosDiskEntry->DiskGeometry = *DiskGeometry;
481
482 return STATUS_SUCCESS;
483 }
484 return STATUS_UNSUCCESSFUL;
485 }
486
487 NTSTATUS
488 NTAPI
489 SystemConfigurationDataQueryRoutine(PWSTR ValueName,
490 ULONG ValueType,
491 PVOID ValueData,
492 ULONG ValueLength,
493 PVOID Context,
494 PVOID EntryContext)
495 {
496 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
497 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
498
499 if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR &&
500 ValueLength >= sizeof (CM_FULL_RESOURCE_DESCRIPTOR) &&
501 (ValueLength - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) % sizeof(CM_INT13_DRIVE_PARAMETER) == 0)
502 {
503 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
504 if (FullResourceDescriptor->InterfaceType != InterfaceTypeUndefined ||
505 FullResourceDescriptor->BusNumber != -1 ||
506 FullResourceDescriptor->PartialResourceList.Count != 1 ||
507 FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != CmResourceTypeDeviceSpecific)
508 {
509 return STATUS_UNSUCCESSFUL;
510 }
511 *Int13Drives = RtlAllocateHeap(ProcessHeap, 0, ValueLength - sizeof (CM_FULL_RESOURCE_DESCRIPTOR));
512 if (*Int13Drives == NULL)
513 {
514 return STATUS_NO_MEMORY;
515 }
516 memcpy(*Int13Drives, FullResourceDescriptor + 1, ValueLength - sizeof (CM_FULL_RESOURCE_DESCRIPTOR));
517 return STATUS_SUCCESS;
518 }
519 return STATUS_UNSUCCESSFUL;
520
521 }
522 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
523
524 static VOID
525 EnumerateBiosDiskEntries(PPARTLIST PartList)
526 {
527 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
528 WCHAR Name[120];
529 ULONG AdapterCount;
530 ULONG DiskCount;
531 NTSTATUS Status;
532 PCM_INT13_DRIVE_PARAMETER Int13Drives;
533 PBIOSDISKENTRY BiosDiskEntry;
534
535 memset(QueryTable, 0, sizeof(QueryTable));
536
537 QueryTable[1].Name = L"Configuration Data";
538 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
539 Int13Drives = NULL;
540 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
541 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
542 &QueryTable[1],
543 (PVOID)&Int13Drives,
544 NULL);
545 if (!NT_SUCCESS(Status))
546 {
547 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
548 return;
549 }
550
551 AdapterCount = 0;
552 while (1)
553 {
554 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
555 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
556 Name,
557 &QueryTable[2],
558 NULL,
559 NULL);
560 if (!NT_SUCCESS(Status))
561 {
562 break;
563 }
564
565 swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
566 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
567 Name,
568 &QueryTable[2],
569 NULL,
570 NULL);
571 if (NT_SUCCESS(Status))
572 {
573 while (1)
574 {
575 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
576 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
577 Name,
578 &QueryTable[2],
579 NULL,
580 NULL);
581 if (!NT_SUCCESS(Status))
582 {
583 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
584 return;
585 }
586
587 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
588 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
589 Name,
590 &QueryTable[2],
591 NULL,
592 NULL);
593 if (NT_SUCCESS(Status))
594 {
595 QueryTable[0].Name = L"Identifier";
596 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
597 QueryTable[1].Name = L"Configuration Data";
598 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
599 DiskCount = 0;
600 while (1)
601 {
602 BiosDiskEntry = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
603 if (BiosDiskEntry == NULL)
604 {
605 break;
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 BiosDiskEntry->DiskNumber = DiskCount;
619 BiosDiskEntry->Recognized = FALSE;
620
621 if (DiskCount < Int13Drives[0].NumberDrives)
622 {
623 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
624 }
625 else
626 {
627 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
628 }
629
630
631 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
632
633 DPRINT("DiskNumber: %d\n", BiosDiskEntry->DiskNumber);
634 DPRINT("Signature: %08x\n", BiosDiskEntry->Signature);
635 DPRINT("Checksum: %08x\n", BiosDiskEntry->Checksum);
636 DPRINT("BytesPerSector: %d\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
637 DPRINT("NumberOfCylinders: %d\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
638 DPRINT("NumberOfHeads: %d\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
639 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
640 DPRINT("MaxCylinders: %d\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 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
649 return;
650 }
651 }
652 AdapterCount++;
653 }
654 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
655 }
656
657 static VOID
658 AddDiskToList (HANDLE FileHandle,
659 ULONG DiskNumber,
660 PPARTLIST List)
661 {
662 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
663 DISK_GEOMETRY DiskGeometry;
664 SCSI_ADDRESS ScsiAddress;
665 PDISKENTRY DiskEntry;
666 IO_STATUS_BLOCK Iosb;
667 NTSTATUS Status;
668 PPARTITION_SECTOR Mbr;
669 PULONG Buffer;
670 LARGE_INTEGER FileOffset;
671 WCHAR Identifier[20];
672 ULONG Checksum;
673 ULONG Signature;
674 ULONG i;
675 PLIST_ENTRY ListEntry;
676 PBIOSDISKENTRY BiosDiskEntry;
677
678 Status = NtDeviceIoControlFile (FileHandle,
679 NULL,
680 NULL,
681 NULL,
682 &Iosb,
683 IOCTL_DISK_GET_DRIVE_GEOMETRY,
684 NULL,
685 0,
686 &DiskGeometry,
687 sizeof(DISK_GEOMETRY));
688 if (!NT_SUCCESS (Status))
689 {
690 return;
691 }
692
693 if (DiskGeometry.MediaType != FixedMedia)
694 {
695 return;
696 }
697
698 Status = NtDeviceIoControlFile (FileHandle,
699 NULL,
700 NULL,
701 NULL,
702 &Iosb,
703 IOCTL_SCSI_GET_ADDRESS,
704 NULL,
705 0,
706 &ScsiAddress,
707 sizeof(SCSI_ADDRESS));
708 if (!NT_SUCCESS(Status))
709 {
710 return;
711 }
712
713 Mbr = RtlAllocateHeap(ProcessHeap,
714 0,
715 DiskGeometry.BytesPerSector);
716
717 if (Mbr == NULL)
718 {
719 return;
720 }
721
722 FileOffset.QuadPart = 0;
723 Status = NtReadFile(FileHandle,
724 NULL,
725 NULL,
726 NULL,
727 &Iosb,
728 (PVOID)Mbr,
729 DiskGeometry.BytesPerSector,
730 &FileOffset,
731 NULL);
732 if (!NT_SUCCESS(Status))
733 {
734 RtlFreeHeap(ProcessHeap,
735 0,
736 Mbr);
737 DPRINT1("NtReadFile failed, status=%x\n", Status);
738 return;
739 }
740 Signature = Mbr->Signature;
741
742 /* Calculate the MBR checksum */
743 Checksum = 0;
744 Buffer = (PULONG)Mbr;
745 for (i = 0; i < 128; i++)
746 {
747 Checksum += Buffer[i];
748 }
749 Checksum = ~Checksum + 1;
750
751 RtlFreeHeap (ProcessHeap,
752 0,
753 Mbr);
754
755 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
756 DPRINT("Identifier: %S\n", Identifier);
757
758 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
759 0,
760 sizeof(DISKENTRY));
761 if (DiskEntry == NULL)
762 {
763 return;
764 }
765
766 DiskEntry->Checksum = Checksum;
767 DiskEntry->Signature = Signature;
768 if (Signature == 0)
769 {
770 /* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
771 DiskEntry->Modified = TRUE;
772 }
773 DiskEntry->BiosFound = FALSE;
774
775 ListEntry = List->BiosDiskListHead.Flink;
776 while(ListEntry != &List->BiosDiskListHead)
777 {
778 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
779 /* FIXME:
780 * Compare the size from bios and the reported size from driver.
781 * If we have more than one disk with a zero or with the same signatur
782 * we must create new signatures and reboot. After the reboot,
783 * it is possible to identify the disks.
784 */
785 if (BiosDiskEntry->Signature == Signature &&
786 BiosDiskEntry->Checksum == Checksum &&
787 !BiosDiskEntry->Recognized)
788 {
789 if (!DiskEntry->BiosFound)
790 {
791 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
792 DiskEntry->BiosFound = TRUE;
793 BiosDiskEntry->Recognized = TRUE;
794 }
795 else
796 {
797 }
798 }
799 ListEntry = ListEntry->Flink;
800 }
801
802 if (!DiskEntry->BiosFound)
803 {
804 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
805 return;
806 }
807
808 InitializeListHead (&DiskEntry->PartListHead);
809
810 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
811 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
812 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
813 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
814
815 DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
816 DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
817 DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
818 DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
819
820 DiskEntry->DiskSize =
821 DiskGeometry.Cylinders.QuadPart *
822 (ULONGLONG)DiskGeometry.TracksPerCylinder *
823 (ULONGLONG)DiskGeometry.SectorsPerTrack *
824 (ULONGLONG)DiskGeometry.BytesPerSector;
825 DiskEntry->CylinderSize =
826 (ULONGLONG)DiskGeometry.TracksPerCylinder *
827 (ULONGLONG)DiskGeometry.SectorsPerTrack *
828 (ULONGLONG)DiskGeometry.BytesPerSector;
829 DiskEntry->TrackSize =
830 (ULONGLONG)DiskGeometry.SectorsPerTrack *
831 (ULONGLONG)DiskGeometry.BytesPerSector;
832
833 DiskEntry->DiskNumber = DiskNumber;
834 DiskEntry->Port = ScsiAddress.PortNumber;
835 DiskEntry->Bus = ScsiAddress.PathId;
836 DiskEntry->Id = ScsiAddress.TargetId;
837
838 GetDriverName (DiskEntry);
839
840 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, BiosDiskNumber);
841
842 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
843 0,
844 8192);
845 if (LayoutBuffer == NULL)
846 {
847 return;
848 }
849
850 Status = NtDeviceIoControlFile (FileHandle,
851 NULL,
852 NULL,
853 NULL,
854 &Iosb,
855 IOCTL_DISK_GET_DRIVE_LAYOUT,
856 NULL,
857 0,
858 LayoutBuffer,
859 8192);
860 if (NT_SUCCESS (Status))
861 {
862 if (LayoutBuffer->PartitionCount == 0)
863 {
864 DiskEntry->NewDisk = TRUE;
865 }
866
867 AddPartitionToList (DiskNumber,
868 DiskEntry,
869 LayoutBuffer);
870
871 ScanForUnpartitionedDiskSpace (DiskEntry);
872 }
873
874 RtlFreeHeap (ProcessHeap,
875 0,
876 LayoutBuffer);
877 }
878
879
880 PPARTLIST
881 CreatePartitionList (SHORT Left,
882 SHORT Top,
883 SHORT Right,
884 SHORT Bottom)
885 {
886 PPARTLIST List;
887 OBJECT_ATTRIBUTES ObjectAttributes;
888 SYSTEM_DEVICE_INFORMATION Sdi;
889 IO_STATUS_BLOCK Iosb;
890 ULONG ReturnSize;
891 NTSTATUS Status;
892 ULONG DiskNumber;
893 WCHAR Buffer[MAX_PATH];
894 UNICODE_STRING Name;
895 HANDLE FileHandle;
896
897 List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
898 0,
899 sizeof (PARTLIST));
900 if (List == NULL)
901 return NULL;
902
903 List->Left = Left;
904 List->Top = Top;
905 List->Right = Right;
906 List->Bottom = Bottom;
907
908 List->Line = 0;
909
910 List->TopDisk = (ULONG)-1;
911 List->TopPartition = (ULONG)-1;
912
913 List->CurrentDisk = NULL;
914 List->CurrentPartition = NULL;
915
916 InitializeListHead (&List->DiskListHead);
917 InitializeListHead (&List->BiosDiskListHead);
918
919 EnumerateBiosDiskEntries(List);
920
921 Status = NtQuerySystemInformation (SystemDeviceInformation,
922 &Sdi,
923 sizeof(SYSTEM_DEVICE_INFORMATION),
924 &ReturnSize);
925 if (!NT_SUCCESS (Status))
926 {
927 RtlFreeHeap (ProcessHeap, 0, List);
928 return NULL;
929 }
930
931 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
932 {
933 swprintf (Buffer,
934 L"\\Device\\Harddisk%d\\Partition0",
935 DiskNumber);
936 RtlInitUnicodeString (&Name,
937 Buffer);
938
939 InitializeObjectAttributes (&ObjectAttributes,
940 &Name,
941 0,
942 NULL,
943 NULL);
944
945 Status = NtOpenFile (&FileHandle,
946 FILE_GENERIC_READ,
947 &ObjectAttributes,
948 &Iosb,
949 FILE_SHARE_READ,
950 FILE_SYNCHRONOUS_IO_NONALERT);
951 if (NT_SUCCESS(Status))
952 {
953 AddDiskToList (FileHandle,
954 DiskNumber,
955 List);
956
957 NtClose(FileHandle);
958 }
959 }
960
961 AssignDriverLetters (List);
962
963 List->TopDisk = 0;
964 List->TopPartition = 0;
965
966 /* Search for first usable disk and partition */
967 if (IsListEmpty (&List->DiskListHead))
968 {
969 List->CurrentDisk = NULL;
970 List->CurrentPartition = NULL;
971 }
972 else
973 {
974 List->CurrentDisk =
975 CONTAINING_RECORD (List->DiskListHead.Flink,
976 DISKENTRY,
977 ListEntry);
978
979 if (IsListEmpty (&List->CurrentDisk->PartListHead))
980 {
981 List->CurrentPartition = 0;
982 }
983 else
984 {
985 List->CurrentPartition =
986 CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
987 PARTENTRY,
988 ListEntry);
989 }
990 }
991
992 return List;
993 }
994
995
996 VOID
997 DestroyPartitionList (PPARTLIST List)
998 {
999 PDISKENTRY DiskEntry;
1000 PBIOSDISKENTRY BiosDiskEntry;
1001 PPARTENTRY PartEntry;
1002 PLIST_ENTRY Entry;
1003
1004 /* Release disk and partition info */
1005 while (!IsListEmpty (&List->DiskListHead))
1006 {
1007 Entry = RemoveHeadList (&List->DiskListHead);
1008 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1009
1010 /* Release driver name */
1011 RtlFreeUnicodeString(&DiskEntry->DriverName);
1012
1013 /* Release partition array */
1014 while (!IsListEmpty (&DiskEntry->PartListHead))
1015 {
1016 Entry = RemoveHeadList (&DiskEntry->PartListHead);
1017 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
1018
1019 RtlFreeHeap (ProcessHeap,
1020 0,
1021 PartEntry);
1022 }
1023
1024 /* Release disk entry */
1025 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
1026 }
1027
1028 /* release the bios disk info */
1029 while(!IsListEmpty(&List->BiosDiskListHead))
1030 {
1031 Entry = RemoveHeadList(&List->BiosDiskListHead);
1032 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1033
1034 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1035 }
1036
1037 /* Release list head */
1038 RtlFreeHeap (ProcessHeap, 0, List);
1039 }
1040
1041
1042 static VOID
1043 PrintEmptyLine (PPARTLIST List)
1044 {
1045 COORD coPos;
1046 ULONG Written;
1047 USHORT Width;
1048 USHORT Height;
1049
1050 Width = List->Right - List->Left - 1;
1051 Height = List->Bottom - List->Top - 2;
1052
1053
1054 coPos.X = List->Left + 1;
1055 coPos.Y = List->Top + 1 + List->Line;
1056
1057 if (List->Line >= 0 && List->Line <= Height)
1058 {
1059 FillConsoleOutputAttribute (StdOutput,
1060 FOREGROUND_WHITE | BACKGROUND_BLUE,
1061 Width,
1062 coPos,
1063 &Written);
1064
1065 FillConsoleOutputCharacterA (StdOutput,
1066 ' ',
1067 Width,
1068 coPos,
1069 &Written);
1070 }
1071 List->Line++;
1072 }
1073
1074
1075 static VOID
1076 PrintPartitionData (PPARTLIST List,
1077 PDISKENTRY DiskEntry,
1078 PPARTENTRY PartEntry)
1079 {
1080 CHAR LineBuffer[128];
1081 COORD coPos;
1082 ULONG Written;
1083 USHORT Width;
1084 USHORT Height;
1085
1086 ULONGLONG PartSize;
1087 PCHAR Unit;
1088 UCHAR Attribute;
1089 PCHAR PartType;
1090
1091 Width = List->Right - List->Left - 1;
1092 Height = List->Bottom - List->Top - 2;
1093
1094
1095 coPos.X = List->Left + 1;
1096 coPos.Y = List->Top + 1 + List->Line;
1097
1098 if (PartEntry->Unpartitioned == TRUE)
1099 {
1100 #if 0
1101 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
1102 {
1103 PartSize = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
1104 Unit = "GB";
1105 }
1106 else
1107 #endif
1108 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
1109 {
1110 PartSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
1111 Unit = "MB";
1112 }
1113 else
1114 {
1115 PartSize = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
1116 Unit = "KB";
1117 }
1118
1119 sprintf (LineBuffer,
1120 " Unpartitioned space %6I64u %s",
1121 PartSize,
1122 Unit);
1123 }
1124 else
1125 {
1126 /* Determine partition type */
1127 PartType = NULL;
1128 if (PartEntry->New == TRUE)
1129 {
1130 PartType = "New (Unformatted)";
1131 }
1132 else if (PartEntry->Unpartitioned == FALSE)
1133 {
1134 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
1135 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
1136 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
1137 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
1138 {
1139 PartType = "FAT";
1140 }
1141 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
1142 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
1143 {
1144 PartType = "FAT32";
1145 }
1146 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
1147 {
1148 PartType = "NTFS"; /* FIXME: Not quite correct! */
1149 }
1150 }
1151
1152 #if 0
1153 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
1154 {
1155 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
1156 Unit = "GB";
1157 }
1158 else
1159 #endif
1160 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
1161 {
1162 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
1163 Unit = "MB";
1164 }
1165 else
1166 {
1167 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
1168 Unit = "KB";
1169 }
1170
1171 if (PartType == NULL)
1172 {
1173 sprintf (LineBuffer,
1174 "%c%c Type %-3u %6I64u %s",
1175 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1176 (PartEntry->DriveLetter == 0) ? '-' : ':',
1177 PartEntry->PartInfo[0].PartitionType,
1178 PartSize,
1179 Unit);
1180 }
1181 else
1182 {
1183 sprintf (LineBuffer,
1184 "%c%c %-24s %6I64u %s",
1185 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1186 (PartEntry->DriveLetter == 0) ? '-' : ':',
1187 PartType,
1188 PartSize,
1189 Unit);
1190 }
1191 }
1192
1193 Attribute = (List->CurrentDisk == DiskEntry &&
1194 List->CurrentPartition == PartEntry) ?
1195 FOREGROUND_BLUE | BACKGROUND_WHITE :
1196 FOREGROUND_WHITE | BACKGROUND_BLUE;
1197
1198 if (List->Line >= 0 && List->Line <= Height)
1199 {
1200 FillConsoleOutputCharacterA (StdOutput,
1201 ' ',
1202 Width,
1203 coPos,
1204 &Written);
1205 }
1206 coPos.X += 4;
1207 Width -= 8;
1208 if (List->Line >= 0 && List->Line <= Height)
1209 {
1210 FillConsoleOutputAttribute (StdOutput,
1211 Attribute,
1212 Width,
1213 coPos,
1214 &Written);
1215 }
1216 coPos.X++;
1217 Width -= 2;
1218 if (List->Line >= 0 && List->Line <= Height)
1219 {
1220 WriteConsoleOutputCharacterA (StdOutput,
1221 LineBuffer,
1222 min (strlen (LineBuffer), Width),
1223 coPos,
1224 &Written);
1225 }
1226 List->Line++;
1227 }
1228
1229
1230 static VOID
1231 PrintDiskData (PPARTLIST List,
1232 PDISKENTRY DiskEntry)
1233 {
1234 PPARTENTRY PartEntry;
1235 CHAR LineBuffer[128];
1236 COORD coPos;
1237 ULONG Written;
1238 USHORT Width;
1239 USHORT Height;
1240 ULARGE_INTEGER DiskSize;
1241 PCHAR Unit;
1242
1243 Width = List->Right - List->Left - 1;
1244 Height = List->Bottom - List->Top - 2;
1245
1246
1247 coPos.X = List->Left + 1;
1248 coPos.Y = List->Top + 1 + List->Line;
1249
1250 #if 0
1251 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1252 {
1253 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1254 Unit = "GB";
1255 }
1256 else
1257 #endif
1258 {
1259 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1260 if (DiskSize.QuadPart == 0)
1261 DiskSize.QuadPart = 1;
1262 Unit = "MB";
1263 }
1264
1265 if (DiskEntry->DriverName.Length > 0)
1266 {
1267 sprintf (LineBuffer,
1268 "%6lu %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %S",
1269 DiskSize.u.LowPart,
1270 Unit,
1271 DiskEntry->DiskNumber,
1272 DiskEntry->Port,
1273 DiskEntry->Bus,
1274 DiskEntry->Id,
1275 DiskEntry->DriverName.Buffer);
1276 }
1277 else
1278 {
1279 sprintf (LineBuffer,
1280 "%6lu %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
1281 DiskSize.u.LowPart,
1282 Unit,
1283 DiskEntry->DiskNumber,
1284 DiskEntry->Port,
1285 DiskEntry->Bus,
1286 DiskEntry->Id);
1287 }
1288 if (List->Line >= 0 && List->Line <= Height)
1289 {
1290 FillConsoleOutputAttribute (StdOutput,
1291 FOREGROUND_WHITE | BACKGROUND_BLUE,
1292 Width,
1293 coPos,
1294 &Written);
1295
1296 FillConsoleOutputCharacterA (StdOutput,
1297 ' ',
1298 Width,
1299 coPos,
1300 &Written);
1301 }
1302
1303 coPos.X++;
1304 if (List->Line >= 0 && List->Line <= Height)
1305 {
1306 WriteConsoleOutputCharacterA (StdOutput,
1307 LineBuffer,
1308 min (strlen (LineBuffer), Width - 2),
1309 coPos,
1310 &Written);
1311 }
1312 List->Line++;
1313
1314 /* Print separator line */
1315 PrintEmptyLine (List);
1316
1317 /* Print partition lines*/
1318 LIST_FOR_EACH(PartEntry, &DiskEntry->PartListHead, PARTENTRY, ListEntry)
1319 {
1320 /* Print disk entry */
1321 PrintPartitionData (List,
1322 DiskEntry,
1323 PartEntry);
1324 }
1325
1326 /* Print separator line */
1327 PrintEmptyLine (List);
1328 }
1329
1330
1331 VOID
1332 DrawPartitionList (PPARTLIST List)
1333 {
1334 PLIST_ENTRY Entry, Entry2;
1335 PDISKENTRY DiskEntry;
1336 PPARTENTRY PartEntry = NULL;
1337 COORD coPos;
1338 ULONG Written;
1339 SHORT i;
1340 SHORT CurrentDiskLine;
1341 SHORT CurrentPartLine;
1342 SHORT LastLine;
1343 BOOL CurrentPartLineFound = FALSE;
1344 BOOL CurrentDiskLineFound = FALSE;
1345
1346 /* Calculate the line of the current disk and partition */
1347 CurrentDiskLine = 0;
1348 CurrentPartLine = 0;
1349 LastLine = 0;
1350 Entry = List->DiskListHead.Flink;
1351 while (Entry != &List->DiskListHead)
1352 {
1353 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1354 LastLine += 2;
1355 if (CurrentPartLineFound == FALSE)
1356 {
1357 CurrentPartLine += 2;
1358 }
1359 Entry2 = DiskEntry->PartListHead.Flink;
1360 while (Entry2 != &DiskEntry->PartListHead)
1361 {
1362 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1363 if (PartEntry == List->CurrentPartition)
1364 {
1365 CurrentPartLineFound = TRUE;
1366 }
1367 Entry2 = Entry2->Flink;
1368 if (CurrentPartLineFound == FALSE)
1369 {
1370 CurrentPartLine++;
1371 }
1372 LastLine++;
1373 }
1374 if (DiskEntry == List->CurrentDisk)
1375 {
1376 CurrentDiskLineFound = TRUE;
1377 }
1378 Entry = Entry->Flink;
1379 if (Entry != &List->DiskListHead)
1380 {
1381 if (CurrentDiskLineFound == FALSE)
1382 {
1383 CurrentPartLine ++;
1384 CurrentDiskLine = CurrentPartLine;
1385 }
1386 LastLine++;
1387 }
1388 else
1389 {
1390 LastLine--;
1391 }
1392 }
1393
1394 /* If it possible, make the disk name visible */
1395 if (CurrentPartLine < List->Offset)
1396 {
1397 List->Offset = CurrentPartLine;
1398 }
1399 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1400 {
1401 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1402 }
1403 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1404 {
1405 List->Offset = CurrentDiskLine;
1406 }
1407
1408
1409 /* draw upper left corner */
1410 coPos.X = List->Left;
1411 coPos.Y = List->Top;
1412 FillConsoleOutputCharacterA (StdOutput,
1413 0xDA, // '+',
1414 1,
1415 coPos,
1416 &Written);
1417
1418 /* draw upper edge */
1419 coPos.X = List->Left + 1;
1420 coPos.Y = List->Top;
1421 if (List->Offset == 0)
1422 {
1423 FillConsoleOutputCharacterA (StdOutput,
1424 0xC4, // '-',
1425 List->Right - List->Left - 1,
1426 coPos,
1427 &Written);
1428 }
1429 else
1430 {
1431 FillConsoleOutputCharacterA (StdOutput,
1432 0xC4, // '-',
1433 List->Right - List->Left - 5,
1434 coPos,
1435 &Written);
1436 coPos.X = List->Right - 5;
1437 WriteConsoleOutputCharacterA (StdOutput,
1438 "(\x18)", // "(up)"
1439 3,
1440 coPos,
1441 &Written);
1442 coPos.X = List->Right - 2;
1443 FillConsoleOutputCharacterA (StdOutput,
1444 0xC4, // '-',
1445 2,
1446 coPos,
1447 &Written);
1448 }
1449
1450 /* draw upper right corner */
1451 coPos.X = List->Right;
1452 coPos.Y = List->Top;
1453 FillConsoleOutputCharacterA (StdOutput,
1454 0xBF, // '+',
1455 1,
1456 coPos,
1457 &Written);
1458
1459 /* draw left and right edge */
1460 for (i = List->Top + 1; i < List->Bottom; i++)
1461 {
1462 coPos.X = List->Left;
1463 coPos.Y = i;
1464 FillConsoleOutputCharacterA (StdOutput,
1465 0xB3, // '|',
1466 1,
1467 coPos,
1468 &Written);
1469
1470 coPos.X = List->Right;
1471 FillConsoleOutputCharacterA (StdOutput,
1472 0xB3, //'|',
1473 1,
1474 coPos,
1475 &Written);
1476 }
1477
1478 /* draw lower left corner */
1479 coPos.X = List->Left;
1480 coPos.Y = List->Bottom;
1481 FillConsoleOutputCharacterA (StdOutput,
1482 0xC0, // '+',
1483 1,
1484 coPos,
1485 &Written);
1486
1487 /* draw lower edge */
1488 coPos.X = List->Left + 1;
1489 coPos.Y = List->Bottom;
1490 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1491 {
1492 FillConsoleOutputCharacterA (StdOutput,
1493 0xC4, // '-',
1494 List->Right - List->Left - 1,
1495 coPos,
1496 &Written);
1497 }
1498 else
1499 {
1500 FillConsoleOutputCharacterA (StdOutput,
1501 0xC4, // '-',
1502 List->Right - List->Left - 5,
1503 coPos,
1504 &Written);
1505 coPos.X = List->Right - 5;
1506 WriteConsoleOutputCharacterA (StdOutput,
1507 "(\x19)", // "(down)"
1508 3,
1509 coPos,
1510 &Written);
1511 coPos.X = List->Right - 2;
1512 FillConsoleOutputCharacterA (StdOutput,
1513 0xC4, // '-',
1514 2,
1515 coPos,
1516 &Written);
1517 }
1518
1519 /* draw lower right corner */
1520 coPos.X = List->Right;
1521 coPos.Y = List->Bottom;
1522 FillConsoleOutputCharacterA (StdOutput,
1523 0xD9, // '+',
1524 1,
1525 coPos,
1526 &Written);
1527
1528 /* print list entries */
1529 List->Line = - List->Offset;
1530
1531 LIST_FOR_EACH(DiskEntry, &List->DiskListHead, DISKENTRY, ListEntry)
1532 {
1533 /* Print disk entry */
1534 PrintDiskData (List,
1535 DiskEntry);
1536 }
1537 }
1538
1539
1540 VOID
1541 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1542 {
1543 PDISKENTRY DiskEntry;
1544 PPARTENTRY PartEntry;
1545 PLIST_ENTRY Entry1;
1546 PLIST_ENTRY Entry2;
1547 ULONG i;
1548
1549 /* Check for empty disks */
1550 if (IsListEmpty (&List->DiskListHead))
1551 return;
1552
1553 /* Check for first usable entry on next disk */
1554 Entry1 = List->CurrentDisk->ListEntry.Flink;
1555 while (Entry1 != &List->DiskListHead)
1556 {
1557 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1558
1559 if (DiskEntry->DiskNumber == DiskNumber)
1560 {
1561 Entry2 = DiskEntry->PartListHead.Flink;
1562 while (Entry2 != &DiskEntry->PartListHead)
1563 {
1564 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1565
1566 for (i = 0; i < 4; i++)
1567 {
1568 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1569 {
1570 List->CurrentDisk = DiskEntry;
1571 List->CurrentPartition = PartEntry;
1572 DrawPartitionList (List);
1573 return;
1574 }
1575 }
1576 Entry2 = Entry2->Flink;
1577 }
1578 return;
1579 }
1580 Entry1 = Entry1->Flink;
1581 }
1582 }
1583
1584
1585 VOID
1586 ScrollDownPartitionList (PPARTLIST List)
1587 {
1588 PDISKENTRY DiskEntry;
1589 PPARTENTRY PartEntry;
1590 PLIST_ENTRY Entry1;
1591 PLIST_ENTRY Entry2;
1592
1593 /* Check for empty disks */
1594 if (IsListEmpty (&List->DiskListHead))
1595 return;
1596
1597 /* Check for next usable entry on current disk */
1598 if (List->CurrentPartition != NULL)
1599 {
1600 Entry2 = List->CurrentPartition->ListEntry.Flink;
1601 while (Entry2 != &List->CurrentDisk->PartListHead)
1602 {
1603 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1604
1605 // if (PartEntry->HidePartEntry == FALSE)
1606 {
1607 List->CurrentPartition = PartEntry;
1608 DrawPartitionList (List);
1609 return;
1610 }
1611 Entry2 = Entry2->Flink;
1612 }
1613 }
1614
1615 /* Check for first usable entry on next disk */
1616 if (List->CurrentDisk != NULL)
1617 {
1618 Entry1 = List->CurrentDisk->ListEntry.Flink;
1619 while (Entry1 != &List->DiskListHead)
1620 {
1621 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1622
1623 Entry2 = DiskEntry->PartListHead.Flink;
1624 while (Entry2 != &DiskEntry->PartListHead)
1625 {
1626 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1627
1628 // if (PartEntry->HidePartEntry == FALSE)
1629 {
1630 List->CurrentDisk = DiskEntry;
1631 List->CurrentPartition = PartEntry;
1632 DrawPartitionList (List);
1633 return;
1634 }
1635
1636 Entry2 = Entry2->Flink;
1637 }
1638
1639 Entry1 = Entry1->Flink;
1640 }
1641 }
1642 }
1643
1644
1645 VOID
1646 ScrollUpPartitionList (PPARTLIST List)
1647 {
1648 PDISKENTRY DiskEntry;
1649 PPARTENTRY PartEntry;
1650 PLIST_ENTRY Entry1;
1651 PLIST_ENTRY Entry2;
1652
1653 /* Check for empty disks */
1654 if (IsListEmpty (&List->DiskListHead))
1655 return;
1656
1657 /* check for previous usable entry on current disk */
1658 if (List->CurrentPartition != NULL)
1659 {
1660 Entry2 = List->CurrentPartition->ListEntry.Blink;
1661 while (Entry2 != &List->CurrentDisk->PartListHead)
1662 {
1663 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1664
1665 // if (PartEntry->HidePartEntry == FALSE)
1666 {
1667 List->CurrentPartition = PartEntry;
1668 DrawPartitionList (List);
1669 return;
1670 }
1671 Entry2 = Entry2->Blink;
1672 }
1673 }
1674
1675
1676 /* check for last usable entry on previous disk */
1677 if (List->CurrentDisk != NULL)
1678 {
1679 Entry1 = List->CurrentDisk->ListEntry.Blink;
1680 while (Entry1 != &List->DiskListHead)
1681 {
1682 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1683
1684 Entry2 = DiskEntry->PartListHead.Blink;
1685 while (Entry2 != &DiskEntry->PartListHead)
1686 {
1687 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1688
1689 // if (PartEntry->HidePartEntry == FALSE)
1690 {
1691 List->CurrentDisk = DiskEntry;
1692 List->CurrentPartition = PartEntry;
1693 DrawPartitionList (List);
1694 return;
1695 }
1696
1697 Entry2 = Entry2->Blink;
1698 }
1699
1700 Entry1 = Entry1->Blink;
1701 }
1702 }
1703 }
1704
1705
1706 static PPARTENTRY
1707 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1708 PPARTENTRY CurrentEntry)
1709 {
1710 PPARTENTRY PrevEntry;
1711 PLIST_ENTRY Entry;
1712
1713 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1714 return NULL;
1715
1716 Entry = CurrentEntry->ListEntry.Blink;
1717 while (Entry != &DiskEntry->PartListHead)
1718 {
1719 PrevEntry = CONTAINING_RECORD (Entry,
1720 PARTENTRY,
1721 ListEntry);
1722 if (PrevEntry->Unpartitioned == FALSE)
1723 return PrevEntry;
1724
1725 Entry = Entry->Blink;
1726 }
1727
1728 return NULL;
1729 }
1730
1731
1732 static PPARTENTRY
1733 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1734 PPARTENTRY CurrentEntry)
1735 {
1736 PPARTENTRY NextEntry;
1737 PLIST_ENTRY Entry;
1738
1739 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1740 return NULL;
1741
1742 Entry = CurrentEntry->ListEntry.Flink;
1743 while (Entry != &DiskEntry->PartListHead)
1744 {
1745 NextEntry = CONTAINING_RECORD (Entry,
1746 PARTENTRY,
1747 ListEntry);
1748 if (NextEntry->Unpartitioned == FALSE)
1749 return NextEntry;
1750
1751 Entry = Entry->Flink;
1752 }
1753
1754 return NULL;
1755 }
1756
1757
1758 static PPARTENTRY
1759 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1760 PPARTENTRY PartEntry)
1761 {
1762 PPARTENTRY PrevPartEntry;
1763
1764 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1765 {
1766 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1767 PARTENTRY,
1768 ListEntry);
1769 if (PrevPartEntry->Unpartitioned == TRUE)
1770 return PrevPartEntry;
1771 }
1772
1773 return NULL;
1774 }
1775
1776
1777 static PPARTENTRY
1778 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1779 PPARTENTRY PartEntry)
1780 {
1781 PPARTENTRY NextPartEntry;
1782
1783 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1784 {
1785 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1786 PARTENTRY,
1787 ListEntry);
1788 if (NextPartEntry->Unpartitioned == TRUE)
1789 return NextPartEntry;
1790 }
1791
1792 return NULL;
1793 }
1794
1795
1796 VOID
1797 CreateNewPartition (PPARTLIST List,
1798 ULONGLONG PartitionSize,
1799 BOOLEAN AutoCreate)
1800 {
1801 PDISKENTRY DiskEntry;
1802 PPARTENTRY PartEntry;
1803 PPARTENTRY PrevPartEntry;
1804 PPARTENTRY NextPartEntry;
1805 PPARTENTRY NewPartEntry;
1806
1807 if (List == NULL ||
1808 List->CurrentDisk == NULL ||
1809 List->CurrentPartition == NULL ||
1810 List->CurrentPartition->Unpartitioned == FALSE)
1811 {
1812 return;
1813 }
1814
1815 DiskEntry = List->CurrentDisk;
1816 PartEntry = List->CurrentPartition;
1817
1818 if (AutoCreate == TRUE ||
1819 PartitionSize == PartEntry->UnpartitionedLength)
1820 {
1821 /* Convert current entry to 'new (unformatted)' */
1822 PartEntry->FormatState = Unformatted;
1823 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1824 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1825 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1826 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1827 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1828 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1829 PartEntry->PartInfo[0].RewritePartition = TRUE;
1830 PartEntry->PartInfo[1].RewritePartition = TRUE;
1831 PartEntry->PartInfo[2].RewritePartition = TRUE;
1832 PartEntry->PartInfo[3].RewritePartition = TRUE;
1833
1834 /* Get previous and next partition entries */
1835 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1836 PartEntry);
1837 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1838 PartEntry);
1839
1840 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1841 {
1842 /* Current entry is in the middle of the list */
1843
1844 /* Copy previous container partition data to current entry */
1845 RtlCopyMemory (&PartEntry->PartInfo[1],
1846 &PrevPartEntry->PartInfo[1],
1847 sizeof(PARTITION_INFORMATION));
1848 PartEntry->PartInfo[1].RewritePartition = TRUE;
1849
1850 /* Update previous container partition data */
1851
1852 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1853 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1854
1855 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1856 {
1857 /* Special case - previous partition is first partition */
1858 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1859 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1860 }
1861 else
1862 {
1863 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1864 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1865 }
1866
1867 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1868 }
1869 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1870 {
1871 /* Current entry is the first entry */
1872 return;
1873 }
1874 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1875 {
1876 /* Current entry is the last entry */
1877
1878 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1879 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1880
1881 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1882 {
1883 /* Special case - previous partition is first partition */
1884 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1885 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1886 }
1887 else
1888 {
1889 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1890 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1891 }
1892
1893 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1894 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1895 (1024LL * 255LL * 63LL * 512LL))
1896 {
1897 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1898 }
1899 else
1900 {
1901 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1902 }
1903
1904 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1905 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1906 }
1907
1908 PartEntry->AutoCreate = AutoCreate;
1909 PartEntry->New = TRUE;
1910 PartEntry->Unpartitioned = FALSE;
1911 PartEntry->UnpartitionedOffset = 0ULL;
1912 PartEntry->UnpartitionedLength = 0ULL;
1913 }
1914 else
1915 {
1916 /* Insert an initialize a new partition entry */
1917 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1918 0,
1919 sizeof(PARTENTRY));
1920 if (NewPartEntry == NULL)
1921 return;
1922
1923 RtlZeroMemory (NewPartEntry,
1924 sizeof(PARTENTRY));
1925
1926 /* Insert the new entry into the list */
1927 InsertTailList (&PartEntry->ListEntry,
1928 &NewPartEntry->ListEntry);
1929
1930 NewPartEntry->New = TRUE;
1931
1932 NewPartEntry->FormatState = Unformatted;
1933 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1934 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1935 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1936 PartitionSize - DiskEntry->TrackSize;
1937 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1938 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1939 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1940 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1941 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1942 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1943
1944 /* Get previous and next partition entries */
1945 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1946 NewPartEntry);
1947 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1948 NewPartEntry);
1949
1950 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1951 {
1952 /* Current entry is in the middle of the list */
1953
1954 /* Copy previous container partition data to current entry */
1955 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1956 &PrevPartEntry->PartInfo[1],
1957 sizeof(PARTITION_INFORMATION));
1958 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1959
1960 /* Update previous container partition data */
1961
1962 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1963 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1964
1965 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1966 {
1967 /* Special case - previous partition is first partition */
1968 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1969 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1970 }
1971 else
1972 {
1973 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1974 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1975 }
1976
1977 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1978 }
1979 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1980 {
1981 /* Current entry is the first entry */
1982 return;
1983 }
1984 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1985 {
1986 /* Current entry is the last entry */
1987
1988 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1989 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1990
1991 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1992 {
1993 /* Special case - previous partition is first partition */
1994 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1995 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1996 }
1997 else
1998 {
1999 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
2000 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
2001 }
2002
2003 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
2004 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
2005 (1024LL * 255LL * 63LL * 512LL))
2006 {
2007 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
2008 }
2009 else
2010 {
2011 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
2012 }
2013
2014 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
2015 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2016 }
2017
2018 /* Update offset and size of the remaining unpartitioned disk space */
2019 PartEntry->UnpartitionedOffset += PartitionSize;
2020 PartEntry->UnpartitionedLength -= PartitionSize;
2021 }
2022
2023 DiskEntry->Modified = TRUE;
2024
2025 UpdatePartitionNumbers (DiskEntry);
2026
2027 AssignDriverLetters (List);
2028 }
2029
2030
2031 VOID
2032 DeleteCurrentPartition (PPARTLIST List)
2033 {
2034 PDISKENTRY DiskEntry;
2035 PPARTENTRY PartEntry;
2036 PPARTENTRY PrevPartEntry;
2037 PPARTENTRY NextPartEntry;
2038
2039 if (List == NULL ||
2040 List->CurrentDisk == NULL ||
2041 List->CurrentPartition == NULL ||
2042 List->CurrentPartition->Unpartitioned == TRUE)
2043 {
2044 return;
2045 }
2046
2047 DiskEntry = List->CurrentDisk;
2048 PartEntry = List->CurrentPartition;
2049
2050 /* Adjust container partition entries */
2051
2052 /* Get previous and next partition entries */
2053 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
2054 PartEntry);
2055 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
2056 PartEntry);
2057
2058 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2059 {
2060 /* Current entry is in the middle of the list */
2061
2062 /*
2063 * The first extended partition can not be deleted
2064 * as long as other extended partitions are present.
2065 */
2066 if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
2067 return;
2068
2069 /* Copy previous container partition data to current entry */
2070 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
2071 &PartEntry->PartInfo[1],
2072 sizeof(PARTITION_INFORMATION));
2073 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2074 }
2075 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2076 {
2077 /*
2078 * A primary partition can not be deleted as long as
2079 * extended partitions are present.
2080 */
2081 return;
2082 }
2083 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2084 {
2085 /* Current entry is the last entry */
2086 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
2087 sizeof(PARTITION_INFORMATION));
2088 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2089 }
2090
2091
2092 /* Adjust unpartitioned disk space entries */
2093
2094 /* Get pointer to previous and next unpartitioned entries */
2095 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
2096 PartEntry);
2097
2098 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
2099 PartEntry);
2100
2101 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2102 {
2103 /* Merge previous, current and next unpartitioned entry */
2104
2105 /* Adjust the previous entries length */
2106 PrevPartEntry->UnpartitionedLength +=
2107 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
2108 NextPartEntry->UnpartitionedLength);
2109
2110 /* Remove the current entry */
2111 RemoveEntryList (&PartEntry->ListEntry);
2112 RtlFreeHeap (ProcessHeap,
2113 0,
2114 PartEntry);
2115
2116 /* Remove the next entry */
2117 RemoveEntryList (&NextPartEntry->ListEntry);
2118 RtlFreeHeap (ProcessHeap,
2119 0,
2120 NextPartEntry);
2121
2122 /* Update current partition */
2123 List->CurrentPartition = PrevPartEntry;
2124 }
2125 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2126 {
2127 /* Merge current and previous unpartitioned entry */
2128
2129 /* Adjust the previous entries length */
2130 PrevPartEntry->UnpartitionedLength +=
2131 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
2132
2133 /* Remove the current entry */
2134 RemoveEntryList (&PartEntry->ListEntry);
2135 RtlFreeHeap (ProcessHeap,
2136 0,
2137 PartEntry);
2138
2139 /* Update current partition */
2140 List->CurrentPartition = PrevPartEntry;
2141 }
2142 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2143 {
2144 /* Merge current and next unpartitioned entry */
2145
2146 /* Adjust the next entries offset and length */
2147 NextPartEntry->UnpartitionedOffset =
2148 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
2149 NextPartEntry->UnpartitionedLength +=
2150 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
2151
2152 /* Remove the current entry */
2153 RemoveEntryList (&PartEntry->ListEntry);
2154 RtlFreeHeap (ProcessHeap,
2155 0,
2156 PartEntry);
2157
2158 /* Update current partition */
2159 List->CurrentPartition = NextPartEntry;
2160 }
2161 else
2162 {
2163 /* Nothing to merge but change current entry */
2164 PartEntry->New = FALSE;
2165 PartEntry->Unpartitioned = TRUE;
2166 PartEntry->UnpartitionedOffset =
2167 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
2168 PartEntry->UnpartitionedLength =
2169 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
2170
2171 /* Wipe the partition table */
2172 RtlZeroMemory (&PartEntry->PartInfo,
2173 sizeof(PartEntry->PartInfo));
2174 }
2175
2176 DiskEntry->Modified = TRUE;
2177
2178 UpdatePartitionNumbers (DiskEntry);
2179
2180 AssignDriverLetters (List);
2181 }
2182
2183
2184 VOID
2185 CheckActiveBootPartition (PPARTLIST List)
2186 {
2187 PDISKENTRY DiskEntry;
2188 PPARTENTRY PartEntry;
2189
2190 /* Check for empty disk list */
2191 if (IsListEmpty (&List->DiskListHead))
2192 {
2193 List->ActiveBootDisk = NULL;
2194 List->ActiveBootPartition = NULL;
2195 return;
2196 }
2197
2198 #if 0
2199 if (List->ActiveBootDisk != NULL &&
2200 List->ActiveBootPartition != NULL)
2201 {
2202 /* We already have an active boot partition */
2203 return;
2204 }
2205 #endif
2206
2207 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
2208 DISKENTRY,
2209 ListEntry);
2210
2211 /* Check for empty partition list */
2212 if (IsListEmpty (&DiskEntry->PartListHead))
2213 {
2214 List->ActiveBootDisk = NULL;
2215 List->ActiveBootPartition = NULL;
2216 return;
2217 }
2218
2219 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
2220 PARTENTRY,
2221 ListEntry);
2222
2223 /* Set active boot partition */
2224 if ((DiskEntry->NewDisk == TRUE) ||
2225 (PartEntry->PartInfo[0].BootIndicator == FALSE &&
2226 PartEntry->PartInfo[1].BootIndicator == FALSE &&
2227 PartEntry->PartInfo[2].BootIndicator == FALSE &&
2228 PartEntry->PartInfo[3].BootIndicator == FALSE))
2229 {
2230 PartEntry->PartInfo[0].BootIndicator = TRUE;
2231 PartEntry->PartInfo[0].RewritePartition = TRUE;
2232 DiskEntry->Modified = TRUE;
2233 }
2234
2235 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2236 List->ActiveBootDisk = DiskEntry;
2237 List->ActiveBootPartition = PartEntry;
2238 }
2239
2240
2241 BOOLEAN
2242 CheckForLinuxFdiskPartitions (PPARTLIST List)
2243 {
2244 PDISKENTRY DiskEntry;
2245 PPARTENTRY PartEntry;
2246 PLIST_ENTRY Entry1;
2247 PLIST_ENTRY Entry2;
2248 ULONG PartitionCount;
2249 ULONG i;
2250
2251 Entry1 = List->DiskListHead.Flink;
2252 while (Entry1 != &List->DiskListHead)
2253 {
2254 DiskEntry = CONTAINING_RECORD (Entry1,
2255 DISKENTRY,
2256 ListEntry);
2257
2258 Entry2 = DiskEntry->PartListHead.Flink;
2259 while (Entry2 != &DiskEntry->PartListHead)
2260 {
2261 PartEntry = CONTAINING_RECORD (Entry2,
2262 PARTENTRY,
2263 ListEntry);
2264
2265 if (PartEntry->Unpartitioned == FALSE)
2266 {
2267 PartitionCount = 0;
2268
2269 for (i = 0; i < 4; i++)
2270 {
2271 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
2272 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2273 {
2274 PartitionCount++;
2275 }
2276 }
2277
2278 if (PartitionCount > 1)
2279 {
2280 return TRUE;
2281 }
2282 }
2283
2284 Entry2 = Entry2->Flink;
2285 }
2286
2287 Entry1 = Entry1->Flink;
2288 }
2289
2290 return FALSE;
2291 }
2292
2293
2294 BOOLEAN
2295 WritePartitionsToDisk (PPARTLIST List)
2296 {
2297 PDRIVE_LAYOUT_INFORMATION DriveLayout;
2298 OBJECT_ATTRIBUTES ObjectAttributes;
2299 IO_STATUS_BLOCK Iosb;
2300 WCHAR SrcPath[MAX_PATH];
2301 WCHAR DstPath[MAX_PATH];
2302 UNICODE_STRING Name;
2303 HANDLE FileHandle;
2304 PDISKENTRY DiskEntry1;
2305 PDISKENTRY DiskEntry2;
2306 PPARTENTRY PartEntry;
2307 PLIST_ENTRY Entry1;
2308 PLIST_ENTRY Entry2;
2309 ULONG PartitionCount;
2310 ULONG DriveLayoutSize;
2311 ULONG Index;
2312 NTSTATUS Status;
2313
2314 if (List == NULL)
2315 {
2316 return TRUE;
2317 }
2318
2319 Entry1 = List->DiskListHead.Flink;
2320 while (Entry1 != &List->DiskListHead)
2321 {
2322 DiskEntry1 = CONTAINING_RECORD (Entry1,
2323 DISKENTRY,
2324 ListEntry);
2325
2326 if (DiskEntry1->Modified == TRUE)
2327 {
2328 /* Count partitioned entries */
2329 PartitionCount = 0;
2330 Entry2 = DiskEntry1->PartListHead.Flink;
2331 while (Entry2 != &DiskEntry1->PartListHead)
2332 {
2333 PartEntry = CONTAINING_RECORD (Entry2,
2334 PARTENTRY,
2335 ListEntry);
2336 if (PartEntry->Unpartitioned == FALSE)
2337 {
2338 PartitionCount += 4;
2339 }
2340
2341 Entry2 = Entry2->Flink;
2342 }
2343 if (PartitionCount == 0)
2344 {
2345 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
2346 ((4 - 1) * sizeof (PARTITION_INFORMATION));
2347 }
2348 else
2349 {
2350 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
2351 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
2352 }
2353 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
2354 0,
2355 DriveLayoutSize);
2356 if (DriveLayout == NULL)
2357 {
2358 DPRINT1 ("RtlAllocateHeap() failed\n");
2359 return FALSE;
2360 }
2361
2362 RtlZeroMemory (DriveLayout,
2363 DriveLayoutSize);
2364
2365 if (PartitionCount == 0)
2366 {
2367 /* delete all partitions in the mbr */
2368 DriveLayout->PartitionCount = 4;
2369 for (Index = 0; Index < 4; Index++)
2370 {
2371 DriveLayout->PartitionEntry[Index].RewritePartition = TRUE;
2372 }
2373 }
2374 else
2375 {
2376 DriveLayout->PartitionCount = PartitionCount;
2377
2378 Index = 0;
2379 Entry2 = DiskEntry1->PartListHead.Flink;
2380 while (Entry2 != &DiskEntry1->PartListHead)
2381 {
2382 PartEntry = CONTAINING_RECORD (Entry2,
2383 PARTENTRY,
2384 ListEntry);
2385 if (PartEntry->Unpartitioned == FALSE)
2386 {
2387 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
2388 &PartEntry->PartInfo[0],
2389 4 * sizeof (PARTITION_INFORMATION));
2390 Index += 4;
2391 }
2392
2393 Entry2 = Entry2->Flink;
2394 }
2395 }
2396 if (DiskEntry1->Signature == 0)
2397 {
2398 LARGE_INTEGER SystemTime;
2399 TIME_FIELDS TimeFields;
2400 PUCHAR Buffer;
2401 Buffer = (PUCHAR)&DiskEntry1->Signature;
2402
2403 while (1)
2404 {
2405 NtQuerySystemTime (&SystemTime);
2406 RtlTimeToTimeFields (&SystemTime, &TimeFields);
2407
2408 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
2409 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
2410 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
2411 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
2412
2413 if (DiskEntry1->Signature == 0)
2414 {
2415 continue;
2416 }
2417
2418 /* check if the signature already exist */
2419 /* FIXME:
2420 * Check also signatures from disks, which are
2421 * not visible (bootable) by the bios.
2422 */
2423 Entry2 = List->DiskListHead.Flink;
2424 while (Entry2 != &List->DiskListHead)
2425 {
2426 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
2427 if (DiskEntry1 != DiskEntry2 &&
2428 DiskEntry1->Signature == DiskEntry2->Signature)
2429 {
2430 break;
2431 }
2432 Entry2 = Entry2->Flink;
2433 }
2434 if (Entry2 == &List->DiskListHead)
2435 {
2436 break;
2437 }
2438 }
2439
2440 /* set one partition entry to dirty, this will update the signature */
2441 DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
2442
2443 }
2444
2445 DriveLayout->Signature = DiskEntry1->Signature;
2446
2447
2448 swprintf (DstPath,
2449 L"\\Device\\Harddisk%d\\Partition0",
2450 DiskEntry1->DiskNumber);
2451 RtlInitUnicodeString (&Name,
2452 DstPath);
2453 InitializeObjectAttributes (&ObjectAttributes,
2454 &Name,
2455 0,
2456 NULL,
2457 NULL);
2458
2459 Status = NtOpenFile (&FileHandle,
2460 FILE_ALL_ACCESS,
2461 &ObjectAttributes,
2462 &Iosb,
2463 0,
2464 FILE_SYNCHRONOUS_IO_NONALERT);
2465
2466 if (!NT_SUCCESS (Status))
2467 {
2468 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
2469 return FALSE;
2470 }
2471
2472 Status = NtDeviceIoControlFile (FileHandle,
2473 NULL,
2474 NULL,
2475 NULL,
2476 &Iosb,
2477 IOCTL_DISK_SET_DRIVE_LAYOUT,
2478 DriveLayout,
2479 DriveLayoutSize,
2480 NULL,
2481 0);
2482 if (!NT_SUCCESS (Status))
2483 {
2484 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
2485 NtClose (FileHandle);
2486 return FALSE;
2487 }
2488
2489 RtlFreeHeap (ProcessHeap,
2490 0,
2491 DriveLayout);
2492
2493 NtClose (FileHandle);
2494
2495 /* Install MBR code if the disk is new */
2496 if (DiskEntry1->NewDisk == TRUE &&
2497 DiskEntry1->BiosDiskNumber == 0)
2498 {
2499 wcscpy (SrcPath, SourceRootPath.Buffer);
2500 wcscat (SrcPath, L"\\loader\\dosmbr.bin");
2501
2502 DPRINT ("Install MBR bootcode: %S ==> %S\n",
2503 SrcPath, DstPath);
2504
2505 /* Install MBR bootcode */
2506 Status = InstallMbrBootCodeToDisk (SrcPath,
2507 DstPath);
2508 if (!NT_SUCCESS (Status))
2509 {
2510 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
2511 Status);
2512 return FALSE;
2513 }
2514
2515 DiskEntry1->NewDisk = FALSE;
2516 }
2517 }
2518
2519 Entry1 = Entry1->Flink;
2520 }
2521
2522 return TRUE;
2523 }
2524
2525 BOOL SetMountedDeviceValues(PPARTLIST List)
2526 {
2527 PLIST_ENTRY Entry1, Entry2;
2528 PDISKENTRY DiskEntry;
2529 PPARTENTRY PartEntry;
2530
2531 if (List == NULL)
2532 {
2533 return FALSE;
2534 }
2535
2536 Entry1 = List->DiskListHead.Flink;
2537 while (Entry1 != &List->DiskListHead)
2538 {
2539 DiskEntry = CONTAINING_RECORD (Entry1,
2540 DISKENTRY,
2541 ListEntry);
2542
2543 Entry2 = DiskEntry->PartListHead.Flink;
2544 while (Entry2 != &DiskEntry->PartListHead)
2545 {
2546 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2547 if (!PartEntry->Unpartitioned && PartEntry->DriveLetter)
2548 {
2549 if (!SetMountedDeviceValue(PartEntry->DriveLetter, DiskEntry->Signature, PartEntry->PartInfo[0].StartingOffset))
2550 {
2551 return FALSE;
2552 }
2553 }
2554 Entry2 = Entry2->Flink;
2555 }
2556 Entry1 = Entry1->Flink;
2557 }
2558 return TRUE;
2559 }
2560
2561
2562
2563 /* EOF */