c10bee914abd2a0651b8070098c28a9a317fd8b4
[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: partlist.c,v 1.26 2003/12/01 18:28:54 navaraf Exp $
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 <ddk/ntddk.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 - 1;
723
724 if (List->Line < 0 || List->Line > Height)
725 return;
726
727 coPos.X = List->Left + 1;
728 coPos.Y = List->Top + 1 + List->Line;
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 - 1;
762
763 if (List->Line < 0 || List->Line > Height)
764 return;
765
766 coPos.X = List->Left + 1;
767 coPos.Y = List->Top + 1 + List->Line;
768
769 if (PartEntry->Unpartitioned == TRUE)
770 {
771 #if 0
772 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
773 {
774 PartSize = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
775 Unit = "GB";
776 }
777 else
778 #endif
779 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
780 {
781 PartSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
782 Unit = "MB";
783 }
784 else
785 {
786 PartSize = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
787 Unit = "KB";
788 }
789
790 sprintf (LineBuffer,
791 " Unpartitioned space %6I64u %s",
792 PartSize,
793 Unit);
794 }
795 else
796 {
797 /* Determine partition type */
798 PartType = NULL;
799 if (PartEntry->New == TRUE)
800 {
801 PartType = "New (Unformatted)";
802 }
803 else if (PartEntry->Unpartitioned == FALSE)
804 {
805 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
806 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
807 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
808 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
809 {
810 PartType = "FAT";
811 }
812 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
813 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
814 {
815 PartType = "FAT32";
816 }
817 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
818 {
819 PartType = "NTFS"; /* FIXME: Not quite correct! */
820 }
821 }
822
823 #if 0
824 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000ULL) /* 10 GB */
825 {
826 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
827 Unit = "GB";
828 }
829 else
830 #endif
831 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000ULL) /* 10 MB */
832 {
833 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
834 Unit = "MB";
835 }
836 else
837 {
838 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
839 Unit = "KB";
840 }
841
842 if (PartType == NULL)
843 {
844 sprintf (LineBuffer,
845 "%c%c Type %-3u %6I64u %s",
846 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
847 (PartEntry->DriveLetter == 0) ? '-' : ':',
848 PartEntry->PartInfo[0].PartitionType,
849 PartSize,
850 Unit);
851 }
852 else
853 {
854 sprintf (LineBuffer,
855 "%c%c %-24s %6I64u %s",
856 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
857 (PartEntry->DriveLetter == 0) ? '-' : ':',
858 PartType,
859 PartSize,
860 Unit);
861 }
862 }
863
864 Attribute = (List->CurrentDisk == DiskEntry &&
865 List->CurrentPartition == PartEntry) ? 0x71 : 0x17;
866
867 FillConsoleOutputCharacter (' ',
868 Width,
869 coPos,
870 &Written);
871
872 coPos.X += 4;
873 Width -= 8;
874 FillConsoleOutputAttribute (Attribute,
875 Width,
876 coPos,
877 &Written);
878
879 coPos.X++;
880 Width -= 2;
881 WriteConsoleOutputCharacters (LineBuffer,
882 min (strlen (LineBuffer), Width),
883 coPos);
884
885 List->Line++;
886 }
887
888
889 static VOID
890 PrintDiskData (PPARTLIST List,
891 PDISKENTRY DiskEntry)
892 {
893 PPARTENTRY PartEntry;
894 PLIST_ENTRY Entry;
895 CHAR LineBuffer[128];
896 COORD coPos;
897 ULONG Written;
898 USHORT Width;
899 USHORT Height;
900 ULONGLONG DiskSize;
901 PCHAR Unit;
902
903 Width = List->Right - List->Left - 1;
904 Height = List->Bottom - List->Top - 1;
905
906 if (List->Line < 0 || List->Line > Height)
907 return;
908
909 coPos.X = List->Left + 1;
910 coPos.Y = List->Top + 1 + List->Line;
911
912 #if 0
913 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
914 {
915 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
916 Unit = "GB";
917 }
918 else
919 #endif
920 {
921 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
922 if (DiskSize == 0)
923 DiskSize = 1;
924 Unit = "MB";
925 }
926
927 if (DiskEntry->DriverName.Length > 0)
928 {
929 sprintf (LineBuffer,
930 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
931 DiskSize,
932 Unit,
933 DiskEntry->DiskNumber,
934 DiskEntry->Port,
935 DiskEntry->Bus,
936 DiskEntry->Id,
937 &DiskEntry->DriverName);
938 }
939 else
940 {
941 sprintf (LineBuffer,
942 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
943 DiskSize,
944 Unit,
945 DiskEntry->DiskNumber,
946 DiskEntry->Port,
947 DiskEntry->Bus,
948 DiskEntry->Id);
949 }
950
951 FillConsoleOutputAttribute (0x17,
952 Width,
953 coPos,
954 &Written);
955
956 FillConsoleOutputCharacter (' ',
957 Width,
958 coPos,
959 &Written);
960
961 coPos.X++;
962 WriteConsoleOutputCharacters (LineBuffer,
963 min (strlen (LineBuffer), Width - 2),
964 coPos);
965
966 List->Line++;
967
968 /* Print separator line */
969 PrintEmptyLine (List);
970
971 /* Print partition lines*/
972 Entry = DiskEntry->PartListHead.Flink;
973 while (Entry != &DiskEntry->PartListHead)
974 {
975 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
976
977 /* Print disk entry */
978 PrintPartitionData (List,
979 DiskEntry,
980 PartEntry);
981
982 Entry = Entry->Flink;
983 }
984
985 /* Print separator line */
986 PrintEmptyLine (List);
987 }
988
989
990 VOID
991 DrawPartitionList (PPARTLIST List)
992 {
993 PLIST_ENTRY Entry;
994 PDISKENTRY DiskEntry;
995 COORD coPos;
996 ULONG Written;
997 SHORT i;
998
999 /* draw upper left corner */
1000 coPos.X = List->Left;
1001 coPos.Y = List->Top;
1002 FillConsoleOutputCharacter (0xDA, // '+',
1003 1,
1004 coPos,
1005 &Written);
1006
1007 /* draw upper edge */
1008 coPos.X = List->Left + 1;
1009 coPos.Y = List->Top;
1010 FillConsoleOutputCharacter (0xC4, // '-',
1011 List->Right - List->Left - 1,
1012 coPos,
1013 &Written);
1014
1015 /* draw upper right corner */
1016 coPos.X = List->Right;
1017 coPos.Y = List->Top;
1018 FillConsoleOutputCharacter (0xBF, // '+',
1019 1,
1020 coPos,
1021 &Written);
1022
1023 /* draw left and right edge */
1024 for (i = List->Top + 1; i < List->Bottom; i++)
1025 {
1026 coPos.X = List->Left;
1027 coPos.Y = i;
1028 FillConsoleOutputCharacter (0xB3, // '|',
1029 1,
1030 coPos,
1031 &Written);
1032
1033 coPos.X = List->Right;
1034 FillConsoleOutputCharacter (0xB3, //'|',
1035 1,
1036 coPos,
1037 &Written);
1038 }
1039
1040 /* draw lower left corner */
1041 coPos.X = List->Left;
1042 coPos.Y = List->Bottom;
1043 FillConsoleOutputCharacter (0xC0, // '+',
1044 1,
1045 coPos,
1046 &Written);
1047
1048 /* draw lower edge */
1049 coPos.X = List->Left + 1;
1050 coPos.Y = List->Bottom;
1051 FillConsoleOutputCharacter (0xC4, // '-',
1052 List->Right - List->Left - 1,
1053 coPos,
1054 &Written);
1055
1056 /* draw lower right corner */
1057 coPos.X = List->Right;
1058 coPos.Y = List->Bottom;
1059 FillConsoleOutputCharacter (0xD9, // '+',
1060 1,
1061 coPos,
1062 &Written);
1063
1064 /* print list entries */
1065 List->Line = 0;
1066
1067 Entry = List->DiskListHead.Flink;
1068 while (Entry != &List->DiskListHead)
1069 {
1070 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1071
1072 /* Print disk entry */
1073 PrintDiskData (List,
1074 DiskEntry);
1075
1076 Entry = Entry->Flink;
1077 }
1078 }
1079
1080
1081 VOID
1082 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1083 {
1084 PDISKENTRY DiskEntry;
1085 PPARTENTRY PartEntry;
1086 PLIST_ENTRY Entry1;
1087 PLIST_ENTRY Entry2;
1088 ULONG i;
1089
1090 /* Check for empty disks */
1091 if (IsListEmpty (&List->DiskListHead))
1092 return;
1093
1094 /* Check for first usable entry on next disk */
1095 Entry1 = List->CurrentDisk->ListEntry.Flink;
1096 while (Entry1 != &List->DiskListHead)
1097 {
1098 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1099
1100 if (DiskEntry->DiskNumber == DiskNumber)
1101 {
1102 Entry2 = DiskEntry->PartListHead.Flink;
1103 while (Entry2 != &DiskEntry->PartListHead)
1104 {
1105 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1106
1107 for (i = 0; i < 4; i++)
1108 {
1109 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1110 {
1111 List->CurrentDisk = DiskEntry;
1112 List->CurrentPartition = PartEntry;
1113 DrawPartitionList (List);
1114 return;
1115 }
1116 }
1117 Entry2 = Entry2->Flink;
1118 }
1119 return;
1120 }
1121 Entry1 = Entry1->Flink;
1122 }
1123 }
1124
1125
1126 VOID
1127 ScrollDownPartitionList (PPARTLIST List)
1128 {
1129 PDISKENTRY DiskEntry;
1130 PPARTENTRY PartEntry;
1131 PLIST_ENTRY Entry1;
1132 PLIST_ENTRY Entry2;
1133
1134 /* Check for empty disks */
1135 if (IsListEmpty (&List->DiskListHead))
1136 return;
1137
1138 /* Check for next usable entry on current disk */
1139 if (List->CurrentPartition != NULL)
1140 {
1141 Entry2 = List->CurrentPartition->ListEntry.Flink;
1142 while (Entry2 != &List->CurrentDisk->PartListHead)
1143 {
1144 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1145
1146 // if (PartEntry->HidePartEntry == FALSE)
1147 {
1148 List->CurrentPartition = PartEntry;
1149 DrawPartitionList (List);
1150 return;
1151 }
1152 Entry2 = Entry2->Flink;
1153 }
1154 }
1155
1156 /* Check for first usable entry on next disk */
1157 if (List->CurrentDisk != NULL)
1158 {
1159 Entry1 = List->CurrentDisk->ListEntry.Flink;
1160 while (Entry1 != &List->DiskListHead)
1161 {
1162 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1163
1164 Entry2 = DiskEntry->PartListHead.Flink;
1165 while (Entry2 != &DiskEntry->PartListHead)
1166 {
1167 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1168
1169 // if (PartEntry->HidePartEntry == FALSE)
1170 {
1171 List->CurrentDisk = DiskEntry;
1172 List->CurrentPartition = PartEntry;
1173 DrawPartitionList (List);
1174 return;
1175 }
1176
1177 Entry2 = Entry2->Flink;
1178 }
1179
1180 Entry1 = Entry1->Flink;
1181 }
1182 }
1183 }
1184
1185
1186 VOID
1187 ScrollUpPartitionList (PPARTLIST List)
1188 {
1189 PDISKENTRY DiskEntry;
1190 PPARTENTRY PartEntry;
1191 PLIST_ENTRY Entry1;
1192 PLIST_ENTRY Entry2;
1193
1194 /* Check for empty disks */
1195 if (IsListEmpty (&List->DiskListHead))
1196 return;
1197
1198 /* check for previous usable entry on current disk */
1199 if (List->CurrentPartition != NULL)
1200 {
1201 Entry2 = List->CurrentPartition->ListEntry.Blink;
1202 while (Entry2 != &List->CurrentDisk->PartListHead)
1203 {
1204 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1205
1206 // if (PartEntry->HidePartEntry == FALSE)
1207 {
1208 List->CurrentPartition = PartEntry;
1209 DrawPartitionList (List);
1210 return;
1211 }
1212 Entry2 = Entry2->Blink;
1213 }
1214 }
1215
1216
1217 /* check for last usable entry on previous disk */
1218 if (List->CurrentDisk != NULL)
1219 {
1220 Entry1 = List->CurrentDisk->ListEntry.Blink;
1221 while (Entry1 != &List->DiskListHead)
1222 {
1223 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1224
1225 Entry2 = DiskEntry->PartListHead.Blink;
1226 while (Entry2 != &DiskEntry->PartListHead)
1227 {
1228 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1229
1230 // if (PartEntry->HidePartEntry == FALSE)
1231 {
1232 List->CurrentDisk = DiskEntry;
1233 List->CurrentPartition = PartEntry;
1234 DrawPartitionList (List);
1235 return;
1236 }
1237
1238 Entry2 = Entry2->Blink;
1239 }
1240
1241 Entry1 = Entry1->Blink;
1242 }
1243 }
1244 }
1245
1246
1247 static PPARTENTRY
1248 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1249 PPARTENTRY CurrentEntry)
1250 {
1251 PPARTENTRY PrevEntry;
1252 PLIST_ENTRY Entry;
1253
1254 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1255 return NULL;
1256
1257 Entry = CurrentEntry->ListEntry.Blink;
1258 while (Entry != &DiskEntry->PartListHead)
1259 {
1260 PrevEntry = CONTAINING_RECORD (Entry,
1261 PARTENTRY,
1262 ListEntry);
1263 if (PrevEntry->Unpartitioned == FALSE)
1264 return PrevEntry;
1265
1266 Entry = Entry->Blink;
1267 }
1268
1269 return NULL;
1270 }
1271
1272
1273 static PPARTENTRY
1274 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1275 PPARTENTRY CurrentEntry)
1276 {
1277 PPARTENTRY NextEntry;
1278 PLIST_ENTRY Entry;
1279
1280 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1281 return NULL;
1282
1283 Entry = CurrentEntry->ListEntry.Flink;
1284 while (Entry != &DiskEntry->PartListHead)
1285 {
1286 NextEntry = CONTAINING_RECORD (Entry,
1287 PARTENTRY,
1288 ListEntry);
1289 if (NextEntry->Unpartitioned == FALSE)
1290 return NextEntry;
1291
1292 Entry = Entry->Flink;
1293 }
1294
1295 return NULL;
1296 }
1297
1298
1299 static PPARTENTRY
1300 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1301 PPARTENTRY PartEntry)
1302 {
1303 PPARTENTRY PrevPartEntry;
1304
1305 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1306 {
1307 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1308 PARTENTRY,
1309 ListEntry);
1310 if (PrevPartEntry->Unpartitioned == TRUE)
1311 return PrevPartEntry;
1312 }
1313
1314 return NULL;
1315 }
1316
1317
1318 static PPARTENTRY
1319 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1320 PPARTENTRY PartEntry)
1321 {
1322 PPARTENTRY NextPartEntry;
1323
1324 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1325 {
1326 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1327 PARTENTRY,
1328 ListEntry);
1329 if (NextPartEntry->Unpartitioned == TRUE)
1330 return NextPartEntry;
1331 }
1332
1333 return NULL;
1334 }
1335
1336
1337 VOID
1338 CreateNewPartition (PPARTLIST List,
1339 ULONGLONG PartitionSize,
1340 BOOLEAN AutoCreate)
1341 {
1342 PDISKENTRY DiskEntry;
1343 PPARTENTRY PartEntry;
1344 PPARTENTRY PrevPartEntry;
1345 PPARTENTRY NextPartEntry;
1346 PPARTENTRY NewPartEntry;
1347
1348 if (List == NULL ||
1349 List->CurrentDisk == NULL ||
1350 List->CurrentPartition == NULL ||
1351 List->CurrentPartition->Unpartitioned == FALSE)
1352 {
1353 return;
1354 }
1355
1356 DiskEntry = List->CurrentDisk;
1357 PartEntry = List->CurrentPartition;
1358
1359 if (AutoCreate == TRUE ||
1360 PartitionSize == PartEntry->UnpartitionedLength)
1361 {
1362 /* Convert current entry to 'new (unformatted)' */
1363 PartEntry->FormatState = Unformatted;
1364 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1365 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1366 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1367 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1368 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1369 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1370 PartEntry->PartInfo[0].RewritePartition = TRUE;
1371 PartEntry->PartInfo[1].RewritePartition = TRUE;
1372 PartEntry->PartInfo[2].RewritePartition = TRUE;
1373 PartEntry->PartInfo[3].RewritePartition = TRUE;
1374
1375 /* Get previous and next partition entries */
1376 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1377 PartEntry);
1378 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1379 PartEntry);
1380
1381 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1382 {
1383 /* Current entry is in the middle of the list */
1384
1385 /* Copy previous container partition data to current entry */
1386 RtlCopyMemory (&PartEntry->PartInfo[1],
1387 &PrevPartEntry->PartInfo[1],
1388 sizeof(PARTITION_INFORMATION));
1389 PartEntry->PartInfo[1].RewritePartition = TRUE;
1390
1391 /* Update previous container partition data */
1392
1393 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1394 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1395
1396 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1397 {
1398 /* Special case - previous partition is first partition */
1399 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1400 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1401 }
1402 else
1403 {
1404 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1405 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1406 }
1407
1408 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1409 }
1410 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1411 {
1412 /* Current entry is the first entry */
1413 return;
1414 }
1415 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1416 {
1417 /* Current entry is the last entry */
1418
1419 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1420 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1421
1422 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1423 {
1424 /* Special case - previous partition is first partition */
1425 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1426 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1427 }
1428 else
1429 {
1430 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1431 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1432 }
1433
1434 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1435 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1436 (1024ULL * 255ULL * 63ULL * 512ULL))
1437 {
1438 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1439 }
1440 else
1441 {
1442 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1443 }
1444
1445 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1446 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1447 }
1448
1449 PartEntry->AutoCreate = AutoCreate;
1450 PartEntry->New = TRUE;
1451 PartEntry->Unpartitioned = FALSE;
1452 PartEntry->UnpartitionedOffset = 0ULL;
1453 PartEntry->UnpartitionedLength = 0ULL;
1454 }
1455 else
1456 {
1457 /* Insert an initialize a new partition entry */
1458 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1459 0,
1460 sizeof(PARTENTRY));
1461 if (NewPartEntry == NULL)
1462 return;
1463
1464 RtlZeroMemory (NewPartEntry,
1465 sizeof(PARTENTRY));
1466
1467 /* Insert the new entry into the list */
1468 InsertTailList (&PartEntry->ListEntry,
1469 &NewPartEntry->ListEntry);
1470
1471 NewPartEntry->New = TRUE;
1472
1473 NewPartEntry->FormatState = Unformatted;
1474 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1475 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1476 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1477 PartitionSize - DiskEntry->TrackSize;
1478 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1479 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1480 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1481 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1482 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1483 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1484
1485 /* Get previous and next partition entries */
1486 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1487 NewPartEntry);
1488 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1489 NewPartEntry);
1490
1491 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1492 {
1493 /* Current entry is in the middle of the list */
1494
1495 /* Copy previous container partition data to current entry */
1496 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1497 &PrevPartEntry->PartInfo[1],
1498 sizeof(PARTITION_INFORMATION));
1499 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1500
1501 /* Update previous container partition data */
1502
1503 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1504 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1505
1506 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1507 {
1508 /* Special case - previous partition is first partition */
1509 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1510 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1511 }
1512 else
1513 {
1514 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1515 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1516 }
1517
1518 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1519 }
1520 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1521 {
1522 /* Current entry is the first entry */
1523 return;
1524 }
1525 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1526 {
1527 /* Current entry is the last entry */
1528
1529 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1530 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1531
1532 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1533 {
1534 /* Special case - previous partition is first partition */
1535 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1536 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1537 }
1538 else
1539 {
1540 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1541 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1542 }
1543
1544 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1545 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1546 (1024ULL * 255ULL * 63ULL * 512ULL))
1547 {
1548 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1549 }
1550 else
1551 {
1552 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1553 }
1554
1555 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1556 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1557 }
1558
1559 /* Update offset and size of the remaining unpartitioned disk space */
1560 PartEntry->UnpartitionedOffset += PartitionSize;
1561 PartEntry->UnpartitionedLength -= PartitionSize;
1562 }
1563
1564 DiskEntry->Modified = TRUE;
1565
1566 UpdatePartitionNumbers (DiskEntry);
1567
1568 AssignDriverLetters (List);
1569 }
1570
1571
1572 VOID
1573 DeleteCurrentPartition (PPARTLIST List)
1574 {
1575 PDISKENTRY DiskEntry;
1576 PPARTENTRY PartEntry;
1577 PPARTENTRY PrevPartEntry;
1578 PPARTENTRY NextPartEntry;
1579
1580 if (List == NULL ||
1581 List->CurrentDisk == NULL ||
1582 List->CurrentPartition == NULL ||
1583 List->CurrentPartition->Unpartitioned == TRUE)
1584 {
1585 return;
1586 }
1587
1588 DiskEntry = List->CurrentDisk;
1589 PartEntry = List->CurrentPartition;
1590
1591 /* Adjust container partition entries */
1592
1593 /* Get previous and next partition entries */
1594 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1595 PartEntry);
1596 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1597 PartEntry);
1598
1599 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1600 {
1601 /* Current entry is in the middle of the list */
1602
1603 /*
1604 * The first extended partition can not be deleted
1605 * as long as other extended partitions are present.
1606 */
1607 if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1608 return;
1609
1610 /* Copy previous container partition data to current entry */
1611 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
1612 &PartEntry->PartInfo[1],
1613 sizeof(PARTITION_INFORMATION));
1614 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1615 }
1616 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1617 {
1618 /*
1619 * A primary partition can not be deleted as long as
1620 * extended partitions are present.
1621 */
1622 return;
1623 }
1624 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1625 {
1626 /* Current entry is the last entry */
1627 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
1628 sizeof(PARTITION_INFORMATION));
1629 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1630 }
1631
1632
1633 /* Adjust unpartitioned disk space entries */
1634
1635 /* Get pointer to previous and next unpartitioned entries */
1636 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
1637 PartEntry);
1638
1639 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
1640 PartEntry);
1641
1642 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1643 {
1644 /* Merge previous, current and next unpartitioned entry */
1645
1646 /* Adjust the previous entries length */
1647 PrevPartEntry->UnpartitionedLength +=
1648 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
1649 NextPartEntry->UnpartitionedLength);
1650
1651 /* Remove the current entry */
1652 RemoveEntryList (&PartEntry->ListEntry);
1653 RtlFreeHeap (ProcessHeap,
1654 0,
1655 PartEntry);
1656
1657 /* Remove the next entry */
1658 RemoveEntryList (&NextPartEntry->ListEntry);
1659 RtlFreeHeap (ProcessHeap,
1660 0,
1661 NextPartEntry);
1662
1663 /* Update current partition */
1664 List->CurrentPartition = PrevPartEntry;
1665 }
1666 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1667 {
1668 /* Merge current and previous unpartitioned entry */
1669
1670 /* Adjust the previous entries length */
1671 PrevPartEntry->UnpartitionedLength +=
1672 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1673
1674 /* Remove the current entry */
1675 RemoveEntryList (&PartEntry->ListEntry);
1676 RtlFreeHeap (ProcessHeap,
1677 0,
1678 PartEntry);
1679
1680 /* Update current partition */
1681 List->CurrentPartition = PrevPartEntry;
1682 }
1683 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1684 {
1685 /* Merge current and next unpartitioned entry */
1686
1687 /* Adjust the next entries offset and length */
1688 NextPartEntry->UnpartitionedOffset =
1689 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1690 NextPartEntry->UnpartitionedLength +=
1691 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1692
1693 /* Remove the current entry */
1694 RemoveEntryList (&PartEntry->ListEntry);
1695 RtlFreeHeap (ProcessHeap,
1696 0,
1697 PartEntry);
1698
1699 /* Update current partition */
1700 List->CurrentPartition = NextPartEntry;
1701 }
1702 else
1703 {
1704 /* Nothing to merge but change current entry */
1705 PartEntry->New = FALSE;
1706 PartEntry->Unpartitioned = TRUE;
1707 PartEntry->UnpartitionedOffset =
1708 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1709 PartEntry->UnpartitionedLength =
1710 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1711
1712 /* Wipe the partition table */
1713 RtlZeroMemory (&PartEntry->PartInfo,
1714 sizeof(PartEntry->PartInfo));
1715 }
1716
1717 DiskEntry->Modified = TRUE;
1718
1719 UpdatePartitionNumbers (DiskEntry);
1720
1721 AssignDriverLetters (List);
1722 }
1723
1724
1725 VOID
1726 CheckActiveBootPartition (PPARTLIST List)
1727 {
1728 PDISKENTRY DiskEntry;
1729 PPARTENTRY PartEntry;
1730
1731 /* Check for empty disk list */
1732 if (IsListEmpty (&List->DiskListHead))
1733 {
1734 List->ActiveBootDisk = NULL;
1735 List->ActiveBootPartition = NULL;
1736 return;
1737 }
1738
1739 #if 0
1740 if (List->ActiveBootDisk != NULL &&
1741 List->ActiveBootPartition != NULL)
1742 {
1743 /* We already have an active boot partition */
1744 return;
1745 }
1746 #endif
1747
1748 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
1749 DISKENTRY,
1750 ListEntry);
1751
1752 /* Check for empty partition list */
1753 if (IsListEmpty (&DiskEntry->PartListHead))
1754 {
1755 List->ActiveBootDisk = NULL;
1756 List->ActiveBootPartition = NULL;
1757 return;
1758 }
1759
1760 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
1761 PARTENTRY,
1762 ListEntry);
1763
1764 /* Set active boot partition */
1765 if ((DiskEntry->NewDisk == TRUE) ||
1766 (PartEntry->PartInfo[0].BootIndicator == FALSE &&
1767 PartEntry->PartInfo[1].BootIndicator == FALSE &&
1768 PartEntry->PartInfo[2].BootIndicator == FALSE &&
1769 PartEntry->PartInfo[3].BootIndicator == FALSE))
1770 {
1771 PartEntry->PartInfo[0].BootIndicator = TRUE;
1772 PartEntry->PartInfo[0].RewritePartition = TRUE;
1773 DiskEntry->Modified = TRUE;
1774 }
1775
1776 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
1777 List->ActiveBootDisk = DiskEntry;
1778 List->ActiveBootPartition = PartEntry;
1779 }
1780
1781
1782 BOOLEAN
1783 CheckForLinuxFdiskPartitions (PPARTLIST List)
1784 {
1785 PDISKENTRY DiskEntry;
1786 PPARTENTRY PartEntry;
1787 PLIST_ENTRY Entry1;
1788 PLIST_ENTRY Entry2;
1789 ULONG PartitionCount;
1790 ULONG i;
1791
1792 Entry1 = List->DiskListHead.Flink;
1793 while (Entry1 != &List->DiskListHead)
1794 {
1795 DiskEntry = CONTAINING_RECORD (Entry1,
1796 DISKENTRY,
1797 ListEntry);
1798
1799 Entry2 = DiskEntry->PartListHead.Flink;
1800 while (Entry2 != &DiskEntry->PartListHead)
1801 {
1802 PartEntry = CONTAINING_RECORD (Entry2,
1803 PARTENTRY,
1804 ListEntry);
1805
1806 if (PartEntry->Unpartitioned == FALSE)
1807 {
1808 PartitionCount = 0;
1809
1810 for (i = 0; i < 4; i++)
1811 {
1812 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
1813 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
1814 {
1815 PartitionCount++;
1816 }
1817 }
1818
1819 if (PartitionCount > 1)
1820 {
1821 return TRUE;
1822 }
1823 }
1824
1825 Entry2 = Entry2->Flink;
1826 }
1827
1828 Entry1 = Entry1->Flink;
1829 }
1830
1831 return FALSE;
1832 }
1833
1834
1835 BOOLEAN
1836 WritePartitionsToDisk (PPARTLIST List)
1837 {
1838 PDRIVE_LAYOUT_INFORMATION DriveLayout;
1839 OBJECT_ATTRIBUTES ObjectAttributes;
1840 IO_STATUS_BLOCK Iosb;
1841 WCHAR SrcPath[MAX_PATH];
1842 WCHAR DstPath[MAX_PATH];
1843 UNICODE_STRING Name;
1844 HANDLE FileHandle;
1845 PDISKENTRY DiskEntry;
1846 PPARTENTRY PartEntry;
1847 PLIST_ENTRY Entry1;
1848 PLIST_ENTRY Entry2;
1849 ULONG PartitionCount;
1850 ULONG DriveLayoutSize;
1851 ULONG Index;
1852 NTSTATUS Status;
1853
1854 if (List == NULL)
1855 {
1856 return TRUE;
1857 }
1858
1859 Entry1 = List->DiskListHead.Flink;
1860 while (Entry1 != &List->DiskListHead)
1861 {
1862 DiskEntry = CONTAINING_RECORD (Entry1,
1863 DISKENTRY,
1864 ListEntry);
1865
1866 if (DiskEntry->Modified == TRUE)
1867 {
1868 /* Count partitioned entries */
1869 PartitionCount = 0;
1870 Entry2 = DiskEntry->PartListHead.Flink;
1871 while (Entry2 != &DiskEntry->PartListHead)
1872 {
1873 PartEntry = CONTAINING_RECORD (Entry2,
1874 PARTENTRY,
1875 ListEntry);
1876 if (PartEntry->Unpartitioned == FALSE)
1877 {
1878 PartitionCount += 4;
1879 }
1880
1881 Entry2 = Entry2->Flink;
1882 }
1883
1884 if (PartitionCount > 0)
1885 {
1886 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
1887 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
1888 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
1889 0,
1890 DriveLayoutSize);
1891 if (DriveLayout == NULL)
1892 {
1893 DPRINT1 ("RtlAllocateHeap() failed\n");
1894 return FALSE;
1895 }
1896
1897 RtlZeroMemory (DriveLayout,
1898 DriveLayoutSize);
1899
1900 DriveLayout->PartitionCount = PartitionCount;
1901
1902 Index = 0;
1903 Entry2 = DiskEntry->PartListHead.Flink;
1904 while (Entry2 != &DiskEntry->PartListHead)
1905 {
1906 PartEntry = CONTAINING_RECORD (Entry2,
1907 PARTENTRY,
1908 ListEntry);
1909 if (PartEntry->Unpartitioned == FALSE)
1910 {
1911 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
1912 &PartEntry->PartInfo[0],
1913 4 * sizeof (PARTITION_INFORMATION));
1914 Index += 4;
1915 }
1916
1917 Entry2 = Entry2->Flink;
1918 }
1919
1920 swprintf (DstPath,
1921 L"\\Device\\Harddisk%d\\Partition0",
1922 DiskEntry->DiskNumber);
1923 RtlInitUnicodeString (&Name,
1924 DstPath);
1925 InitializeObjectAttributes (&ObjectAttributes,
1926 &Name,
1927 0,
1928 NULL,
1929 NULL);
1930
1931 Status = NtOpenFile (&FileHandle,
1932 FILE_ALL_ACCESS,
1933 &ObjectAttributes,
1934 &Iosb,
1935 0,
1936 FILE_SYNCHRONOUS_IO_NONALERT);
1937 if (!NT_SUCCESS (Status))
1938 {
1939 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
1940 return FALSE;
1941 }
1942
1943 Status = NtDeviceIoControlFile (FileHandle,
1944 NULL,
1945 NULL,
1946 NULL,
1947 &Iosb,
1948 IOCTL_DISK_SET_DRIVE_LAYOUT,
1949 DriveLayout,
1950 DriveLayoutSize,
1951 NULL,
1952 0);
1953 if (!NT_SUCCESS (Status))
1954 {
1955 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
1956 NtClose (FileHandle);
1957 return FALSE;
1958 }
1959
1960 RtlFreeHeap (ProcessHeap,
1961 0,
1962 DriveLayout);
1963
1964 NtClose (FileHandle);
1965
1966 /* Install MBR code if the disk is new */
1967 if (DiskEntry->NewDisk == TRUE)
1968 {
1969 wcscpy (SrcPath, SourceRootPath.Buffer);
1970 wcscat (SrcPath, L"\\loader\\dosmbr.bin");
1971
1972 DPRINT1 ("Install MBR bootcode: %S ==> %S\n",
1973 SrcPath, DstPath);
1974
1975 /* Install MBR bootcode */
1976 Status = InstallMbrBootCodeToDisk (SrcPath,
1977 DstPath);
1978 if (!NT_SUCCESS (Status))
1979 {
1980 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
1981 Status);
1982 return FALSE;
1983 }
1984
1985 DiskEntry->NewDisk = FALSE;
1986 }
1987 }
1988 }
1989
1990 Entry1 = Entry1->Flink;
1991 }
1992
1993 return TRUE;
1994 }
1995
1996 /* EOF */