* Write modified partition sectors to disk.
[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.18 2003/08/18 17:39:26 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 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
224 0,
225 sizeof(PARTENTRY));
226 if (PartEntry == NULL)
227 {
228 return;
229 }
230
231 RtlZeroMemory (PartEntry,
232 sizeof(PARTENTRY));
233
234 PartEntry->Unpartitioned = FALSE;
235
236 for (j = 0; j < 4; j++)
237 {
238 RtlCopyMemory (&PartEntry->PartInfo[j],
239 &LayoutBuffer->PartitionEntry[i+j],
240 sizeof(PARTITION_INFORMATION));
241 }
242
243 InsertTailList (&DiskEntry->PartListHead,
244 &PartEntry->ListEntry);
245 }
246 }
247
248
249 static VOID
250 ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
251 {
252 ULONGLONG LastStartingOffset;
253 ULONGLONG LastPartitionLength;
254 ULONGLONG LastUnusedPartitionLength;
255 PPARTENTRY PartEntry;
256 PPARTENTRY NewPartEntry;
257 PLIST_ENTRY Entry;
258 ULONG i;
259 ULONG j;
260
261 if (IsListEmpty (&DiskEntry->PartListHead))
262 {
263 /* Create a partition table that represents the empty disk */
264 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
265 0,
266 sizeof(PARTENTRY));
267 if (PartEntry == NULL)
268 return;
269
270 RtlZeroMemory (PartEntry,
271 sizeof(PARTENTRY));
272
273 PartEntry->Unpartitioned = TRUE;
274 PartEntry->UnpartitionedOffset = 0ULL;
275 PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
276
277 InsertTailList (&DiskEntry->PartListHead,
278 &PartEntry->ListEntry);
279 }
280 else
281 {
282 /* Start partition at head 1, cylinder 0 */
283 LastStartingOffset = DiskEntry->TrackSize;
284 LastPartitionLength = 0ULL;
285 LastUnusedPartitionLength = 0ULL;
286
287 i = 0;
288 Entry = DiskEntry->PartListHead.Flink;
289 while (Entry != &DiskEntry->PartListHead)
290 {
291 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
292
293 for (j = 0; j < 4; j++)
294 {
295 if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
296 (PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
297 PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
298 {
299 LastUnusedPartitionLength =
300 PartEntry->PartInfo[j].StartingOffset.QuadPart -
301 (LastStartingOffset + LastPartitionLength);
302
303 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
304 {
305 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
306
307 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
308 0,
309 sizeof(PARTENTRY));
310 if (NewPartEntry == NULL)
311 return;
312
313 RtlZeroMemory (NewPartEntry,
314 sizeof(PARTENTRY));
315
316 NewPartEntry->Unpartitioned = TRUE;
317 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
318 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
319 if (j == 0)
320 NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
321
322 /* Insert the table into the list */
323 InsertTailList (&PartEntry->ListEntry,
324 &NewPartEntry->ListEntry);
325 }
326
327 LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
328 LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
329 }
330 }
331
332 i += 4;
333 Entry = Entry->Flink;
334 }
335
336 /* Check for trailing unpartitioned disk space */
337 if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
338 {
339 /* Round-down to cylinder size */
340 LastUnusedPartitionLength =
341 ROUND_DOWN (DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength),
342 DiskEntry->CylinderSize);
343
344 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
345 {
346 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
347
348 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
349 0,
350 sizeof(PARTENTRY));
351 if (NewPartEntry == NULL)
352 return;
353
354 RtlZeroMemory (NewPartEntry,
355 sizeof(PARTENTRY));
356
357 NewPartEntry->Unpartitioned = TRUE;
358 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
359 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
360
361 /* Append the table to the list */
362 InsertTailList (&DiskEntry->PartListHead,
363 &NewPartEntry->ListEntry);
364 }
365 }
366 }
367 }
368
369
370 static VOID
371 AddDiskToList (HANDLE FileHandle,
372 ULONG DiskNumber,
373 PPARTLIST List)
374 {
375 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
376 DISK_GEOMETRY DiskGeometry;
377 SCSI_ADDRESS ScsiAddress;
378 PDISKENTRY DiskEntry;
379 IO_STATUS_BLOCK Iosb;
380 NTSTATUS Status;
381
382 Status = NtDeviceIoControlFile (FileHandle,
383 NULL,
384 NULL,
385 NULL,
386 &Iosb,
387 IOCTL_DISK_GET_DRIVE_GEOMETRY,
388 NULL,
389 0,
390 &DiskGeometry,
391 sizeof(DISK_GEOMETRY));
392 if (!NT_SUCCESS (Status))
393 {
394 return;
395 }
396
397 if (DiskGeometry.MediaType != FixedMedia)
398 {
399 return;
400 }
401
402 Status = NtDeviceIoControlFile (FileHandle,
403 NULL,
404 NULL,
405 NULL,
406 &Iosb,
407 IOCTL_SCSI_GET_ADDRESS,
408 NULL,
409 0,
410 &ScsiAddress,
411 sizeof(SCSI_ADDRESS));
412 if (!NT_SUCCESS(Status))
413 {
414 return;
415 }
416
417 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
418 0,
419 sizeof(DISKENTRY));
420 if (DiskEntry == NULL)
421 {
422 return;
423 }
424
425 InitializeListHead (&DiskEntry->PartListHead);
426
427 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
428 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
429 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
430 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
431
432 DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
433 DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
434 DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
435 DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
436
437 DiskEntry->DiskSize =
438 DiskGeometry.Cylinders.QuadPart *
439 (ULONGLONG)DiskGeometry.TracksPerCylinder *
440 (ULONGLONG)DiskGeometry.SectorsPerTrack *
441 (ULONGLONG)DiskGeometry.BytesPerSector;
442 DiskEntry->CylinderSize =
443 (ULONGLONG)DiskGeometry.TracksPerCylinder *
444 (ULONGLONG)DiskGeometry.SectorsPerTrack *
445 (ULONGLONG)DiskGeometry.BytesPerSector;
446 DiskEntry->TrackSize =
447 (ULONGLONG)DiskGeometry.SectorsPerTrack *
448 (ULONGLONG)DiskGeometry.BytesPerSector;
449
450 DiskEntry->DiskNumber = DiskNumber;
451 DiskEntry->Port = ScsiAddress.PortNumber;
452 DiskEntry->Bus = ScsiAddress.PathId;
453 DiskEntry->Id = ScsiAddress.TargetId;
454
455 DiskEntry->UseLba = (DiskEntry->DiskSize > (1024ULL * 255ULL * 63ULL * 512ULL));
456
457 GetDriverName (DiskEntry);
458
459 InsertTailList (&List->DiskListHead,
460 &DiskEntry->ListEntry);
461
462 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
463 0,
464 8192);
465 if (LayoutBuffer == NULL)
466 {
467 return;
468 }
469
470 Status = NtDeviceIoControlFile (FileHandle,
471 NULL,
472 NULL,
473 NULL,
474 &Iosb,
475 IOCTL_DISK_GET_DRIVE_LAYOUT,
476 NULL,
477 0,
478 LayoutBuffer,
479 8192);
480 if (NT_SUCCESS (Status))
481 {
482 AddPartitionToList (DiskNumber,
483 DiskEntry,
484 LayoutBuffer);
485
486 ScanForUnpartitionedDiskSpace (DiskEntry);
487 }
488
489 RtlFreeHeap (ProcessHeap,
490 0,
491 LayoutBuffer);
492 }
493
494
495 PPARTLIST
496 CreatePartitionList (SHORT Left,
497 SHORT Top,
498 SHORT Right,
499 SHORT Bottom)
500 {
501 PPARTLIST List;
502 OBJECT_ATTRIBUTES ObjectAttributes;
503 SYSTEM_DEVICE_INFORMATION Sdi;
504 DISK_GEOMETRY DiskGeometry;
505 IO_STATUS_BLOCK Iosb;
506 ULONG ReturnSize;
507 NTSTATUS Status;
508 ULONG DiskNumber;
509 WCHAR Buffer[MAX_PATH];
510 UNICODE_STRING Name;
511 HANDLE FileHandle;
512
513 List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
514 0,
515 sizeof (PARTLIST));
516 if (List == NULL)
517 return NULL;
518
519 List->Left = Left;
520 List->Top = Top;
521 List->Right = Right;
522 List->Bottom = Bottom;
523
524 List->Line = 0;
525
526 List->TopDisk = (ULONG)-1;
527 List->TopPartition = (ULONG)-1;
528
529 List->CurrentDisk = NULL;
530 List->CurrentPartition = NULL;
531
532 InitializeListHead (&List->DiskListHead);
533
534 Status = NtQuerySystemInformation (SystemDeviceInformation,
535 &Sdi,
536 sizeof(SYSTEM_DEVICE_INFORMATION),
537 &ReturnSize);
538 if (!NT_SUCCESS (Status))
539 {
540 RtlFreeHeap (ProcessHeap, 0, List);
541 return NULL;
542 }
543
544 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
545 {
546 swprintf (Buffer,
547 L"\\Device\\Harddisk%d\\Partition0",
548 DiskNumber);
549 RtlInitUnicodeString (&Name,
550 Buffer);
551
552 InitializeObjectAttributes (&ObjectAttributes,
553 &Name,
554 0,
555 NULL,
556 NULL);
557
558 Status = NtOpenFile (&FileHandle,
559 FILE_GENERIC_READ,
560 &ObjectAttributes,
561 &Iosb,
562 FILE_SHARE_READ,
563 FILE_SYNCHRONOUS_IO_NONALERT);
564 if (NT_SUCCESS(Status))
565 {
566 AddDiskToList (FileHandle,
567 DiskNumber,
568 List);
569
570 NtClose(FileHandle);
571 }
572 }
573
574 AssignDriverLetters (List);
575
576 List->TopDisk = 0;
577 List->TopPartition = 0;
578
579 /* Search for first usable disk and partition */
580 if (IsListEmpty (&List->DiskListHead))
581 {
582 List->CurrentDisk = NULL;
583 List->CurrentPartition = NULL;
584 }
585 else
586 {
587 List->CurrentDisk =
588 CONTAINING_RECORD (List->DiskListHead.Flink,
589 DISKENTRY,
590 ListEntry);
591
592 if (IsListEmpty (&List->CurrentDisk->PartListHead))
593 {
594 List->CurrentPartition = 0;
595 }
596 else
597 {
598 List->CurrentPartition =
599 CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
600 PARTENTRY,
601 ListEntry);
602 }
603 }
604
605 return List;
606 }
607
608
609 VOID
610 DestroyPartitionList (PPARTLIST List)
611 {
612 PDISKENTRY DiskEntry;
613 PPARTENTRY PartEntry;
614 PLIST_ENTRY Entry;
615
616 /* Release disk and partition info */
617 while (!IsListEmpty (&List->DiskListHead))
618 {
619 Entry = RemoveHeadList (&List->DiskListHead);
620 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
621
622 /* Release driver name */
623 RtlFreeUnicodeString(&DiskEntry->DriverName);
624
625 /* Release partition array */
626 while (!IsListEmpty (&DiskEntry->PartListHead))
627 {
628 Entry = RemoveHeadList (&DiskEntry->PartListHead);
629 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
630
631 RtlFreeHeap (ProcessHeap,
632 0,
633 PartEntry);
634 }
635
636 /* Release disk entry */
637 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
638 }
639
640 /* Release list head */
641 RtlFreeHeap (ProcessHeap, 0, List);
642 }
643
644
645 static VOID
646 PrintEmptyLine (PPARTLIST List)
647 {
648 COORD coPos;
649 ULONG Written;
650 USHORT Width;
651 USHORT Height;
652
653 Width = List->Right - List->Left - 1;
654 Height = List->Bottom - List->Top - 1;
655
656 if (List->Line < 0 || List->Line > Height)
657 return;
658
659 coPos.X = List->Left + 1;
660 coPos.Y = List->Top + 1 + List->Line;
661
662 FillConsoleOutputAttribute (0x17,
663 Width,
664 coPos,
665 &Written);
666
667 FillConsoleOutputCharacter (' ',
668 Width,
669 coPos,
670 &Written);
671
672 List->Line++;
673 }
674
675
676 static VOID
677 PrintPartitionData (PPARTLIST List,
678 PDISKENTRY DiskEntry,
679 PPARTENTRY PartEntry)
680 {
681 CHAR LineBuffer[128];
682 COORD coPos;
683 ULONG Written;
684 USHORT Width;
685 USHORT Height;
686
687 ULONGLONG PartSize;
688 PCHAR Unit;
689 UCHAR Attribute;
690 PCHAR PartType;
691
692 Width = List->Right - List->Left - 1;
693 Height = List->Bottom - List->Top - 1;
694
695 if (List->Line < 0 || List->Line > Height)
696 return;
697
698 coPos.X = List->Left + 1;
699 coPos.Y = List->Top + 1 + List->Line;
700
701 if (PartEntry->Unpartitioned == TRUE)
702 {
703 #if 0
704 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
705 {
706 PartSize = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
707 Unit = "GB";
708 }
709 else
710 #endif
711 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
712 {
713 PartSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
714 Unit = "MB";
715 }
716 else
717 {
718 PartSize = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
719 Unit = "KB";
720 }
721
722 sprintf (LineBuffer,
723 " Unpartitioned space %6I64u %s",
724 PartSize,
725 Unit);
726 }
727 else
728 {
729 /* Determine partition type */
730 PartType = NULL;
731 if (PartEntry->New == TRUE)
732 {
733 PartType = "New (Unformatted)";
734 }
735 else if (PartEntry->Unpartitioned == FALSE)
736 {
737 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
738 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
739 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
740 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
741 {
742 PartType = "FAT";
743 }
744 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
745 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
746 {
747 PartType = "FAT32";
748 }
749 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
750 {
751 PartType = "NTFS"; /* FIXME: Not quite correct! */
752 }
753 }
754
755 #if 0
756 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000ULL) /* 10 GB */
757 {
758 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
759 Unit = "GB";
760 }
761 else
762 #endif
763 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000ULL) /* 10 MB */
764 {
765 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
766 Unit = "MB";
767 }
768 else
769 {
770 PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
771 Unit = "KB";
772 }
773
774 if (PartType == NULL)
775 {
776 sprintf (LineBuffer,
777 "%c%c Type %-3lu %6I64u %s",
778 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
779 (PartEntry->DriveLetter == 0) ? '-' : ':',
780 PartEntry->PartInfo[0].PartitionType,
781 PartSize,
782 Unit);
783 }
784 else
785 {
786 sprintf (LineBuffer,
787 "%c%c %-24s %6I64u %s",
788 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
789 (PartEntry->DriveLetter == 0) ? '-' : ':',
790 PartType,
791 PartSize,
792 Unit);
793 }
794 }
795
796 Attribute = (List->CurrentDisk == DiskEntry &&
797 List->CurrentPartition == PartEntry) ? 0x71 : 0x17;
798
799 FillConsoleOutputCharacter (' ',
800 Width,
801 coPos,
802 &Written);
803
804 coPos.X += 4;
805 Width -= 8;
806 FillConsoleOutputAttribute (Attribute,
807 Width,
808 coPos,
809 &Written);
810
811 coPos.X++;
812 Width -= 2;
813 WriteConsoleOutputCharacters (LineBuffer,
814 min (strlen (LineBuffer), Width),
815 coPos);
816
817 List->Line++;
818 }
819
820
821 static VOID
822 PrintDiskData (PPARTLIST List,
823 PDISKENTRY DiskEntry)
824 {
825 PPARTENTRY PartEntry;
826 PLIST_ENTRY Entry;
827 CHAR LineBuffer[128];
828 COORD coPos;
829 ULONG Written;
830 USHORT Width;
831 USHORT Height;
832 ULONGLONG DiskSize;
833 PCHAR Unit;
834 SHORT PartIndex;
835
836 Width = List->Right - List->Left - 1;
837 Height = List->Bottom - List->Top - 1;
838
839 if (List->Line < 0 || List->Line > Height)
840 return;
841
842 coPos.X = List->Left + 1;
843 coPos.Y = List->Top + 1 + List->Line;
844
845 #if 0
846 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
847 {
848 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
849 Unit = "GB";
850 }
851 else
852 #endif
853 {
854 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
855 if (DiskSize == 0)
856 DiskSize = 1;
857 Unit = "MB";
858 }
859
860 if (DiskEntry->DriverName.Length > 0)
861 {
862 sprintf (LineBuffer,
863 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
864 DiskSize,
865 Unit,
866 DiskEntry->DiskNumber,
867 DiskEntry->Port,
868 DiskEntry->Bus,
869 DiskEntry->Id,
870 &DiskEntry->DriverName);
871 }
872 else
873 {
874 sprintf (LineBuffer,
875 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
876 DiskSize,
877 Unit,
878 DiskEntry->DiskNumber,
879 DiskEntry->Port,
880 DiskEntry->Bus,
881 DiskEntry->Id);
882 }
883
884 FillConsoleOutputAttribute (0x17,
885 Width,
886 coPos,
887 &Written);
888
889 FillConsoleOutputCharacter (' ',
890 Width,
891 coPos,
892 &Written);
893
894 coPos.X++;
895 WriteConsoleOutputCharacters (LineBuffer,
896 min (strlen (LineBuffer), Width - 2),
897 coPos);
898
899 List->Line++;
900
901 /* Print separator line */
902 PrintEmptyLine (List);
903
904 /* Print partition lines*/
905 Entry = DiskEntry->PartListHead.Flink;
906 while (Entry != &DiskEntry->PartListHead)
907 {
908 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
909
910 /* Print disk entry */
911 PrintPartitionData (List,
912 DiskEntry,
913 PartEntry);
914
915 Entry = Entry->Flink;
916 }
917
918 /* Print separator line */
919 PrintEmptyLine (List);
920 }
921
922
923 VOID
924 DrawPartitionList (PPARTLIST List)
925 {
926 PLIST_ENTRY Entry;
927 PDISKENTRY DiskEntry;
928 CHAR LineBuffer[128];
929 COORD coPos;
930 ULONG Written;
931 SHORT i;
932 SHORT DiskIndex;
933
934 /* draw upper left corner */
935 coPos.X = List->Left;
936 coPos.Y = List->Top;
937 FillConsoleOutputCharacter (0xDA, // '+',
938 1,
939 coPos,
940 &Written);
941
942 /* draw upper edge */
943 coPos.X = List->Left + 1;
944 coPos.Y = List->Top;
945 FillConsoleOutputCharacter (0xC4, // '-',
946 List->Right - List->Left - 1,
947 coPos,
948 &Written);
949
950 /* draw upper right corner */
951 coPos.X = List->Right;
952 coPos.Y = List->Top;
953 FillConsoleOutputCharacter (0xBF, // '+',
954 1,
955 coPos,
956 &Written);
957
958 /* draw left and right edge */
959 for (i = List->Top + 1; i < List->Bottom; i++)
960 {
961 coPos.X = List->Left;
962 coPos.Y = i;
963 FillConsoleOutputCharacter (0xB3, // '|',
964 1,
965 coPos,
966 &Written);
967
968 coPos.X = List->Right;
969 FillConsoleOutputCharacter (0xB3, //'|',
970 1,
971 coPos,
972 &Written);
973 }
974
975 /* draw lower left corner */
976 coPos.X = List->Left;
977 coPos.Y = List->Bottom;
978 FillConsoleOutputCharacter (0xC0, // '+',
979 1,
980 coPos,
981 &Written);
982
983 /* draw lower edge */
984 coPos.X = List->Left + 1;
985 coPos.Y = List->Bottom;
986 FillConsoleOutputCharacter (0xC4, // '-',
987 List->Right - List->Left - 1,
988 coPos,
989 &Written);
990
991 /* draw lower right corner */
992 coPos.X = List->Right;
993 coPos.Y = List->Bottom;
994 FillConsoleOutputCharacter (0xD9, // '+',
995 1,
996 coPos,
997 &Written);
998
999 /* print list entries */
1000 List->Line = 0;
1001
1002 Entry = List->DiskListHead.Flink;
1003 while (Entry != &List->DiskListHead)
1004 {
1005 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1006
1007 /* Print disk entry */
1008 PrintDiskData (List,
1009 DiskEntry);
1010
1011 Entry = Entry->Flink;
1012 }
1013 }
1014
1015
1016 VOID
1017 ScrollDownPartitionList (PPARTLIST List)
1018 {
1019 PDISKENTRY DiskEntry;
1020 PPARTENTRY PartEntry;
1021 PLIST_ENTRY Entry1;
1022 PLIST_ENTRY Entry2;
1023
1024 /* Check for empty disks */
1025 if (IsListEmpty (&List->DiskListHead))
1026 return;
1027
1028 /* Check for next usable entry on current disk */
1029 if (List->CurrentPartition != NULL)
1030 {
1031 Entry2 = List->CurrentPartition->ListEntry.Flink;
1032 while (Entry2 != &List->CurrentDisk->PartListHead)
1033 {
1034 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1035
1036 // if (PartEntry->HidePartEntry == FALSE)
1037 {
1038 List->CurrentPartition = PartEntry;
1039 DrawPartitionList (List);
1040 return;
1041 }
1042 Entry2 = Entry2->Flink;
1043 }
1044 }
1045
1046 /* Check for first usable entry on next disk */
1047 if (List->CurrentDisk != NULL)
1048 {
1049 Entry1 = List->CurrentDisk->ListEntry.Flink;
1050 while (Entry1 != &List->DiskListHead)
1051 {
1052 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1053
1054 Entry2 = DiskEntry->PartListHead.Flink;
1055 while (Entry2 != &DiskEntry->PartListHead)
1056 {
1057 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1058
1059 // if (PartEntry->HidePartEntry == FALSE)
1060 {
1061 List->CurrentDisk = DiskEntry;
1062 List->CurrentPartition = PartEntry;
1063 DrawPartitionList (List);
1064 return;
1065 }
1066
1067 Entry2 = Entry2->Flink;
1068 }
1069
1070 Entry1 = Entry1->Flink;
1071 }
1072 }
1073 }
1074
1075
1076 VOID
1077 ScrollUpPartitionList (PPARTLIST List)
1078 {
1079 PDISKENTRY DiskEntry;
1080 PPARTENTRY PartEntry;
1081 PLIST_ENTRY Entry1;
1082 PLIST_ENTRY Entry2;
1083 ULONG i;
1084
1085 /* Check for empty disks */
1086 if (IsListEmpty (&List->DiskListHead))
1087 return;
1088
1089 /* check for previous usable entry on current disk */
1090 if (List->CurrentPartition != NULL)
1091 {
1092 Entry2 = List->CurrentPartition->ListEntry.Blink;
1093 while (Entry2 != &List->CurrentDisk->PartListHead)
1094 {
1095 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1096
1097 // if (PartEntry->HidePartEntry == FALSE)
1098 {
1099 List->CurrentPartition = PartEntry;
1100 DrawPartitionList (List);
1101 return;
1102 }
1103 Entry2 = Entry2->Blink;
1104 }
1105 }
1106
1107
1108 /* check for last usable entry on previous disk */
1109 if (List->CurrentDisk != NULL)
1110 {
1111 Entry1 = List->CurrentDisk->ListEntry.Blink;
1112 while (Entry1 != &List->DiskListHead)
1113 {
1114 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1115
1116 Entry2 = DiskEntry->PartListHead.Blink;
1117 while (Entry2 != &DiskEntry->PartListHead)
1118 {
1119 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1120
1121 // if (PartEntry->HidePartEntry == FALSE)
1122 {
1123 List->CurrentDisk = DiskEntry;
1124 List->CurrentPartition = PartEntry;
1125 DrawPartitionList (List);
1126 return;
1127 }
1128
1129 Entry2 = Entry2->Blink;
1130 }
1131
1132 Entry1 = Entry1->Blink;
1133 }
1134 }
1135 }
1136
1137
1138 VOID
1139 SetActiveBootPartition (PPARTLIST List)
1140 {
1141 PDISKENTRY DiskEntry;
1142 PPARTENTRY PartEntry;
1143
1144 /* Check for empty disk list */
1145 if (IsListEmpty (&List->DiskListHead))
1146 {
1147 List->ActiveBootDisk = NULL;
1148 List->ActiveBootPartition = NULL;
1149 return;
1150 }
1151
1152 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
1153 DISKENTRY,
1154 ListEntry);
1155
1156 /* Check for empty partition list */
1157 if (IsListEmpty (&DiskEntry->PartListHead))
1158 {
1159 List->ActiveBootDisk = NULL;
1160 List->ActiveBootPartition = NULL;
1161 return;
1162 }
1163
1164 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
1165 PARTENTRY,
1166 ListEntry);
1167
1168 /* Set active boot partition 1 */
1169 if (PartEntry->PartInfo[0].BootIndicator == FALSE &&
1170 PartEntry->PartInfo[1].BootIndicator == FALSE &&
1171 PartEntry->PartInfo[2].BootIndicator == FALSE &&
1172 PartEntry->PartInfo[3].BootIndicator == FALSE)
1173 {
1174 PartEntry->PartInfo[0].BootIndicator == TRUE;
1175 PartEntry->PartInfo[0].RewritePartition == TRUE;
1176 DiskEntry->Modified = TRUE;
1177 }
1178
1179 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
1180 List->ActiveBootDisk = DiskEntry;
1181 List->ActiveBootPartition = PartEntry;
1182 }
1183
1184
1185 static PPARTENTRY
1186 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1187 PPARTENTRY CurrentEntry)
1188 {
1189 PPARTENTRY PrevEntry;
1190 PLIST_ENTRY Entry;
1191
1192 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1193 return NULL;
1194
1195 Entry = CurrentEntry->ListEntry.Blink;
1196 while (Entry != &DiskEntry->PartListHead)
1197 {
1198 PrevEntry = CONTAINING_RECORD (Entry,
1199 PARTENTRY,
1200 ListEntry);
1201 if (PrevEntry->Unpartitioned == FALSE)
1202 return PrevEntry;
1203
1204 Entry = Entry->Blink;
1205 }
1206
1207 return NULL;
1208 }
1209
1210
1211 static PPARTENTRY
1212 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1213 PPARTENTRY CurrentEntry)
1214 {
1215 PPARTENTRY NextEntry;
1216 PLIST_ENTRY Entry;
1217
1218 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1219 return NULL;
1220
1221 Entry = CurrentEntry->ListEntry.Flink;
1222 while (Entry != &DiskEntry->PartListHead)
1223 {
1224 NextEntry = CONTAINING_RECORD (Entry,
1225 PARTENTRY,
1226 ListEntry);
1227 if (NextEntry->Unpartitioned == FALSE)
1228 return NextEntry;
1229
1230 Entry = Entry->Flink;
1231 }
1232
1233 return NULL;
1234 }
1235
1236
1237 static PPARTENTRY
1238 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1239 PPARTENTRY PartEntry)
1240 {
1241 PPARTENTRY PrevPartEntry;
1242
1243 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1244 {
1245 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1246 PARTENTRY,
1247 ListEntry);
1248 if (PrevPartEntry->Unpartitioned == TRUE)
1249 return PrevPartEntry;
1250 }
1251
1252 return NULL;
1253 }
1254
1255
1256 static PPARTENTRY
1257 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1258 PPARTENTRY PartEntry)
1259 {
1260 PPARTENTRY NextPartEntry;
1261
1262 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1263 {
1264 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1265 PARTENTRY,
1266 ListEntry);
1267 if (NextPartEntry->Unpartitioned == TRUE)
1268 return NextPartEntry;
1269 }
1270
1271 return NULL;
1272 }
1273
1274
1275 VOID
1276 CreateNewPartition (PPARTLIST List,
1277 ULONGLONG PartitionSize,
1278 BOOLEAN AutoCreate)
1279 {
1280 PDISKENTRY DiskEntry;
1281 PPARTENTRY PartEntry;
1282 PPARTENTRY PrevPartEntry;
1283 PPARTENTRY NextPartEntry;
1284 PPARTENTRY NewPartEntry;
1285
1286 if (List == NULL ||
1287 List->CurrentDisk == NULL ||
1288 List->CurrentPartition == NULL ||
1289 List->CurrentPartition->Unpartitioned == FALSE)
1290 {
1291 return;
1292 }
1293
1294 DiskEntry = List->CurrentDisk;
1295 PartEntry = List->CurrentPartition;
1296
1297 if (AutoCreate == TRUE ||
1298 PartitionSize == PartEntry->UnpartitionedLength)
1299 {
1300 /* Convert current entry to 'new (unformatted)' */
1301 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1302 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1303 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1304 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1305 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1306 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1307 PartEntry->PartInfo[0].RewritePartition = TRUE;
1308 PartEntry->PartInfo[1].RewritePartition = TRUE;
1309 PartEntry->PartInfo[2].RewritePartition = TRUE;
1310 PartEntry->PartInfo[3].RewritePartition = TRUE;
1311
1312 /* Get previous and next partition entries */
1313 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1314 PartEntry);
1315 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1316 PartEntry);
1317
1318 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1319 {
1320 /* Current entry is in the middle of the list */
1321
1322 /* Copy previous container partition data to current entry */
1323 RtlCopyMemory (&PartEntry->PartInfo[1],
1324 &PrevPartEntry->PartInfo[1],
1325 sizeof(PARTITION_INFORMATION));
1326 PartEntry->PartInfo[1].RewritePartition = TRUE;
1327
1328 /* Update previous container partition data */
1329
1330 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1331 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1332
1333 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1334 {
1335 /* Special case - previous partition is first partition */
1336 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1337 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1338 }
1339 else
1340 {
1341 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1342 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1343 }
1344
1345 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1346 }
1347 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1348 {
1349 /* Current entry is the first entry */
1350
1351 /* FIXME: Update extended partition entries */
1352 }
1353 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1354 {
1355 /* Current entry is the last entry */
1356
1357 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1358 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1359
1360 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1361 {
1362 /* Special case - previous partition is first partition */
1363 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1364 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1365 }
1366 else
1367 {
1368 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1369 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1370 }
1371
1372 PrevPartEntry->PartInfo[1].PartitionType =
1373 (DiskEntry->UseLba == TRUE) ? PARTITION_XINT13_EXTENDED : PARTITION_EXTENDED;
1374 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1375 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1376 }
1377
1378 PartEntry->AutoCreate = AutoCreate;
1379 PartEntry->New = TRUE;
1380 PartEntry->Unpartitioned = FALSE;
1381 PartEntry->UnpartitionedOffset = 0ULL;
1382 PartEntry->UnpartitionedLength = 0ULL;
1383 }
1384 else
1385 {
1386 /* Insert an initialize a new partition entry */
1387 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1388 0,
1389 sizeof(PARTENTRY));
1390 if (NewPartEntry == NULL)
1391 return;
1392
1393 RtlZeroMemory (NewPartEntry,
1394 sizeof(PARTENTRY));
1395
1396 /* Insert the new entry into the list */
1397 InsertTailList (&PartEntry->ListEntry,
1398 &NewPartEntry->ListEntry);
1399
1400 NewPartEntry->New = TRUE;
1401
1402 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1403 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1404 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1405 PartitionSize - DiskEntry->TrackSize;
1406 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1407 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1408 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1409 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1410 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1411 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1412
1413 /* Get previous and next partition entries */
1414 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1415 NewPartEntry);
1416 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1417 NewPartEntry);
1418
1419 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1420 {
1421 /* Current entry is in the middle of the list */
1422
1423 /* Copy previous container partition data to current entry */
1424 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1425 &PrevPartEntry->PartInfo[1],
1426 sizeof(PARTITION_INFORMATION));
1427 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1428
1429 /* Update previous container partition data */
1430
1431 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1432 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1433
1434 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1435 {
1436 /* Special case - previous partition is first partition */
1437 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1438 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1439 }
1440 else
1441 {
1442 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1443 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1444 }
1445
1446 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1447 }
1448 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1449 {
1450 /* Current entry is the first entry */
1451
1452 /* FIXME: Update extended partition entries */
1453 }
1454 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1455 {
1456 /* Current entry is the last entry */
1457
1458 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1459 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1460
1461 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1462 {
1463 /* Special case - previous partition is first partition */
1464 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1465 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1466 }
1467 else
1468 {
1469 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1470 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1471 }
1472
1473 PrevPartEntry->PartInfo[1].PartitionType =
1474 (DiskEntry->UseLba == TRUE) ? PARTITION_XINT13_EXTENDED : PARTITION_EXTENDED;
1475 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1476 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1477 }
1478
1479 /* Update offset and size of the remaining unpartitioned disk space */
1480 PartEntry->UnpartitionedOffset += PartitionSize;
1481 PartEntry->UnpartitionedLength -= PartitionSize;
1482 }
1483
1484 DiskEntry->Modified = TRUE;
1485
1486 UpdatePartitionNumbers (DiskEntry);
1487
1488 AssignDriverLetters (List);
1489 }
1490
1491
1492 VOID
1493 DeleteCurrentPartition (PPARTLIST List)
1494 {
1495 PDISKENTRY DiskEntry;
1496 PPARTENTRY PartEntry;
1497 PPARTENTRY PrevPartEntry;
1498 PPARTENTRY NextPartEntry;
1499
1500 if (List == NULL ||
1501 List->CurrentDisk == NULL ||
1502 List->CurrentPartition == NULL ||
1503 List->CurrentPartition->Unpartitioned == TRUE)
1504 {
1505 return;
1506 }
1507
1508 DiskEntry = List->CurrentDisk;
1509 PartEntry = List->CurrentPartition;
1510
1511 /* Adjust container partition entries */
1512
1513 /* Get previous and next partition entries */
1514 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1515 PartEntry);
1516 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1517 PartEntry);
1518
1519 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1520 {
1521 /* Current entry is in the middle of the list */
1522 /* Copy previous container partition data to current entry */
1523 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
1524 &PartEntry->PartInfo[1],
1525 sizeof(PARTITION_INFORMATION));
1526 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1527 }
1528 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1529 {
1530 /* Current entry is the first entry */
1531
1532 /* FIXME: Update extended partition entries */
1533 }
1534 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1535 {
1536 /* Current entry is the last entry */
1537 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
1538 sizeof(PARTITION_INFORMATION));
1539 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1540 }
1541
1542
1543 /* Adjust unpartitioned disk space entries */
1544
1545 /* Get pointer to previous and next unpartitioned entries */
1546 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
1547 PartEntry);
1548
1549 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
1550 PartEntry);
1551
1552 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1553 {
1554 /* Merge previous, current and next unpartitioned entry */
1555
1556 /* Adjust the previous entries length */
1557 PrevPartEntry->UnpartitionedLength +=
1558 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
1559 NextPartEntry->UnpartitionedLength);
1560
1561 /* Remove the current entry */
1562 RemoveEntryList (&PartEntry->ListEntry);
1563 RtlFreeHeap (ProcessHeap,
1564 0,
1565 PartEntry);
1566
1567 /* Remove the next entry */
1568 RemoveEntryList (&NextPartEntry->ListEntry);
1569 RtlFreeHeap (ProcessHeap,
1570 0,
1571 NextPartEntry);
1572
1573 /* Update current partition */
1574 List->CurrentPartition = PrevPartEntry;
1575 }
1576 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1577 {
1578 /* Merge current and previous unpartitioned entry */
1579
1580 /* Adjust the previous entries length */
1581 PrevPartEntry->UnpartitionedLength +=
1582 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1583
1584 /* Remove the current entry */
1585 RemoveEntryList (&PartEntry->ListEntry);
1586 RtlFreeHeap (ProcessHeap,
1587 0,
1588 PartEntry);
1589
1590 /* Update current partition */
1591 List->CurrentPartition = PrevPartEntry;
1592 }
1593 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1594 {
1595 /* Merge current and next unpartitioned entry */
1596
1597 /* Adjust the next entries offset and length */
1598 NextPartEntry->UnpartitionedOffset =
1599 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1600 NextPartEntry->UnpartitionedLength +=
1601 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
1602
1603 /* Remove the current entry */
1604 RemoveEntryList (&PartEntry->ListEntry);
1605 RtlFreeHeap (ProcessHeap,
1606 0,
1607 PartEntry);
1608
1609 /* Update current partition */
1610 List->CurrentPartition = NextPartEntry;
1611 }
1612 else
1613 {
1614 /* Nothing to merge but change current entry */
1615 PartEntry->New = FALSE;
1616 PartEntry->Unpartitioned = TRUE;
1617 PartEntry->UnpartitionedOffset =
1618 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1619 PartEntry->UnpartitionedLength =
1620 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1621
1622 /* Wipe the partition table */
1623 RtlZeroMemory (&PartEntry->PartInfo,
1624 sizeof(PartEntry->PartInfo));
1625 }
1626
1627 DiskEntry->Modified = TRUE;
1628
1629 UpdatePartitionNumbers (DiskEntry);
1630
1631 AssignDriverLetters (List);
1632 }
1633
1634
1635 BOOLEAN
1636 WritePartitionsToDisk (PPARTLIST List)
1637 {
1638 PDRIVE_LAYOUT_INFORMATION DriveLayout;
1639 OBJECT_ATTRIBUTES ObjectAttributes;
1640 IO_STATUS_BLOCK Iosb;
1641 WCHAR Buffer[MAX_PATH];
1642 UNICODE_STRING Name;
1643 HANDLE FileHandle;
1644 PDISKENTRY DiskEntry;
1645 PPARTENTRY PartEntry;
1646 PLIST_ENTRY Entry1;
1647 PLIST_ENTRY Entry2;
1648 ULONG PartitionCount;
1649 ULONG DriveLayoutSize;
1650 ULONG Index;
1651 NTSTATUS Status;
1652
1653 if (List == NULL)
1654 {
1655 return TRUE;
1656 }
1657
1658 Entry1 = List->DiskListHead.Flink;
1659 while (Entry1 != &List->DiskListHead)
1660 {
1661 DiskEntry = CONTAINING_RECORD (Entry1,
1662 DISKENTRY,
1663 ListEntry);
1664
1665 if (DiskEntry->Modified == TRUE)
1666 {
1667 /* Count partitioned entries */
1668 PartitionCount = 0;
1669 Entry2 = DiskEntry->PartListHead.Flink;
1670 while (Entry2 != &DiskEntry->PartListHead)
1671 {
1672 PartEntry = CONTAINING_RECORD (Entry2,
1673 PARTENTRY,
1674 ListEntry);
1675 if (PartEntry->Unpartitioned == FALSE)
1676 {
1677 PartitionCount += 4;
1678 }
1679
1680 Entry2 = Entry2->Flink;
1681 }
1682
1683 if (PartitionCount > 0)
1684 {
1685 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
1686 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
1687 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
1688 0,
1689 DriveLayoutSize);
1690 if (DriveLayout == NULL)
1691 {
1692 DPRINT1 ("RtlAllocateHeap() failed\n");
1693 return FALSE;
1694 }
1695
1696 RtlZeroMemory (DriveLayout,
1697 DriveLayoutSize);
1698
1699 DriveLayout->PartitionCount = PartitionCount;
1700
1701 Index = 0;
1702 Entry2 = DiskEntry->PartListHead.Flink;
1703 while (Entry2 != &DiskEntry->PartListHead)
1704 {
1705 PartEntry = CONTAINING_RECORD (Entry2,
1706 PARTENTRY,
1707 ListEntry);
1708 if (PartEntry->Unpartitioned == FALSE)
1709 {
1710 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
1711 &PartEntry->PartInfo[0],
1712 4 * sizeof (PARTITION_INFORMATION));
1713 Index += 4;
1714 }
1715
1716 Entry2 = Entry2->Flink;
1717 }
1718
1719 swprintf (Buffer,
1720 L"\\Device\\Harddisk%d\\Partition0",
1721 DiskEntry->DiskNumber);
1722 RtlInitUnicodeString (&Name,
1723 Buffer);
1724 InitializeObjectAttributes (&ObjectAttributes,
1725 &Name,
1726 0,
1727 NULL,
1728 NULL);
1729
1730 Status = NtOpenFile (&FileHandle,
1731 FILE_GENERIC_WRITE,
1732 &ObjectAttributes,
1733 &Iosb,
1734 0,
1735 FILE_SYNCHRONOUS_IO_NONALERT);
1736 if (!NT_SUCCESS (Status))
1737 {
1738 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
1739 return FALSE;
1740 }
1741
1742 Status = NtDeviceIoControlFile (FileHandle,
1743 NULL,
1744 NULL,
1745 NULL,
1746 &Iosb,
1747 IOCTL_DISK_SET_DRIVE_LAYOUT,
1748 DriveLayout,
1749 DriveLayoutSize,
1750 NULL,
1751 0);
1752 if (!NT_SUCCESS (Status))
1753 {
1754 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
1755 NtClose (FileHandle);
1756 return FALSE;
1757 }
1758
1759 RtlFreeHeap (ProcessHeap,
1760 0,
1761 DriveLayout);
1762
1763 /* FIXME: Install MBR code */
1764
1765 NtClose (FileHandle);
1766 }
1767 }
1768
1769 Entry1 = Entry1->Flink;
1770 }
1771
1772 return TRUE;
1773 }
1774
1775 /* EOF */