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