2003-10-06 Casper S. Hornstrup <chorns@users.sourceforge.net>
[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.24 2003/10/06 19:22:42 chorns 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 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1084 {
1085 PDISKENTRY DiskEntry;
1086 PPARTENTRY PartEntry;
1087 PLIST_ENTRY Entry1;
1088 PLIST_ENTRY Entry2;
1089 ULONG i;
1090
1091 /* Check for empty disks */
1092 if (IsListEmpty (&List->DiskListHead))
1093 return;
1094
1095 /* Check for first usable entry on next disk */
1096 Entry1 = List->CurrentDisk->ListEntry.Flink;
1097 while (Entry1 != &List->DiskListHead)
1098 {
1099 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1100
1101 if (DiskEntry->DiskNumber == DiskNumber)
1102 {
1103 Entry2 = DiskEntry->PartListHead.Flink;
1104 while (Entry2 != &DiskEntry->PartListHead)
1105 {
1106 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1107
1108 for (i = 0; i < 4; i++)
1109 {
1110 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1111 {
1112 List->CurrentDisk = DiskEntry;
1113 List->CurrentPartition = PartEntry;
1114 DrawPartitionList (List);
1115 return;
1116 }
1117 }
1118 Entry2 = Entry2->Flink;
1119 }
1120 return;
1121 }
1122 Entry1 = Entry1->Flink;
1123 }
1124 }
1125
1126
1127 VOID
1128 ScrollDownPartitionList (PPARTLIST List)
1129 {
1130 PDISKENTRY DiskEntry;
1131 PPARTENTRY PartEntry;
1132 PLIST_ENTRY Entry1;
1133 PLIST_ENTRY Entry2;
1134
1135 /* Check for empty disks */
1136 if (IsListEmpty (&List->DiskListHead))
1137 return;
1138
1139 /* Check for next usable entry on current disk */
1140 if (List->CurrentPartition != NULL)
1141 {
1142 Entry2 = List->CurrentPartition->ListEntry.Flink;
1143 while (Entry2 != &List->CurrentDisk->PartListHead)
1144 {
1145 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1146
1147 // if (PartEntry->HidePartEntry == FALSE)
1148 {
1149 List->CurrentPartition = PartEntry;
1150 DrawPartitionList (List);
1151 return;
1152 }
1153 Entry2 = Entry2->Flink;
1154 }
1155 }
1156
1157 /* Check for first usable entry on next disk */
1158 if (List->CurrentDisk != NULL)
1159 {
1160 Entry1 = List->CurrentDisk->ListEntry.Flink;
1161 while (Entry1 != &List->DiskListHead)
1162 {
1163 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1164
1165 Entry2 = DiskEntry->PartListHead.Flink;
1166 while (Entry2 != &DiskEntry->PartListHead)
1167 {
1168 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1169
1170 // if (PartEntry->HidePartEntry == FALSE)
1171 {
1172 List->CurrentDisk = DiskEntry;
1173 List->CurrentPartition = PartEntry;
1174 DrawPartitionList (List);
1175 return;
1176 }
1177
1178 Entry2 = Entry2->Flink;
1179 }
1180
1181 Entry1 = Entry1->Flink;
1182 }
1183 }
1184 }
1185
1186
1187 VOID
1188 ScrollUpPartitionList (PPARTLIST List)
1189 {
1190 PDISKENTRY DiskEntry;
1191 PPARTENTRY PartEntry;
1192 PLIST_ENTRY Entry1;
1193 PLIST_ENTRY Entry2;
1194 ULONG i;
1195
1196 /* Check for empty disks */
1197 if (IsListEmpty (&List->DiskListHead))
1198 return;
1199
1200 /* check for previous usable entry on current disk */
1201 if (List->CurrentPartition != NULL)
1202 {
1203 Entry2 = List->CurrentPartition->ListEntry.Blink;
1204 while (Entry2 != &List->CurrentDisk->PartListHead)
1205 {
1206 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1207
1208 // if (PartEntry->HidePartEntry == FALSE)
1209 {
1210 List->CurrentPartition = PartEntry;
1211 DrawPartitionList (List);
1212 return;
1213 }
1214 Entry2 = Entry2->Blink;
1215 }
1216 }
1217
1218
1219 /* check for last usable entry on previous disk */
1220 if (List->CurrentDisk != NULL)
1221 {
1222 Entry1 = List->CurrentDisk->ListEntry.Blink;
1223 while (Entry1 != &List->DiskListHead)
1224 {
1225 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1226
1227 Entry2 = DiskEntry->PartListHead.Blink;
1228 while (Entry2 != &DiskEntry->PartListHead)
1229 {
1230 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1231
1232 // if (PartEntry->HidePartEntry == FALSE)
1233 {
1234 List->CurrentDisk = DiskEntry;
1235 List->CurrentPartition = PartEntry;
1236 DrawPartitionList (List);
1237 return;
1238 }
1239
1240 Entry2 = Entry2->Blink;
1241 }
1242
1243 Entry1 = Entry1->Blink;
1244 }
1245 }
1246 }
1247
1248
1249 static PPARTENTRY
1250 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1251 PPARTENTRY CurrentEntry)
1252 {
1253 PPARTENTRY PrevEntry;
1254 PLIST_ENTRY Entry;
1255
1256 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1257 return NULL;
1258
1259 Entry = CurrentEntry->ListEntry.Blink;
1260 while (Entry != &DiskEntry->PartListHead)
1261 {
1262 PrevEntry = CONTAINING_RECORD (Entry,
1263 PARTENTRY,
1264 ListEntry);
1265 if (PrevEntry->Unpartitioned == FALSE)
1266 return PrevEntry;
1267
1268 Entry = Entry->Blink;
1269 }
1270
1271 return NULL;
1272 }
1273
1274
1275 static PPARTENTRY
1276 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1277 PPARTENTRY CurrentEntry)
1278 {
1279 PPARTENTRY NextEntry;
1280 PLIST_ENTRY Entry;
1281
1282 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1283 return NULL;
1284
1285 Entry = CurrentEntry->ListEntry.Flink;
1286 while (Entry != &DiskEntry->PartListHead)
1287 {
1288 NextEntry = CONTAINING_RECORD (Entry,
1289 PARTENTRY,
1290 ListEntry);
1291 if (NextEntry->Unpartitioned == FALSE)
1292 return NextEntry;
1293
1294 Entry = Entry->Flink;
1295 }
1296
1297 return NULL;
1298 }
1299
1300
1301 static PPARTENTRY
1302 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1303 PPARTENTRY PartEntry)
1304 {
1305 PPARTENTRY PrevPartEntry;
1306
1307 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1308 {
1309 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1310 PARTENTRY,
1311 ListEntry);
1312 if (PrevPartEntry->Unpartitioned == TRUE)
1313 return PrevPartEntry;
1314 }
1315
1316 return NULL;
1317 }
1318
1319
1320 static PPARTENTRY
1321 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1322 PPARTENTRY PartEntry)
1323 {
1324 PPARTENTRY NextPartEntry;
1325
1326 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1327 {
1328 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1329 PARTENTRY,
1330 ListEntry);
1331 if (NextPartEntry->Unpartitioned == TRUE)
1332 return NextPartEntry;
1333 }
1334
1335 return NULL;
1336 }
1337
1338
1339 VOID
1340 CreateNewPartition (PPARTLIST List,
1341 ULONGLONG PartitionSize,
1342 BOOLEAN AutoCreate)
1343 {
1344 PDISKENTRY DiskEntry;
1345 PPARTENTRY PartEntry;
1346 PPARTENTRY PrevPartEntry;
1347 PPARTENTRY NextPartEntry;
1348 PPARTENTRY NewPartEntry;
1349
1350 if (List == NULL ||
1351 List->CurrentDisk == NULL ||
1352 List->CurrentPartition == NULL ||
1353 List->CurrentPartition->Unpartitioned == FALSE)
1354 {
1355 return;
1356 }
1357
1358 DiskEntry = List->CurrentDisk;
1359 PartEntry = List->CurrentPartition;
1360
1361 if (AutoCreate == TRUE ||
1362 PartitionSize == PartEntry->UnpartitionedLength)
1363 {
1364 /* Convert current entry to 'new (unformatted)' */
1365 PartEntry->FormatState = Unformatted;
1366 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1367 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1368 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1369 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1370 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1371 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1372 PartEntry->PartInfo[0].RewritePartition = TRUE;
1373 PartEntry->PartInfo[1].RewritePartition = TRUE;
1374 PartEntry->PartInfo[2].RewritePartition = TRUE;
1375 PartEntry->PartInfo[3].RewritePartition = TRUE;
1376
1377 /* Get previous and next partition entries */
1378 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1379 PartEntry);
1380 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1381 PartEntry);
1382
1383 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1384 {
1385 /* Current entry is in the middle of the list */
1386
1387 /* Copy previous container partition data to current entry */
1388 RtlCopyMemory (&PartEntry->PartInfo[1],
1389 &PrevPartEntry->PartInfo[1],
1390 sizeof(PARTITION_INFORMATION));
1391 PartEntry->PartInfo[1].RewritePartition = TRUE;
1392
1393 /* Update previous container partition data */
1394
1395 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1396 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1397
1398 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1399 {
1400 /* Special case - previous partition is first partition */
1401 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1402 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1403 }
1404 else
1405 {
1406 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1407 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1408 }
1409
1410 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1411 }
1412 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1413 {
1414 /* Current entry is the first entry */
1415 return;
1416 }
1417 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1418 {
1419 /* Current entry is the last entry */
1420
1421 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1422 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1423
1424 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1425 {
1426 /* Special case - previous partition is first partition */
1427 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1428 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1429 }
1430 else
1431 {
1432 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1433 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1434 }
1435
1436 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1437 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1438 (1024ULL * 255ULL * 63ULL * 512ULL))
1439 {
1440 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1441 }
1442 else
1443 {
1444 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1445 }
1446
1447 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1448 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1449 }
1450
1451 PartEntry->AutoCreate = AutoCreate;
1452 PartEntry->New = TRUE;
1453 PartEntry->Unpartitioned = FALSE;
1454 PartEntry->UnpartitionedOffset = 0ULL;
1455 PartEntry->UnpartitionedLength = 0ULL;
1456 }
1457 else
1458 {
1459 /* Insert an initialize a new partition entry */
1460 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1461 0,
1462 sizeof(PARTENTRY));
1463 if (NewPartEntry == NULL)
1464 return;
1465
1466 RtlZeroMemory (NewPartEntry,
1467 sizeof(PARTENTRY));
1468
1469 /* Insert the new entry into the list */
1470 InsertTailList (&PartEntry->ListEntry,
1471 &NewPartEntry->ListEntry);
1472
1473 NewPartEntry->New = TRUE;
1474
1475 NewPartEntry->FormatState = Unformatted;
1476 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1477 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1478 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1479 PartitionSize - DiskEntry->TrackSize;
1480 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1481 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1482 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1483 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1484 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1485 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1486
1487 /* Get previous and next partition entries */
1488 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1489 NewPartEntry);
1490 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1491 NewPartEntry);
1492
1493 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1494 {
1495 /* Current entry is in the middle of the list */
1496
1497 /* Copy previous container partition data to current entry */
1498 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1499 &PrevPartEntry->PartInfo[1],
1500 sizeof(PARTITION_INFORMATION));
1501 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1502
1503 /* Update previous container partition data */
1504
1505 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1506 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1507
1508 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1509 {
1510 /* Special case - previous partition is first partition */
1511 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1512 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1513 }
1514 else
1515 {
1516 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1517 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1518 }
1519
1520 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1521 }
1522 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1523 {
1524 /* Current entry is the first entry */
1525 return;
1526 }
1527 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1528 {
1529 /* Current entry is the last entry */
1530
1531 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1532 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1533
1534 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1535 {
1536 /* Special case - previous partition is first partition */
1537 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1538 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1539 }
1540 else
1541 {
1542 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1543 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1544 }
1545
1546 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1547 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1548 (1024ULL * 255ULL * 63ULL * 512ULL))
1549 {
1550 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1551 }
1552 else
1553 {
1554 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1555 }
1556
1557 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1558 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1559 }
1560
1561 /* Update offset and size of the remaining unpartitioned disk space */
1562 PartEntry->UnpartitionedOffset += PartitionSize;
1563 PartEntry->UnpartitionedLength -= PartitionSize;
1564 }
1565
1566 DiskEntry->Modified = TRUE;
1567
1568 UpdatePartitionNumbers (DiskEntry);
1569
1570 AssignDriverLetters (List);
1571 }
1572
1573
1574 VOID
1575 DeleteCurrentPartition (PPARTLIST List)
1576 {
1577 PDISKENTRY DiskEntry;
1578 PPARTENTRY PartEntry;
1579 PPARTENTRY PrevPartEntry;
1580 PPARTENTRY NextPartEntry;
1581
1582 if (List == NULL ||
1583 List->CurrentDisk == NULL ||
1584 List->CurrentPartition == NULL ||
1585 List->CurrentPartition->Unpartitioned == TRUE)
1586 {
1587 return;
1588 }
1589
1590 DiskEntry = List->CurrentDisk;
1591 PartEntry = List->CurrentPartition;
1592
1593 /* Adjust container partition entries */
1594
1595 /* Get previous and next partition entries */
1596 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1597 PartEntry);
1598 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1599 PartEntry);
1600
1601 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1602 {
1603 /* Current entry is in the middle of the list */
1604
1605 /*
1606 * The first extended partition can not be deleted
1607 * as long as other extended partitions are present.
1608 */
1609 if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1610 return;
1611
1612 /* Copy previous container partition data to current entry */
1613 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
1614 &PartEntry->PartInfo[1],
1615 sizeof(PARTITION_INFORMATION));
1616 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1617 }
1618 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1619 {
1620 /*
1621 * A primary partition can not be deleted as long as
1622 * extended partitions are present.
1623 */
1624 return;
1625 }
1626 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1627 {
1628 /* Current entry is the last entry */
1629 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
1630 sizeof(PARTITION_INFORMATION));
1631 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1632 }
1633
1634
1635 /* Adjust unpartitioned disk space entries */
1636
1637 /* Get pointer to previous and next unpartitioned entries */
1638 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
1639 PartEntry);
1640
1641 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
1642 PartEntry);
1643
1644 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1645 {
1646 /* Merge previous, current and next unpartitioned entry */
1647
1648 /* Adjust the previous entries length */
1649 PrevPartEntry->UnpartitionedLength +=
1650 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
1651 NextPartEntry->UnpartitionedLength);
1652
1653 /* Remove the current entry */
1654 RemoveEntryList (&PartEntry->ListEntry);
1655 RtlFreeHeap (ProcessHeap,
1656 0,
1657 PartEntry);
1658
1659 /* Remove the next entry */
1660 RemoveEntryList (&NextPartEntry->ListEntry);
1661 RtlFreeHeap (ProcessHeap,
1662 0,
1663 NextPartEntry);
1664
1665 /* Update current partition */
1666 List->CurrentPartition = PrevPartEntry;
1667 }
1668 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1669 {
1670 /* Merge current and previous unpartitioned entry */
1671
1672 /* Adjust the previous entries length */
1673 PrevPartEntry->UnpartitionedLength +=
1674 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1675
1676 /* Remove the current entry */
1677 RemoveEntryList (&PartEntry->ListEntry);
1678 RtlFreeHeap (ProcessHeap,
1679 0,
1680 PartEntry);
1681
1682 /* Update current partition */
1683 List->CurrentPartition = PrevPartEntry;
1684 }
1685 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1686 {
1687 /* Merge current and next unpartitioned entry */
1688
1689 /* Adjust the next entries offset and length */
1690 NextPartEntry->UnpartitionedOffset =
1691 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1692 NextPartEntry->UnpartitionedLength +=
1693 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1694
1695 /* Remove the current entry */
1696 RemoveEntryList (&PartEntry->ListEntry);
1697 RtlFreeHeap (ProcessHeap,
1698 0,
1699 PartEntry);
1700
1701 /* Update current partition */
1702 List->CurrentPartition = NextPartEntry;
1703 }
1704 else
1705 {
1706 /* Nothing to merge but change current entry */
1707 PartEntry->New = FALSE;
1708 PartEntry->Unpartitioned = TRUE;
1709 PartEntry->UnpartitionedOffset =
1710 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1711 PartEntry->UnpartitionedLength =
1712 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1713
1714 /* Wipe the partition table */
1715 RtlZeroMemory (&PartEntry->PartInfo,
1716 sizeof(PartEntry->PartInfo));
1717 }
1718
1719 DiskEntry->Modified = TRUE;
1720
1721 UpdatePartitionNumbers (DiskEntry);
1722
1723 AssignDriverLetters (List);
1724 }
1725
1726
1727 VOID
1728 CheckActiveBootPartition (PPARTLIST List)
1729 {
1730 PDISKENTRY DiskEntry;
1731 PPARTENTRY PartEntry;
1732
1733 /* Check for empty disk list */
1734 if (IsListEmpty (&List->DiskListHead))
1735 {
1736 List->ActiveBootDisk = NULL;
1737 List->ActiveBootPartition = NULL;
1738 return;
1739 }
1740
1741 #if 0
1742 if (List->ActiveBootDisk != NULL &&
1743 List->ActiveBootPartition != NULL)
1744 {
1745 /* We already have an active boot partition */
1746 return;
1747 }
1748 #endif
1749
1750 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
1751 DISKENTRY,
1752 ListEntry);
1753
1754 /* Check for empty partition list */
1755 if (IsListEmpty (&DiskEntry->PartListHead))
1756 {
1757 List->ActiveBootDisk = NULL;
1758 List->ActiveBootPartition = NULL;
1759 return;
1760 }
1761
1762 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
1763 PARTENTRY,
1764 ListEntry);
1765
1766 /* Set active boot partition */
1767 if ((DiskEntry->NewDisk == TRUE) ||
1768 (PartEntry->PartInfo[0].BootIndicator == FALSE &&
1769 PartEntry->PartInfo[1].BootIndicator == FALSE &&
1770 PartEntry->PartInfo[2].BootIndicator == FALSE &&
1771 PartEntry->PartInfo[3].BootIndicator == FALSE))
1772 {
1773 PartEntry->PartInfo[0].BootIndicator = TRUE;
1774 PartEntry->PartInfo[0].RewritePartition = TRUE;
1775 DiskEntry->Modified = TRUE;
1776 }
1777
1778 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
1779 List->ActiveBootDisk = DiskEntry;
1780 List->ActiveBootPartition = PartEntry;
1781 }
1782
1783
1784 BOOLEAN
1785 CheckForLinuxFdiskPartitions (PPARTLIST List)
1786 {
1787 PDISKENTRY DiskEntry;
1788 PPARTENTRY PartEntry;
1789 PLIST_ENTRY Entry1;
1790 PLIST_ENTRY Entry2;
1791 ULONG PartitionCount;
1792 ULONG i;
1793
1794 Entry1 = List->DiskListHead.Flink;
1795 while (Entry1 != &List->DiskListHead)
1796 {
1797 DiskEntry = CONTAINING_RECORD (Entry1,
1798 DISKENTRY,
1799 ListEntry);
1800
1801 Entry2 = DiskEntry->PartListHead.Flink;
1802 while (Entry2 != &DiskEntry->PartListHead)
1803 {
1804 PartEntry = CONTAINING_RECORD (Entry2,
1805 PARTENTRY,
1806 ListEntry);
1807
1808 if (PartEntry->Unpartitioned == FALSE)
1809 {
1810 PartitionCount = 0;
1811
1812 for (i = 0; i < 4; i++)
1813 {
1814 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
1815 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
1816 {
1817 PartitionCount++;
1818 }
1819 }
1820
1821 if (PartitionCount > 1)
1822 {
1823 return TRUE;
1824 }
1825 }
1826
1827 Entry2 = Entry2->Flink;
1828 }
1829
1830 Entry1 = Entry1->Flink;
1831 }
1832
1833 return FALSE;
1834 }
1835
1836
1837 BOOLEAN
1838 WritePartitionsToDisk (PPARTLIST List)
1839 {
1840 PDRIVE_LAYOUT_INFORMATION DriveLayout;
1841 OBJECT_ATTRIBUTES ObjectAttributes;
1842 IO_STATUS_BLOCK Iosb;
1843 WCHAR SrcPath[MAX_PATH];
1844 WCHAR DstPath[MAX_PATH];
1845 UNICODE_STRING Name;
1846 HANDLE FileHandle;
1847 PDISKENTRY DiskEntry;
1848 PPARTENTRY PartEntry;
1849 PLIST_ENTRY Entry1;
1850 PLIST_ENTRY Entry2;
1851 ULONG PartitionCount;
1852 ULONG DriveLayoutSize;
1853 ULONG Index;
1854 NTSTATUS Status;
1855
1856 if (List == NULL)
1857 {
1858 return TRUE;
1859 }
1860
1861 Entry1 = List->DiskListHead.Flink;
1862 while (Entry1 != &List->DiskListHead)
1863 {
1864 DiskEntry = CONTAINING_RECORD (Entry1,
1865 DISKENTRY,
1866 ListEntry);
1867
1868 if (DiskEntry->Modified == TRUE)
1869 {
1870 /* Count partitioned entries */
1871 PartitionCount = 0;
1872 Entry2 = DiskEntry->PartListHead.Flink;
1873 while (Entry2 != &DiskEntry->PartListHead)
1874 {
1875 PartEntry = CONTAINING_RECORD (Entry2,
1876 PARTENTRY,
1877 ListEntry);
1878 if (PartEntry->Unpartitioned == FALSE)
1879 {
1880 PartitionCount += 4;
1881 }
1882
1883 Entry2 = Entry2->Flink;
1884 }
1885
1886 if (PartitionCount > 0)
1887 {
1888 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
1889 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
1890 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
1891 0,
1892 DriveLayoutSize);
1893 if (DriveLayout == NULL)
1894 {
1895 DPRINT1 ("RtlAllocateHeap() failed\n");
1896 return FALSE;
1897 }
1898
1899 RtlZeroMemory (DriveLayout,
1900 DriveLayoutSize);
1901
1902 DriveLayout->PartitionCount = PartitionCount;
1903
1904 Index = 0;
1905 Entry2 = DiskEntry->PartListHead.Flink;
1906 while (Entry2 != &DiskEntry->PartListHead)
1907 {
1908 PartEntry = CONTAINING_RECORD (Entry2,
1909 PARTENTRY,
1910 ListEntry);
1911 if (PartEntry->Unpartitioned == FALSE)
1912 {
1913 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
1914 &PartEntry->PartInfo[0],
1915 4 * sizeof (PARTITION_INFORMATION));
1916 Index += 4;
1917 }
1918
1919 Entry2 = Entry2->Flink;
1920 }
1921
1922 swprintf (DstPath,
1923 L"\\Device\\Harddisk%d\\Partition0",
1924 DiskEntry->DiskNumber);
1925 RtlInitUnicodeString (&Name,
1926 DstPath);
1927 InitializeObjectAttributes (&ObjectAttributes,
1928 &Name,
1929 0,
1930 NULL,
1931 NULL);
1932
1933 Status = NtOpenFile (&FileHandle,
1934 FILE_ALL_ACCESS,
1935 &ObjectAttributes,
1936 &Iosb,
1937 0,
1938 FILE_SYNCHRONOUS_IO_NONALERT);
1939 if (!NT_SUCCESS (Status))
1940 {
1941 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
1942 return FALSE;
1943 }
1944
1945 Status = NtDeviceIoControlFile (FileHandle,
1946 NULL,
1947 NULL,
1948 NULL,
1949 &Iosb,
1950 IOCTL_DISK_SET_DRIVE_LAYOUT,
1951 DriveLayout,
1952 DriveLayoutSize,
1953 NULL,
1954 0);
1955 if (!NT_SUCCESS (Status))
1956 {
1957 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
1958 NtClose (FileHandle);
1959 return FALSE;
1960 }
1961
1962 RtlFreeHeap (ProcessHeap,
1963 0,
1964 DriveLayout);
1965
1966 NtClose (FileHandle);
1967
1968 /* Install MBR code if the disk is new */
1969 if (DiskEntry->NewDisk == TRUE)
1970 {
1971 wcscpy (SrcPath, SourceRootPath.Buffer);
1972 wcscat (SrcPath, L"\\loader\\dosmbr.bin");
1973
1974 DPRINT1 ("Install MBR bootcode: %S ==> %S\n",
1975 SrcPath, DstPath);
1976
1977 /* Install MBR bootcode */
1978 Status = InstallMbrBootCodeToDisk (SrcPath,
1979 DstPath);
1980 if (!NT_SUCCESS (Status))
1981 {
1982 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
1983 Status);
1984 return FALSE;
1985 }
1986
1987 DiskEntry->NewDisk = FALSE;
1988 }
1989 }
1990 }
1991
1992 Entry1 = Entry1->Flink;
1993 }
1994
1995 return TRUE;
1996 }
1997
1998 /* EOF */