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