352f1237fe436a96be4e63b016ac5bf783ae686e
[reactos.git] / reactos / subsys / system / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003 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
425 static VOID
426 AddDiskToList (HANDLE FileHandle,
427 ULONG DiskNumber,
428 PPARTLIST List)
429 {
430 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
431 DISK_GEOMETRY DiskGeometry;
432 SCSI_ADDRESS ScsiAddress;
433 PDISKENTRY DiskEntry;
434 IO_STATUS_BLOCK Iosb;
435 NTSTATUS Status;
436
437 Status = NtDeviceIoControlFile (FileHandle,
438 NULL,
439 NULL,
440 NULL,
441 &Iosb,
442 IOCTL_DISK_GET_DRIVE_GEOMETRY,
443 NULL,
444 0,
445 &DiskGeometry,
446 sizeof(DISK_GEOMETRY));
447 if (!NT_SUCCESS (Status))
448 {
449 return;
450 }
451
452 if (DiskGeometry.MediaType != FixedMedia)
453 {
454 return;
455 }
456
457 Status = NtDeviceIoControlFile (FileHandle,
458 NULL,
459 NULL,
460 NULL,
461 &Iosb,
462 IOCTL_SCSI_GET_ADDRESS,
463 NULL,
464 0,
465 &ScsiAddress,
466 sizeof(SCSI_ADDRESS));
467 if (!NT_SUCCESS(Status))
468 {
469 return;
470 }
471
472 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
473 0,
474 sizeof(DISKENTRY));
475 if (DiskEntry == NULL)
476 {
477 return;
478 }
479
480 InitializeListHead (&DiskEntry->PartListHead);
481
482 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
483 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
484 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
485 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
486
487 DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
488 DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
489 DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
490 DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
491
492 DiskEntry->DiskSize =
493 DiskGeometry.Cylinders.QuadPart *
494 (ULONGLONG)DiskGeometry.TracksPerCylinder *
495 (ULONGLONG)DiskGeometry.SectorsPerTrack *
496 (ULONGLONG)DiskGeometry.BytesPerSector;
497 DiskEntry->CylinderSize =
498 (ULONGLONG)DiskGeometry.TracksPerCylinder *
499 (ULONGLONG)DiskGeometry.SectorsPerTrack *
500 (ULONGLONG)DiskGeometry.BytesPerSector;
501 DiskEntry->TrackSize =
502 (ULONGLONG)DiskGeometry.SectorsPerTrack *
503 (ULONGLONG)DiskGeometry.BytesPerSector;
504
505 DiskEntry->DiskNumber = DiskNumber;
506 DiskEntry->Port = ScsiAddress.PortNumber;
507 DiskEntry->Bus = ScsiAddress.PathId;
508 DiskEntry->Id = ScsiAddress.TargetId;
509
510 GetDriverName (DiskEntry);
511
512 InsertTailList (&List->DiskListHead,
513 &DiskEntry->ListEntry);
514
515 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
516 0,
517 8192);
518 if (LayoutBuffer == NULL)
519 {
520 return;
521 }
522
523 Status = NtDeviceIoControlFile (FileHandle,
524 NULL,
525 NULL,
526 NULL,
527 &Iosb,
528 IOCTL_DISK_GET_DRIVE_LAYOUT,
529 NULL,
530 0,
531 LayoutBuffer,
532 8192);
533 if (NT_SUCCESS (Status))
534 {
535 if (LayoutBuffer->PartitionCount == 0)
536 {
537 DiskEntry->NewDisk = TRUE;
538 }
539
540 AddPartitionToList (DiskNumber,
541 DiskEntry,
542 LayoutBuffer);
543
544 ScanForUnpartitionedDiskSpace (DiskEntry);
545 }
546
547 RtlFreeHeap (ProcessHeap,
548 0,
549 LayoutBuffer);
550 }
551
552
553 PPARTLIST
554 CreatePartitionList (SHORT Left,
555 SHORT Top,
556 SHORT Right,
557 SHORT Bottom)
558 {
559 PPARTLIST List;
560 OBJECT_ATTRIBUTES ObjectAttributes;
561 SYSTEM_DEVICE_INFORMATION Sdi;
562 IO_STATUS_BLOCK Iosb;
563 ULONG ReturnSize;
564 NTSTATUS Status;
565 ULONG DiskNumber;
566 WCHAR Buffer[MAX_PATH];
567 UNICODE_STRING Name;
568 HANDLE FileHandle;
569
570 List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
571 0,
572 sizeof (PARTLIST));
573 if (List == NULL)
574 return NULL;
575
576 List->Left = Left;
577 List->Top = Top;
578 List->Right = Right;
579 List->Bottom = Bottom;
580
581 List->Line = 0;
582
583 List->TopDisk = (ULONG)-1;
584 List->TopPartition = (ULONG)-1;
585
586 List->CurrentDisk = NULL;
587 List->CurrentPartition = NULL;
588
589 InitializeListHead (&List->DiskListHead);
590
591 Status = NtQuerySystemInformation (SystemDeviceInformation,
592 &Sdi,
593 sizeof(SYSTEM_DEVICE_INFORMATION),
594 &ReturnSize);
595 if (!NT_SUCCESS (Status))
596 {
597 RtlFreeHeap (ProcessHeap, 0, List);
598 return NULL;
599 }
600
601 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
602 {
603 swprintf (Buffer,
604 L"\\Device\\Harddisk%d\\Partition0",
605 DiskNumber);
606 RtlInitUnicodeString (&Name,
607 Buffer);
608
609 InitializeObjectAttributes (&ObjectAttributes,
610 &Name,
611 0,
612 NULL,
613 NULL);
614
615 Status = NtOpenFile (&FileHandle,
616 FILE_GENERIC_READ,
617 &ObjectAttributes,
618 &Iosb,
619 FILE_SHARE_READ,
620 FILE_SYNCHRONOUS_IO_NONALERT);
621 if (NT_SUCCESS(Status))
622 {
623 AddDiskToList (FileHandle,
624 DiskNumber,
625 List);
626
627 NtClose(FileHandle);
628 }
629 }
630
631 AssignDriverLetters (List);
632
633 List->TopDisk = 0;
634 List->TopPartition = 0;
635
636 /* Search for first usable disk and partition */
637 if (IsListEmpty (&List->DiskListHead))
638 {
639 List->CurrentDisk = NULL;
640 List->CurrentPartition = NULL;
641 }
642 else
643 {
644 List->CurrentDisk =
645 CONTAINING_RECORD (List->DiskListHead.Flink,
646 DISKENTRY,
647 ListEntry);
648
649 if (IsListEmpty (&List->CurrentDisk->PartListHead))
650 {
651 List->CurrentPartition = 0;
652 }
653 else
654 {
655 List->CurrentPartition =
656 CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
657 PARTENTRY,
658 ListEntry);
659 }
660 }
661
662 return List;
663 }
664
665
666 VOID
667 DestroyPartitionList (PPARTLIST List)
668 {
669 PDISKENTRY DiskEntry;
670 PPARTENTRY PartEntry;
671 PLIST_ENTRY Entry;
672
673 /* Release disk and partition info */
674 while (!IsListEmpty (&List->DiskListHead))
675 {
676 Entry = RemoveHeadList (&List->DiskListHead);
677 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
678
679 /* Release driver name */
680 RtlFreeUnicodeString(&DiskEntry->DriverName);
681
682 /* Release partition array */
683 while (!IsListEmpty (&DiskEntry->PartListHead))
684 {
685 Entry = RemoveHeadList (&DiskEntry->PartListHead);
686 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
687
688 RtlFreeHeap (ProcessHeap,
689 0,
690 PartEntry);
691 }
692
693 /* Release disk entry */
694 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
695 }
696
697 /* Release list head */
698 RtlFreeHeap (ProcessHeap, 0, List);
699 }
700
701
702 static VOID
703 PrintEmptyLine (PPARTLIST List)
704 {
705 COORD coPos;
706 ULONG Written;
707 USHORT Width;
708 USHORT Height;
709
710 Width = List->Right - List->Left - 1;
711 Height = List->Bottom - List->Top - 2;
712
713
714 coPos.X = List->Left + 1;
715 coPos.Y = List->Top + 1 + List->Line;
716
717 if (List->Line >= 0 && List->Line <= Height)
718 {
719 FillConsoleOutputAttribute (0x17,
720 Width,
721 coPos,
722 &Written);
723
724 FillConsoleOutputCharacter (' ',
725 Width,
726 coPos,
727 &Written);
728 }
729 List->Line++;
730 }
731
732
733 static VOID
734 PrintPartitionData (PPARTLIST List,
735 PDISKENTRY DiskEntry,
736 PPARTENTRY PartEntry)
737 {
738 CHAR LineBuffer[128];
739 COORD coPos;
740 ULONG Written;
741 USHORT Width;
742 USHORT Height;
743
744 ULONGLONG PartSize;
745 PCHAR Unit;
746 UCHAR Attribute;
747 PCHAR PartType;
748
749 Width = List->Right - List->Left - 1;
750 Height = List->Bottom - List->Top - 2;
751
752
753 coPos.X = List->Left + 1;
754 coPos.Y = List->Top + 1 + List->Line;
755
756 if (PartEntry->Unpartitioned == TRUE)
757 {
758 #if 0
759 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
760 {
761 PartSize = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
762 Unit = "GB";
763 }
764 else
765 #endif
766 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
767 {
768 PartSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
769 Unit = "MB";
770 }
771 else
772 {
773 PartSize = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
774 Unit = "KB";
775 }
776
777 sprintf (LineBuffer,
778 " Unpartitioned space %6I64u %s",
779 PartSize,
780 Unit);
781 }
782 else
783 {
784 /* Determine partition type */
785 PartType = NULL;
786 if (PartEntry->New == TRUE)
787 {
788 PartType = "New (Unformatted)";
789 }
790 else if (PartEntry->Unpartitioned == FALSE)
791 {
792 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
793 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
794 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
795 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
796 {
797 PartType = "FAT";
798 }
799 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
800 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
801 {
802 PartType = "FAT32";
803 }
804 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
805 {
806 PartType = "NTFS"; /* FIXME: Not quite correct! */
807 }
808 }
809
810 #if 0
811 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
812 {
813 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
814 Unit = "GB";
815 }
816 else
817 #endif
818 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
819 {
820 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
821 Unit = "MB";
822 }
823 else
824 {
825 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
826 Unit = "KB";
827 }
828
829 if (PartType == NULL)
830 {
831 sprintf (LineBuffer,
832 "%c%c Type %-3u %6I64u %s",
833 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
834 (PartEntry->DriveLetter == 0) ? '-' : ':',
835 PartEntry->PartInfo[0].PartitionType,
836 PartSize,
837 Unit);
838 }
839 else
840 {
841 sprintf (LineBuffer,
842 "%c%c %-24s %6I64u %s",
843 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
844 (PartEntry->DriveLetter == 0) ? '-' : ':',
845 PartType,
846 PartSize,
847 Unit);
848 }
849 }
850
851 Attribute = (List->CurrentDisk == DiskEntry &&
852 List->CurrentPartition == PartEntry) ? 0x71 : 0x17;
853
854 if (List->Line >= 0 && List->Line <= Height)
855 {
856 FillConsoleOutputCharacter (' ',
857 Width,
858 coPos,
859 &Written);
860 }
861 coPos.X += 4;
862 Width -= 8;
863 if (List->Line >= 0 && List->Line <= Height)
864 {
865 FillConsoleOutputAttribute (Attribute,
866 Width,
867 coPos,
868 &Written);
869 }
870 coPos.X++;
871 Width -= 2;
872 if (List->Line >= 0 && List->Line <= Height)
873 {
874 WriteConsoleOutputCharacters (LineBuffer,
875 min (strlen (LineBuffer), Width),
876 coPos);
877 }
878 List->Line++;
879 }
880
881
882 static VOID
883 PrintDiskData (PPARTLIST List,
884 PDISKENTRY DiskEntry)
885 {
886 PPARTENTRY PartEntry;
887 PLIST_ENTRY Entry;
888 CHAR LineBuffer[128];
889 COORD coPos;
890 ULONG Written;
891 USHORT Width;
892 USHORT Height;
893 ULONGLONG DiskSize;
894 PCHAR Unit;
895
896 Width = List->Right - List->Left - 1;
897 Height = List->Bottom - List->Top - 2;
898
899
900 coPos.X = List->Left + 1;
901 coPos.Y = List->Top + 1 + List->Line;
902
903 #if 0
904 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
905 {
906 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
907 Unit = "GB";
908 }
909 else
910 #endif
911 {
912 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
913 if (DiskSize == 0)
914 DiskSize = 1;
915 Unit = "MB";
916 }
917
918 if (DiskEntry->DriverName.Length > 0)
919 {
920 sprintf (LineBuffer,
921 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
922 DiskSize,
923 Unit,
924 DiskEntry->DiskNumber,
925 DiskEntry->Port,
926 DiskEntry->Bus,
927 DiskEntry->Id,
928 &DiskEntry->DriverName);
929 }
930 else
931 {
932 sprintf (LineBuffer,
933 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
934 DiskSize,
935 Unit,
936 DiskEntry->DiskNumber,
937 DiskEntry->Port,
938 DiskEntry->Bus,
939 DiskEntry->Id);
940 }
941 if (List->Line >= 0 && List->Line <= Height)
942 {
943 FillConsoleOutputAttribute (0x17,
944 Width,
945 coPos,
946 &Written);
947
948 FillConsoleOutputCharacter (' ',
949 Width,
950 coPos,
951 &Written);
952 }
953
954 coPos.X++;
955 if (List->Line >= 0 && List->Line <= Height)
956 {
957 WriteConsoleOutputCharacters (LineBuffer,
958 min (strlen (LineBuffer), Width - 2),
959 coPos);
960 }
961 List->Line++;
962
963 /* Print separator line */
964 PrintEmptyLine (List);
965
966 /* Print partition lines*/
967 Entry = DiskEntry->PartListHead.Flink;
968 while (Entry != &DiskEntry->PartListHead)
969 {
970 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
971
972 /* Print disk entry */
973 PrintPartitionData (List,
974 DiskEntry,
975 PartEntry);
976
977 Entry = Entry->Flink;
978 }
979
980 /* Print separator line */
981 PrintEmptyLine (List);
982 }
983
984
985 VOID
986 DrawPartitionList (PPARTLIST List)
987 {
988 PLIST_ENTRY Entry, Entry2;
989 PDISKENTRY DiskEntry;
990 PPARTENTRY PartEntry = NULL;
991 COORD coPos;
992 ULONG Written;
993 SHORT i;
994 SHORT CurrentDiskLine;
995 SHORT CurrentPartLine;
996 SHORT LastLine;
997 BOOL CurrentPartLineFound = FALSE;
998 BOOL CurrentDiskLineFound = FALSE;
999
1000 /* Calculate the line of the current disk and partition */
1001 CurrentDiskLine = 0;
1002 CurrentPartLine = 0;
1003 LastLine = 0;
1004 Entry = List->DiskListHead.Flink;
1005 while (Entry != &List->DiskListHead)
1006 {
1007 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1008 LastLine += 2;
1009 if (CurrentPartLineFound == FALSE)
1010 {
1011 CurrentPartLine += 2;
1012 }
1013 Entry2 = DiskEntry->PartListHead.Flink;
1014 while (Entry2 != &DiskEntry->PartListHead)
1015 {
1016 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1017 if (PartEntry == List->CurrentPartition)
1018 {
1019 CurrentPartLineFound = TRUE;
1020 }
1021 Entry2 = Entry2->Flink;
1022 if (CurrentPartLineFound == FALSE)
1023 {
1024 CurrentPartLine++;
1025 }
1026 LastLine++;
1027 }
1028 if (DiskEntry == List->CurrentDisk)
1029 {
1030 CurrentDiskLineFound = TRUE;
1031 }
1032 Entry = Entry->Flink;
1033 if (Entry != &List->DiskListHead)
1034 {
1035 if (CurrentDiskLineFound == FALSE)
1036 {
1037 CurrentPartLine ++;
1038 CurrentDiskLine = CurrentPartLine;
1039 }
1040 LastLine++;
1041 }
1042 else
1043 {
1044 LastLine--;
1045 }
1046 }
1047
1048 /* If it possible, make the disk name visible */
1049 if (CurrentPartLine < List->Offset)
1050 {
1051 List->Offset = CurrentPartLine;
1052 }
1053 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1054 {
1055 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1056 }
1057 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1058 {
1059 List->Offset = CurrentDiskLine;
1060 }
1061
1062
1063 /* draw upper left corner */
1064 coPos.X = List->Left;
1065 coPos.Y = List->Top;
1066 FillConsoleOutputCharacter (0xDA, // '+',
1067 1,
1068 coPos,
1069 &Written);
1070
1071 /* draw upper edge */
1072 coPos.X = List->Left + 1;
1073 coPos.Y = List->Top;
1074 if (List->Offset == 0)
1075 {
1076 FillConsoleOutputCharacter (0xC4, // '-',
1077 List->Right - List->Left - 1,
1078 coPos,
1079 &Written);
1080 }
1081 else
1082 {
1083 FillConsoleOutputCharacter (0xC4, // '-',
1084 List->Right - List->Left - 5,
1085 coPos,
1086 &Written);
1087 coPos.X = List->Right - 5;
1088 WriteConsoleOutputCharacters ("(\x18)", // "(up)"
1089 3,
1090 coPos);
1091 coPos.X = List->Right - 2;
1092 FillConsoleOutputCharacter (0xC4, // '-',
1093 2,
1094 coPos,
1095 &Written);
1096 }
1097
1098 /* draw upper right corner */
1099 coPos.X = List->Right;
1100 coPos.Y = List->Top;
1101 FillConsoleOutputCharacter (0xBF, // '+',
1102 1,
1103 coPos,
1104 &Written);
1105
1106 /* draw left and right edge */
1107 for (i = List->Top + 1; i < List->Bottom; i++)
1108 {
1109 coPos.X = List->Left;
1110 coPos.Y = i;
1111 FillConsoleOutputCharacter (0xB3, // '|',
1112 1,
1113 coPos,
1114 &Written);
1115
1116 coPos.X = List->Right;
1117 FillConsoleOutputCharacter (0xB3, //'|',
1118 1,
1119 coPos,
1120 &Written);
1121 }
1122
1123 /* draw lower left corner */
1124 coPos.X = List->Left;
1125 coPos.Y = List->Bottom;
1126 FillConsoleOutputCharacter (0xC0, // '+',
1127 1,
1128 coPos,
1129 &Written);
1130
1131 /* draw lower edge */
1132 coPos.X = List->Left + 1;
1133 coPos.Y = List->Bottom;
1134 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1135 {
1136 FillConsoleOutputCharacter (0xC4, // '-',
1137 List->Right - List->Left - 1,
1138 coPos,
1139 &Written);
1140 }
1141 else
1142 {
1143 FillConsoleOutputCharacter (0xC4, // '-',
1144 List->Right - List->Left - 5,
1145 coPos,
1146 &Written);
1147 coPos.X = List->Right - 5;
1148 WriteConsoleOutputCharacters ("(\x19)", // "(down)"
1149 3,
1150 coPos);
1151 coPos.X = List->Right - 2;
1152 FillConsoleOutputCharacter (0xC4, // '-',
1153 2,
1154 coPos,
1155 &Written);
1156 }
1157
1158 /* draw lower right corner */
1159 coPos.X = List->Right;
1160 coPos.Y = List->Bottom;
1161 FillConsoleOutputCharacter (0xD9, // '+',
1162 1,
1163 coPos,
1164 &Written);
1165
1166 /* print list entries */
1167 List->Line = - List->Offset;
1168
1169 Entry = List->DiskListHead.Flink;
1170 while (Entry != &List->DiskListHead)
1171 {
1172 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1173
1174 /* Print disk entry */
1175 PrintDiskData (List,
1176 DiskEntry);
1177
1178 Entry = Entry->Flink;
1179 }
1180 }
1181
1182
1183 VOID
1184 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1185 {
1186 PDISKENTRY DiskEntry;
1187 PPARTENTRY PartEntry;
1188 PLIST_ENTRY Entry1;
1189 PLIST_ENTRY Entry2;
1190 ULONG i;
1191
1192 /* Check for empty disks */
1193 if (IsListEmpty (&List->DiskListHead))
1194 return;
1195
1196 /* Check for first usable entry on next disk */
1197 Entry1 = List->CurrentDisk->ListEntry.Flink;
1198 while (Entry1 != &List->DiskListHead)
1199 {
1200 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1201
1202 if (DiskEntry->DiskNumber == DiskNumber)
1203 {
1204 Entry2 = DiskEntry->PartListHead.Flink;
1205 while (Entry2 != &DiskEntry->PartListHead)
1206 {
1207 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1208
1209 for (i = 0; i < 4; i++)
1210 {
1211 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1212 {
1213 List->CurrentDisk = DiskEntry;
1214 List->CurrentPartition = PartEntry;
1215 DrawPartitionList (List);
1216 return;
1217 }
1218 }
1219 Entry2 = Entry2->Flink;
1220 }
1221 return;
1222 }
1223 Entry1 = Entry1->Flink;
1224 }
1225 }
1226
1227
1228 VOID
1229 ScrollDownPartitionList (PPARTLIST List)
1230 {
1231 PDISKENTRY DiskEntry;
1232 PPARTENTRY PartEntry;
1233 PLIST_ENTRY Entry1;
1234 PLIST_ENTRY Entry2;
1235
1236 /* Check for empty disks */
1237 if (IsListEmpty (&List->DiskListHead))
1238 return;
1239
1240 /* Check for next usable entry on current disk */
1241 if (List->CurrentPartition != NULL)
1242 {
1243 Entry2 = List->CurrentPartition->ListEntry.Flink;
1244 while (Entry2 != &List->CurrentDisk->PartListHead)
1245 {
1246 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1247
1248 // if (PartEntry->HidePartEntry == FALSE)
1249 {
1250 List->CurrentPartition = PartEntry;
1251 DrawPartitionList (List);
1252 return;
1253 }
1254 Entry2 = Entry2->Flink;
1255 }
1256 }
1257
1258 /* Check for first usable entry on next disk */
1259 if (List->CurrentDisk != NULL)
1260 {
1261 Entry1 = List->CurrentDisk->ListEntry.Flink;
1262 while (Entry1 != &List->DiskListHead)
1263 {
1264 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1265
1266 Entry2 = DiskEntry->PartListHead.Flink;
1267 while (Entry2 != &DiskEntry->PartListHead)
1268 {
1269 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1270
1271 // if (PartEntry->HidePartEntry == FALSE)
1272 {
1273 List->CurrentDisk = DiskEntry;
1274 List->CurrentPartition = PartEntry;
1275 DrawPartitionList (List);
1276 return;
1277 }
1278
1279 Entry2 = Entry2->Flink;
1280 }
1281
1282 Entry1 = Entry1->Flink;
1283 }
1284 }
1285 }
1286
1287
1288 VOID
1289 ScrollUpPartitionList (PPARTLIST List)
1290 {
1291 PDISKENTRY DiskEntry;
1292 PPARTENTRY PartEntry;
1293 PLIST_ENTRY Entry1;
1294 PLIST_ENTRY Entry2;
1295
1296 /* Check for empty disks */
1297 if (IsListEmpty (&List->DiskListHead))
1298 return;
1299
1300 /* check for previous usable entry on current disk */
1301 if (List->CurrentPartition != NULL)
1302 {
1303 Entry2 = List->CurrentPartition->ListEntry.Blink;
1304 while (Entry2 != &List->CurrentDisk->PartListHead)
1305 {
1306 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1307
1308 // if (PartEntry->HidePartEntry == FALSE)
1309 {
1310 List->CurrentPartition = PartEntry;
1311 DrawPartitionList (List);
1312 return;
1313 }
1314 Entry2 = Entry2->Blink;
1315 }
1316 }
1317
1318
1319 /* check for last usable entry on previous disk */
1320 if (List->CurrentDisk != NULL)
1321 {
1322 Entry1 = List->CurrentDisk->ListEntry.Blink;
1323 while (Entry1 != &List->DiskListHead)
1324 {
1325 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1326
1327 Entry2 = DiskEntry->PartListHead.Blink;
1328 while (Entry2 != &DiskEntry->PartListHead)
1329 {
1330 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1331
1332 // if (PartEntry->HidePartEntry == FALSE)
1333 {
1334 List->CurrentDisk = DiskEntry;
1335 List->CurrentPartition = PartEntry;
1336 DrawPartitionList (List);
1337 return;
1338 }
1339
1340 Entry2 = Entry2->Blink;
1341 }
1342
1343 Entry1 = Entry1->Blink;
1344 }
1345 }
1346 }
1347
1348
1349 static PPARTENTRY
1350 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1351 PPARTENTRY CurrentEntry)
1352 {
1353 PPARTENTRY PrevEntry;
1354 PLIST_ENTRY Entry;
1355
1356 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1357 return NULL;
1358
1359 Entry = CurrentEntry->ListEntry.Blink;
1360 while (Entry != &DiskEntry->PartListHead)
1361 {
1362 PrevEntry = CONTAINING_RECORD (Entry,
1363 PARTENTRY,
1364 ListEntry);
1365 if (PrevEntry->Unpartitioned == FALSE)
1366 return PrevEntry;
1367
1368 Entry = Entry->Blink;
1369 }
1370
1371 return NULL;
1372 }
1373
1374
1375 static PPARTENTRY
1376 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1377 PPARTENTRY CurrentEntry)
1378 {
1379 PPARTENTRY NextEntry;
1380 PLIST_ENTRY Entry;
1381
1382 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1383 return NULL;
1384
1385 Entry = CurrentEntry->ListEntry.Flink;
1386 while (Entry != &DiskEntry->PartListHead)
1387 {
1388 NextEntry = CONTAINING_RECORD (Entry,
1389 PARTENTRY,
1390 ListEntry);
1391 if (NextEntry->Unpartitioned == FALSE)
1392 return NextEntry;
1393
1394 Entry = Entry->Flink;
1395 }
1396
1397 return NULL;
1398 }
1399
1400
1401 static PPARTENTRY
1402 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1403 PPARTENTRY PartEntry)
1404 {
1405 PPARTENTRY PrevPartEntry;
1406
1407 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1408 {
1409 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1410 PARTENTRY,
1411 ListEntry);
1412 if (PrevPartEntry->Unpartitioned == TRUE)
1413 return PrevPartEntry;
1414 }
1415
1416 return NULL;
1417 }
1418
1419
1420 static PPARTENTRY
1421 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1422 PPARTENTRY PartEntry)
1423 {
1424 PPARTENTRY NextPartEntry;
1425
1426 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1427 {
1428 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1429 PARTENTRY,
1430 ListEntry);
1431 if (NextPartEntry->Unpartitioned == TRUE)
1432 return NextPartEntry;
1433 }
1434
1435 return NULL;
1436 }
1437
1438
1439 VOID
1440 CreateNewPartition (PPARTLIST List,
1441 ULONGLONG PartitionSize,
1442 BOOLEAN AutoCreate)
1443 {
1444 PDISKENTRY DiskEntry;
1445 PPARTENTRY PartEntry;
1446 PPARTENTRY PrevPartEntry;
1447 PPARTENTRY NextPartEntry;
1448 PPARTENTRY NewPartEntry;
1449
1450 if (List == NULL ||
1451 List->CurrentDisk == NULL ||
1452 List->CurrentPartition == NULL ||
1453 List->CurrentPartition->Unpartitioned == FALSE)
1454 {
1455 return;
1456 }
1457
1458 DiskEntry = List->CurrentDisk;
1459 PartEntry = List->CurrentPartition;
1460
1461 if (AutoCreate == TRUE ||
1462 PartitionSize == PartEntry->UnpartitionedLength)
1463 {
1464 /* Convert current entry to 'new (unformatted)' */
1465 PartEntry->FormatState = Unformatted;
1466 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1467 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1468 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1469 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1470 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1471 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1472 PartEntry->PartInfo[0].RewritePartition = TRUE;
1473 PartEntry->PartInfo[1].RewritePartition = TRUE;
1474 PartEntry->PartInfo[2].RewritePartition = TRUE;
1475 PartEntry->PartInfo[3].RewritePartition = TRUE;
1476
1477 /* Get previous and next partition entries */
1478 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1479 PartEntry);
1480 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1481 PartEntry);
1482
1483 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1484 {
1485 /* Current entry is in the middle of the list */
1486
1487 /* Copy previous container partition data to current entry */
1488 RtlCopyMemory (&PartEntry->PartInfo[1],
1489 &PrevPartEntry->PartInfo[1],
1490 sizeof(PARTITION_INFORMATION));
1491 PartEntry->PartInfo[1].RewritePartition = TRUE;
1492
1493 /* Update previous container partition data */
1494
1495 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1496 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1497
1498 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1499 {
1500 /* Special case - previous partition is first partition */
1501 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1502 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1503 }
1504 else
1505 {
1506 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1507 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1508 }
1509
1510 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1511 }
1512 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1513 {
1514 /* Current entry is the first entry */
1515 return;
1516 }
1517 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1518 {
1519 /* Current entry is the last entry */
1520
1521 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1522 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1523
1524 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1525 {
1526 /* Special case - previous partition is first partition */
1527 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1528 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1529 }
1530 else
1531 {
1532 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1533 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1534 }
1535
1536 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1537 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1538 (1024LL * 255LL * 63LL * 512LL))
1539 {
1540 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1541 }
1542 else
1543 {
1544 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1545 }
1546
1547 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1548 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1549 }
1550
1551 PartEntry->AutoCreate = AutoCreate;
1552 PartEntry->New = TRUE;
1553 PartEntry->Unpartitioned = FALSE;
1554 PartEntry->UnpartitionedOffset = 0ULL;
1555 PartEntry->UnpartitionedLength = 0ULL;
1556 }
1557 else
1558 {
1559 /* Insert an initialize a new partition entry */
1560 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1561 0,
1562 sizeof(PARTENTRY));
1563 if (NewPartEntry == NULL)
1564 return;
1565
1566 RtlZeroMemory (NewPartEntry,
1567 sizeof(PARTENTRY));
1568
1569 /* Insert the new entry into the list */
1570 InsertTailList (&PartEntry->ListEntry,
1571 &NewPartEntry->ListEntry);
1572
1573 NewPartEntry->New = TRUE;
1574
1575 NewPartEntry->FormatState = Unformatted;
1576 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1577 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1578 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1579 PartitionSize - DiskEntry->TrackSize;
1580 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1581 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1582 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1583 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1584 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1585 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1586
1587 /* Get previous and next partition entries */
1588 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1589 NewPartEntry);
1590 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1591 NewPartEntry);
1592
1593 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1594 {
1595 /* Current entry is in the middle of the list */
1596
1597 /* Copy previous container partition data to current entry */
1598 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1599 &PrevPartEntry->PartInfo[1],
1600 sizeof(PARTITION_INFORMATION));
1601 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1602
1603 /* Update previous container partition data */
1604
1605 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1606 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1607
1608 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1609 {
1610 /* Special case - previous partition is first partition */
1611 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1612 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1613 }
1614 else
1615 {
1616 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1617 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1618 }
1619
1620 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1621 }
1622 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1623 {
1624 /* Current entry is the first entry */
1625 return;
1626 }
1627 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1628 {
1629 /* Current entry is the last entry */
1630
1631 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1632 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1633
1634 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1635 {
1636 /* Special case - previous partition is first partition */
1637 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1638 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1639 }
1640 else
1641 {
1642 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1643 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1644 }
1645
1646 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1647 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1648 (1024LL * 255LL * 63LL * 512LL))
1649 {
1650 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1651 }
1652 else
1653 {
1654 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1655 }
1656
1657 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1658 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1659 }
1660
1661 /* Update offset and size of the remaining unpartitioned disk space */
1662 PartEntry->UnpartitionedOffset += PartitionSize;
1663 PartEntry->UnpartitionedLength -= PartitionSize;
1664 }
1665
1666 DiskEntry->Modified = TRUE;
1667
1668 UpdatePartitionNumbers (DiskEntry);
1669
1670 AssignDriverLetters (List);
1671 }
1672
1673
1674 VOID
1675 DeleteCurrentPartition (PPARTLIST List)
1676 {
1677 PDISKENTRY DiskEntry;
1678 PPARTENTRY PartEntry;
1679 PPARTENTRY PrevPartEntry;
1680 PPARTENTRY NextPartEntry;
1681
1682 if (List == NULL ||
1683 List->CurrentDisk == NULL ||
1684 List->CurrentPartition == NULL ||
1685 List->CurrentPartition->Unpartitioned == TRUE)
1686 {
1687 return;
1688 }
1689
1690 DiskEntry = List->CurrentDisk;
1691 PartEntry = List->CurrentPartition;
1692
1693 /* Adjust container partition entries */
1694
1695 /* Get previous and next partition entries */
1696 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1697 PartEntry);
1698 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1699 PartEntry);
1700
1701 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1702 {
1703 /* Current entry is in the middle of the list */
1704
1705 /*
1706 * The first extended partition can not be deleted
1707 * as long as other extended partitions are present.
1708 */
1709 if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1710 return;
1711
1712 /* Copy previous container partition data to current entry */
1713 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
1714 &PartEntry->PartInfo[1],
1715 sizeof(PARTITION_INFORMATION));
1716 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1717 }
1718 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1719 {
1720 /*
1721 * A primary partition can not be deleted as long as
1722 * extended partitions are present.
1723 */
1724 return;
1725 }
1726 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1727 {
1728 /* Current entry is the last entry */
1729 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
1730 sizeof(PARTITION_INFORMATION));
1731 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1732 }
1733
1734
1735 /* Adjust unpartitioned disk space entries */
1736
1737 /* Get pointer to previous and next unpartitioned entries */
1738 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
1739 PartEntry);
1740
1741 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
1742 PartEntry);
1743
1744 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1745 {
1746 /* Merge previous, current and next unpartitioned entry */
1747
1748 /* Adjust the previous entries length */
1749 PrevPartEntry->UnpartitionedLength +=
1750 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
1751 NextPartEntry->UnpartitionedLength);
1752
1753 /* Remove the current entry */
1754 RemoveEntryList (&PartEntry->ListEntry);
1755 RtlFreeHeap (ProcessHeap,
1756 0,
1757 PartEntry);
1758
1759 /* Remove the next entry */
1760 RemoveEntryList (&NextPartEntry->ListEntry);
1761 RtlFreeHeap (ProcessHeap,
1762 0,
1763 NextPartEntry);
1764
1765 /* Update current partition */
1766 List->CurrentPartition = PrevPartEntry;
1767 }
1768 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1769 {
1770 /* Merge current and previous unpartitioned entry */
1771
1772 /* Adjust the previous entries length */
1773 PrevPartEntry->UnpartitionedLength +=
1774 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1775
1776 /* Remove the current entry */
1777 RemoveEntryList (&PartEntry->ListEntry);
1778 RtlFreeHeap (ProcessHeap,
1779 0,
1780 PartEntry);
1781
1782 /* Update current partition */
1783 List->CurrentPartition = PrevPartEntry;
1784 }
1785 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1786 {
1787 /* Merge current and next unpartitioned entry */
1788
1789 /* Adjust the next entries offset and length */
1790 NextPartEntry->UnpartitionedOffset =
1791 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1792 NextPartEntry->UnpartitionedLength +=
1793 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1794
1795 /* Remove the current entry */
1796 RemoveEntryList (&PartEntry->ListEntry);
1797 RtlFreeHeap (ProcessHeap,
1798 0,
1799 PartEntry);
1800
1801 /* Update current partition */
1802 List->CurrentPartition = NextPartEntry;
1803 }
1804 else
1805 {
1806 /* Nothing to merge but change current entry */
1807 PartEntry->New = FALSE;
1808 PartEntry->Unpartitioned = TRUE;
1809 PartEntry->UnpartitionedOffset =
1810 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1811 PartEntry->UnpartitionedLength =
1812 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1813
1814 /* Wipe the partition table */
1815 RtlZeroMemory (&PartEntry->PartInfo,
1816 sizeof(PartEntry->PartInfo));
1817 }
1818
1819 DiskEntry->Modified = TRUE;
1820
1821 UpdatePartitionNumbers (DiskEntry);
1822
1823 AssignDriverLetters (List);
1824 }
1825
1826
1827 VOID
1828 CheckActiveBootPartition (PPARTLIST List)
1829 {
1830 PDISKENTRY DiskEntry;
1831 PPARTENTRY PartEntry;
1832
1833 /* Check for empty disk list */
1834 if (IsListEmpty (&List->DiskListHead))
1835 {
1836 List->ActiveBootDisk = NULL;
1837 List->ActiveBootPartition = NULL;
1838 return;
1839 }
1840
1841 #if 0
1842 if (List->ActiveBootDisk != NULL &&
1843 List->ActiveBootPartition != NULL)
1844 {
1845 /* We already have an active boot partition */
1846 return;
1847 }
1848 #endif
1849
1850 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
1851 DISKENTRY,
1852 ListEntry);
1853
1854 /* Check for empty partition list */
1855 if (IsListEmpty (&DiskEntry->PartListHead))
1856 {
1857 List->ActiveBootDisk = NULL;
1858 List->ActiveBootPartition = NULL;
1859 return;
1860 }
1861
1862 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
1863 PARTENTRY,
1864 ListEntry);
1865
1866 /* Set active boot partition */
1867 if ((DiskEntry->NewDisk == TRUE) ||
1868 (PartEntry->PartInfo[0].BootIndicator == FALSE &&
1869 PartEntry->PartInfo[1].BootIndicator == FALSE &&
1870 PartEntry->PartInfo[2].BootIndicator == FALSE &&
1871 PartEntry->PartInfo[3].BootIndicator == FALSE))
1872 {
1873 PartEntry->PartInfo[0].BootIndicator = TRUE;
1874 PartEntry->PartInfo[0].RewritePartition = TRUE;
1875 DiskEntry->Modified = TRUE;
1876 }
1877
1878 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
1879 List->ActiveBootDisk = DiskEntry;
1880 List->ActiveBootPartition = PartEntry;
1881 }
1882
1883
1884 BOOLEAN
1885 CheckForLinuxFdiskPartitions (PPARTLIST List)
1886 {
1887 PDISKENTRY DiskEntry;
1888 PPARTENTRY PartEntry;
1889 PLIST_ENTRY Entry1;
1890 PLIST_ENTRY Entry2;
1891 ULONG PartitionCount;
1892 ULONG i;
1893
1894 Entry1 = List->DiskListHead.Flink;
1895 while (Entry1 != &List->DiskListHead)
1896 {
1897 DiskEntry = CONTAINING_RECORD (Entry1,
1898 DISKENTRY,
1899 ListEntry);
1900
1901 Entry2 = DiskEntry->PartListHead.Flink;
1902 while (Entry2 != &DiskEntry->PartListHead)
1903 {
1904 PartEntry = CONTAINING_RECORD (Entry2,
1905 PARTENTRY,
1906 ListEntry);
1907
1908 if (PartEntry->Unpartitioned == FALSE)
1909 {
1910 PartitionCount = 0;
1911
1912 for (i = 0; i < 4; i++)
1913 {
1914 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
1915 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
1916 {
1917 PartitionCount++;
1918 }
1919 }
1920
1921 if (PartitionCount > 1)
1922 {
1923 return TRUE;
1924 }
1925 }
1926
1927 Entry2 = Entry2->Flink;
1928 }
1929
1930 Entry1 = Entry1->Flink;
1931 }
1932
1933 return FALSE;
1934 }
1935
1936
1937 BOOLEAN
1938 WritePartitionsToDisk (PPARTLIST List)
1939 {
1940 PDRIVE_LAYOUT_INFORMATION DriveLayout;
1941 OBJECT_ATTRIBUTES ObjectAttributes;
1942 IO_STATUS_BLOCK Iosb;
1943 WCHAR SrcPath[MAX_PATH];
1944 WCHAR DstPath[MAX_PATH];
1945 UNICODE_STRING Name;
1946 HANDLE FileHandle;
1947 PDISKENTRY DiskEntry;
1948 PPARTENTRY PartEntry;
1949 PLIST_ENTRY Entry1;
1950 PLIST_ENTRY Entry2;
1951 ULONG PartitionCount;
1952 ULONG DriveLayoutSize;
1953 ULONG Index;
1954 NTSTATUS Status;
1955
1956 if (List == NULL)
1957 {
1958 return TRUE;
1959 }
1960
1961 Entry1 = List->DiskListHead.Flink;
1962 while (Entry1 != &List->DiskListHead)
1963 {
1964 DiskEntry = CONTAINING_RECORD (Entry1,
1965 DISKENTRY,
1966 ListEntry);
1967
1968 if (DiskEntry->Modified == TRUE)
1969 {
1970 /* Count partitioned entries */
1971 PartitionCount = 0;
1972 Entry2 = DiskEntry->PartListHead.Flink;
1973 while (Entry2 != &DiskEntry->PartListHead)
1974 {
1975 PartEntry = CONTAINING_RECORD (Entry2,
1976 PARTENTRY,
1977 ListEntry);
1978 if (PartEntry->Unpartitioned == FALSE)
1979 {
1980 PartitionCount += 4;
1981 }
1982
1983 Entry2 = Entry2->Flink;
1984 }
1985
1986 if (PartitionCount > 0)
1987 {
1988 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
1989 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
1990 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
1991 0,
1992 DriveLayoutSize);
1993 if (DriveLayout == NULL)
1994 {
1995 DPRINT1 ("RtlAllocateHeap() failed\n");
1996 return FALSE;
1997 }
1998
1999 RtlZeroMemory (DriveLayout,
2000 DriveLayoutSize);
2001
2002 DriveLayout->PartitionCount = PartitionCount;
2003
2004 Index = 0;
2005 Entry2 = DiskEntry->PartListHead.Flink;
2006 while (Entry2 != &DiskEntry->PartListHead)
2007 {
2008 PartEntry = CONTAINING_RECORD (Entry2,
2009 PARTENTRY,
2010 ListEntry);
2011 if (PartEntry->Unpartitioned == FALSE)
2012 {
2013 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
2014 &PartEntry->PartInfo[0],
2015 4 * sizeof (PARTITION_INFORMATION));
2016 Index += 4;
2017 }
2018
2019 Entry2 = Entry2->Flink;
2020 }
2021
2022 swprintf (DstPath,
2023 L"\\Device\\Harddisk%d\\Partition0",
2024 DiskEntry->DiskNumber);
2025 RtlInitUnicodeString (&Name,
2026 DstPath);
2027 InitializeObjectAttributes (&ObjectAttributes,
2028 &Name,
2029 0,
2030 NULL,
2031 NULL);
2032
2033 Status = NtOpenFile (&FileHandle,
2034 FILE_ALL_ACCESS,
2035 &ObjectAttributes,
2036 &Iosb,
2037 0,
2038 FILE_SYNCHRONOUS_IO_NONALERT);
2039 if (!NT_SUCCESS (Status))
2040 {
2041 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
2042 return FALSE;
2043 }
2044
2045 Status = NtDeviceIoControlFile (FileHandle,
2046 NULL,
2047 NULL,
2048 NULL,
2049 &Iosb,
2050 IOCTL_DISK_SET_DRIVE_LAYOUT,
2051 DriveLayout,
2052 DriveLayoutSize,
2053 NULL,
2054 0);
2055 if (!NT_SUCCESS (Status))
2056 {
2057 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
2058 NtClose (FileHandle);
2059 return FALSE;
2060 }
2061
2062 RtlFreeHeap (ProcessHeap,
2063 0,
2064 DriveLayout);
2065
2066 NtClose (FileHandle);
2067
2068 /* Install MBR code if the disk is new */
2069 if (DiskEntry->NewDisk == TRUE)
2070 {
2071 wcscpy (SrcPath, SourceRootPath.Buffer);
2072 wcscat (SrcPath, L"\\loader\\dosmbr.bin");
2073
2074 DPRINT1 ("Install MBR bootcode: %S ==> %S\n",
2075 SrcPath, DstPath);
2076
2077 /* Install MBR bootcode */
2078 Status = InstallMbrBootCodeToDisk (SrcPath,
2079 DstPath);
2080 if (!NT_SUCCESS (Status))
2081 {
2082 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
2083 Status);
2084 return FALSE;
2085 }
2086
2087 DiskEntry->NewDisk = FALSE;
2088 }
2089 }
2090 }
2091
2092 Entry1 = Entry1->Flink;
2093 }
2094
2095 return TRUE;
2096 }
2097
2098 /* EOF */