Replaced array of disk entries in partition list by doubley-linked list of disk entries.
[reactos.git] / reactos / subsys / system / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 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.11 2003/08/02 16:49:36 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 AddPartitionToList (ULONG DiskNumber,
78 PDISKENTRY DiskEntry,
79 DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
80 {
81 PPARTENTRY PartEntry;
82 ULONG i;
83 ULONG EntryCount;
84 BOOLEAN LastEntryWasUnused;
85 ULONGLONG LastStartingOffset;
86 ULONGLONG LastPartitionSize;
87 ULONGLONG LastUnusedPartitionSize;
88 ULONG LastUnusedEntry;
89
90 /*
91 * FIXME:
92 * Determine required number of partiton entries.
93 * This must include entries for unused disk space.
94 */
95
96 /* Check for unpartitioned disk */
97 if (LayoutBuffer->PartitionCount == 0)
98 {
99 EntryCount = 1;
100 }
101 else
102 {
103 EntryCount = LayoutBuffer->PartitionCount;
104 }
105
106
107 DiskEntry->PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
108 0,
109 EntryCount * sizeof(PARTENTRY));
110 DiskEntry->PartCount = EntryCount;
111
112 RtlZeroMemory(DiskEntry->PartArray,
113 EntryCount * sizeof(PARTENTRY));
114
115 if (LayoutBuffer->PartitionCount == 0)
116 {
117 /* Initialize an 'Unpartitioned space' entry */
118 PartEntry = &DiskEntry->PartArray[0];
119
120 PartEntry->Unpartitioned = TRUE;
121 // Start partition at head 1, cylinder 0
122 PartEntry->StartingOffset = DiskEntry->SectorsPerTrack * DiskEntry->BytesPerSector;
123 PartEntry->PartSize = DiskEntry->DiskSize - PartEntry->StartingOffset;
124 PartEntry->Used = FALSE;
125 PartEntry->HidePartEntry = FALSE;
126 PartEntry->PartNumber = 1;
127 }
128 else
129 {
130 LastEntryWasUnused = FALSE;
131 // Start partition at head 1, cylinder 0
132 LastStartingOffset = DiskEntry->SectorsPerTrack * DiskEntry->BytesPerSector;
133 LastPartitionSize = 0;
134 LastUnusedEntry = -1;
135 LastUnusedPartitionSize = 0;
136 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
137 {
138 PartEntry = &DiskEntry->PartArray[i];
139
140 if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
141 (!IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType)))
142 {
143 LastUnusedPartitionSize = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart
144 - (LastStartingOffset + LastPartitionSize);
145 if (LastUnusedEntry != -1)
146 {
147 DiskEntry->PartArray[LastUnusedEntry].StartingOffset = LastStartingOffset + LastPartitionSize;
148 DiskEntry->PartArray[LastUnusedEntry].PartSize = LastUnusedPartitionSize;
149 DiskEntry->PartArray[LastUnusedEntry].PartNumber = LastUnusedEntry + 1; /* FIXME: Is this always correct? */
150 }
151 LastStartingOffset = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart;
152 LastPartitionSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
153
154 PartEntry->StartingOffset = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart;
155 PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
156 PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
157 PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
158 PartEntry->Active = LayoutBuffer->PartitionEntry[i].BootIndicator;
159
160 PartEntry->DriveLetter = GetDriveLetter(DiskNumber,
161 LayoutBuffer->PartitionEntry[i].PartitionNumber);
162
163 PartEntry->Unpartitioned = FALSE;
164
165 PartEntry->Used = TRUE;
166 PartEntry->HidePartEntry = FALSE;
167 LastEntryWasUnused = FALSE;
168 LastUnusedEntry = -1;
169 }
170 else
171 {
172 if (LastEntryWasUnused)
173 {
174 /* Group unused entries into one unpartitioned disk space area */
175 PartEntry->HidePartEntry = TRUE;
176 PartEntry->PartSize = 0;
177 }
178 else
179 {
180 LastUnusedEntry = i;
181 }
182
183 PartEntry->Unpartitioned = TRUE;
184
185 PartEntry->Used = FALSE;
186 LastEntryWasUnused = TRUE;
187 }
188 }
189 LastUnusedPartitionSize = DiskEntry->DiskSize
190 - (LastStartingOffset + LastPartitionSize);
191 if (LastUnusedEntry != -1)
192 {
193 DiskEntry->PartArray[LastUnusedEntry].StartingOffset = LastStartingOffset + LastPartitionSize;
194 DiskEntry->PartArray[LastUnusedEntry].PartSize = LastUnusedPartitionSize;
195 DiskEntry->PartArray[LastUnusedEntry].PartNumber = LastUnusedEntry + 1; /* FIXME: Is this always correct? */
196 }
197 }
198 }
199
200
201 static VOID
202 AddDiskToList (HANDLE FileHandle,
203 ULONG DiskNumber,
204 PPARTLIST List)
205 {
206 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
207 DISK_GEOMETRY DiskGeometry;
208 SCSI_ADDRESS ScsiAddress;
209 PDISKENTRY DiskEntry;
210 IO_STATUS_BLOCK Iosb;
211 NTSTATUS Status;
212
213 Status = NtDeviceIoControlFile (FileHandle,
214 NULL,
215 NULL,
216 NULL,
217 &Iosb,
218 IOCTL_DISK_GET_DRIVE_GEOMETRY,
219 NULL,
220 0,
221 &DiskGeometry,
222 sizeof(DISK_GEOMETRY));
223 if (!NT_SUCCESS(Status))
224 {
225 return;
226 }
227
228 if (DiskGeometry.MediaType != FixedMedia)
229 {
230 return;
231 }
232
233 Status = NtDeviceIoControlFile (FileHandle,
234 NULL,
235 NULL,
236 NULL,
237 &Iosb,
238 IOCTL_SCSI_GET_ADDRESS,
239 NULL,
240 0,
241 &ScsiAddress,
242 sizeof(SCSI_ADDRESS));
243 if (!NT_SUCCESS(Status))
244 {
245 return;
246 }
247
248 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
249 0,
250 sizeof(DISKENTRY));
251 if (DiskEntry == NULL)
252 {
253 return;
254 }
255
256 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
257 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
258 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
259 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
260
261 DPRINT("Cylinders %d\n", DiskEntry->Cylinders);
262 DPRINT("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
263 DPRINT("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
264 DPRINT("BytesPerSector %d\n", DiskEntry->BytesPerSector);
265
266 DiskEntry->DiskSize =
267 DiskGeometry.Cylinders.QuadPart *
268 (ULONGLONG)DiskGeometry.TracksPerCylinder *
269 (ULONGLONG)DiskGeometry.SectorsPerTrack *
270 (ULONGLONG)DiskGeometry.BytesPerSector;
271 DiskEntry->DiskNumber = DiskNumber;
272 DiskEntry->Port = ScsiAddress.PortNumber;
273 DiskEntry->Bus = ScsiAddress.PathId;
274 DiskEntry->Id = ScsiAddress.TargetId;
275
276 GetDriverName (DiskEntry);
277
278 InsertTailList (&List->DiskList, &DiskEntry->ListEntry);
279
280 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
281 0,
282 8192);
283 if (LayoutBuffer == NULL)
284 {
285 return;
286 }
287
288 Status = NtDeviceIoControlFile (FileHandle,
289 NULL,
290 NULL,
291 NULL,
292 &Iosb,
293 IOCTL_DISK_GET_DRIVE_LAYOUT,
294 NULL,
295 0,
296 LayoutBuffer,
297 8192);
298 if (NT_SUCCESS (Status))
299 {
300 AddPartitionToList (DiskNumber,
301 DiskEntry,
302 LayoutBuffer);
303 }
304
305 RtlFreeHeap (ProcessHeap,
306 0,
307 LayoutBuffer);
308 }
309
310
311 PPARTLIST
312 InitializePartitionList(VOID)
313 {
314 PPARTLIST List;
315 OBJECT_ATTRIBUTES ObjectAttributes;
316 SYSTEM_DEVICE_INFORMATION Sdi;
317 DISK_GEOMETRY DiskGeometry;
318 IO_STATUS_BLOCK Iosb;
319 ULONG ReturnSize;
320 NTSTATUS Status;
321 ULONG DiskNumber;
322 WCHAR Buffer[MAX_PATH];
323 UNICODE_STRING Name;
324 HANDLE FileHandle;
325
326 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
327 if (List == NULL)
328 return(NULL);
329
330 List->Left = 0;
331 List->Top = 0;
332 List->Right = 0;
333 List->Bottom = 0;
334
335 List->Line = 0;
336
337 List->TopDisk = (ULONG)-1;
338 List->TopPartition = (ULONG)-1;
339
340 List->CurrentDisk = NULL;
341 List->CurrentPartition = (ULONG)-1;
342
343 InitializeListHead (&List->DiskList);
344
345 Status = NtQuerySystemInformation(SystemDeviceInformation,
346 &Sdi,
347 sizeof(SYSTEM_DEVICE_INFORMATION),
348 &ReturnSize);
349 if (!NT_SUCCESS(Status))
350 {
351 RtlFreeHeap(ProcessHeap, 0, List);
352 return(NULL);
353 }
354
355 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
356 {
357 swprintf(Buffer,
358 L"\\Device\\Harddisk%d\\Partition0",
359 DiskNumber);
360 RtlInitUnicodeString(&Name,
361 Buffer);
362
363 InitializeObjectAttributes(&ObjectAttributes,
364 &Name,
365 0,
366 NULL,
367 NULL);
368
369 Status = NtOpenFile(&FileHandle,
370 0x10001,
371 &ObjectAttributes,
372 &Iosb,
373 1,
374 FILE_SYNCHRONOUS_IO_NONALERT);
375 if (NT_SUCCESS(Status))
376 {
377 AddDiskToList (FileHandle,
378 DiskNumber,
379 List);
380
381 NtClose(FileHandle);
382 }
383 }
384
385 List->TopDisk = 0;
386 List->TopPartition = 0;
387
388 /* Search for first usable disk and partition */
389 if (IsListEmpty (&List->DiskList))
390 {
391 List->CurrentDisk = NULL;
392 List->CurrentPartition = (ULONG)-1;
393 }
394 else
395 {
396 List->CurrentDisk = CONTAINING_RECORD(List->DiskList.Flink, DISKENTRY, ListEntry);
397 List->CurrentPartition = 0;
398 }
399
400 return(List);
401 }
402
403
404 PPARTLIST
405 CreatePartitionList(SHORT Left,
406 SHORT Top,
407 SHORT Right,
408 SHORT Bottom)
409 {
410 PPARTLIST List;
411
412 List = InitializePartitionList();
413 if (List == NULL)
414 return(NULL);
415
416 List->Left = Left;
417 List->Top = Top;
418 List->Right = Right;
419 List->Bottom = Bottom;
420
421 DrawPartitionList(List);
422
423 return(List);
424 }
425
426
427 PPARTENTRY
428 GetPartitionInformation(PPARTLIST List,
429 ULONG DiskNumber,
430 ULONG PartitionNumber,
431 PULONG PartEntryNumber)
432 {
433 PPARTENTRY PartEntry;
434 ULONG i;
435
436 if (IsListEmpty(&List->DiskList))
437 {
438 return NULL;
439 }
440
441 #if 0
442 if (DiskNumber >= List->DiskCount)
443 {
444 return NULL;
445 }
446
447 if (PartitionNumber >= List->DiskArray[DiskNumber].PartCount)
448 {
449 return NULL;
450 }
451
452 if (List->DiskArray[DiskNumber].FixedDisk != TRUE)
453 {
454 return NULL;
455 }
456
457 for (i = 0; i < List->DiskArray[DiskNumber].PartCount; i++)
458 {
459 PartEntry = &List->DiskArray[DiskNumber].PartArray[i];
460 if (PartEntry->PartNumber == PartitionNumber)
461 {
462 *PartEntryNumber = i;
463 return PartEntry;
464 }
465 }
466 #endif
467 return NULL;
468 }
469
470
471 VOID
472 DestroyPartitionList(PPARTLIST List)
473 {
474 PLIST_ENTRY Entry;
475 PDISKENTRY DiskEntry;
476 #if 0
477 COORD coPos;
478 USHORT Width;
479
480 /* clear occupied screen area */
481 coPos.X = List->Left;
482 Width = List->Right - List->Left + 1;
483 for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
484 {
485 FillConsoleOutputAttribute(0x17,
486 Width,
487 coPos,
488 &i);
489
490 FillConsoleOutputCharacter(' ',
491 Width,
492 coPos,
493 &i);
494 }
495 #endif
496
497 /* Release disk and partition info */
498 while (!IsListEmpty (&List->DiskList))
499 {
500 Entry = RemoveHeadList (&List->DiskList);
501 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
502
503 /* Release driver name */
504 RtlFreeUnicodeString(&DiskEntry->DriverName);
505
506 /* Release partition array */
507 if (DiskEntry->PartArray != NULL)
508 {
509 RtlFreeHeap(ProcessHeap, 0, DiskEntry->PartArray);
510 }
511
512 /* Release disk entry */
513 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
514 }
515
516 /* Release list head */
517 RtlFreeHeap (ProcessHeap, 0, List);
518 }
519
520
521 static VOID
522 PrintEmptyLine(PPARTLIST List)
523 {
524 COORD coPos;
525 ULONG Written;
526 USHORT Width;
527 USHORT Height;
528
529 Width = List->Right - List->Left - 1;
530 Height = List->Bottom - List->Top - 1;
531
532 if (List->Line < 0 || List->Line > Height)
533 return;
534
535 coPos.X = List->Left + 1;
536 coPos.Y = List->Top + 1 + List->Line;
537
538 FillConsoleOutputAttribute(0x17,
539 Width,
540 coPos,
541 &Written);
542
543 FillConsoleOutputCharacter(' ',
544 Width,
545 coPos,
546 &Written);
547
548 List->Line++;
549 }
550
551
552 static VOID
553 PrintPartitionData(PPARTLIST List,
554 PDISKENTRY DiskEntry,
555 SHORT PartIndex)
556 {
557 PPARTENTRY PartEntry;
558 CHAR LineBuffer[128];
559 COORD coPos;
560 ULONG Written;
561 USHORT Width;
562 USHORT Height;
563
564 ULONGLONG PartSize;
565 PCHAR Unit;
566 UCHAR Attribute;
567 PCHAR PartType;
568
569 Width = List->Right - List->Left - 1;
570 Height = List->Bottom - List->Top - 1;
571
572 if (List->Line < 0 || List->Line > Height)
573 return;
574
575 coPos.X = List->Left + 1;
576 coPos.Y = List->Top + 1 + List->Line;
577
578 PartEntry = &DiskEntry->PartArray[PartIndex];
579
580 /* Determine partition type */
581 PartType = NULL;
582 if (PartEntry->Unpartitioned == FALSE)
583 {
584 if ((PartEntry->PartType == PARTITION_FAT_12) ||
585 (PartEntry->PartType == PARTITION_FAT_16) ||
586 (PartEntry->PartType == PARTITION_HUGE) ||
587 (PartEntry->PartType == PARTITION_XINT13))
588 {
589 PartType = "FAT";
590 }
591 else if ((PartEntry->PartType == PARTITION_FAT32) ||
592 (PartEntry->PartType == PARTITION_FAT32_XINT13))
593 {
594 PartType = "FAT32";
595 }
596 else if (PartEntry->PartType == PARTITION_IFS)
597 {
598 PartType = "NTFS"; /* FIXME: Not quite correct! */
599 }
600 }
601
602
603 #if 0
604 if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
605 {
606 PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
607 Unit = "GB";
608 }
609 else
610 #endif
611 if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
612 {
613 PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
614 Unit = "MB";
615 }
616 else
617 {
618 PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
619 Unit = "KB";
620 }
621
622
623 if (PartEntry->Unpartitioned == TRUE)
624 {
625 sprintf(LineBuffer,
626 " Unpartitioned space %I64u %s",
627 PartSize,
628 Unit);
629 }
630 else if (PartEntry->DriveLetter != (CHAR)0)
631 {
632 if (PartType == NULL)
633 {
634 sprintf(LineBuffer,
635 "%c: Type %-3lu %I64u %s",
636 PartEntry->DriveLetter,
637 PartEntry->PartType,
638 PartSize,
639 Unit);
640 }
641 else
642 {
643 sprintf(LineBuffer,
644 "%c: %s %I64u %s",
645 PartEntry->DriveLetter,
646 PartType,
647 PartSize,
648 Unit);
649 }
650 }
651 else
652 {
653 sprintf(LineBuffer,
654 "-- %s Type -3lu %I64u %s",
655 PartEntry->FileSystemName,
656 PartEntry->PartType,
657 PartSize,
658 Unit);
659 }
660
661 Attribute = (List->CurrentDisk == DiskEntry &&
662 List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
663
664 FillConsoleOutputCharacter(' ',
665 Width,
666 coPos,
667 &Written);
668
669 coPos.X += 4;
670 Width -= 8;
671 FillConsoleOutputAttribute(Attribute,
672 Width,
673 coPos,
674 &Written);
675
676 coPos.X++;
677 Width -= 2;
678 WriteConsoleOutputCharacters(LineBuffer,
679 min(strlen(LineBuffer), Width),
680 coPos);
681
682 List->Line++;
683 }
684
685
686 static VOID
687 PrintDiskData(PPARTLIST List,
688 PDISKENTRY DiskEntry)
689 {
690 CHAR LineBuffer[128];
691 COORD coPos;
692 ULONG Written;
693 USHORT Width;
694 USHORT Height;
695 ULONGLONG DiskSize;
696 PCHAR Unit;
697 SHORT PartIndex;
698
699 Width = List->Right - List->Left - 1;
700 Height = List->Bottom - List->Top - 1;
701
702 if (List->Line < 0 || List->Line > Height)
703 return;
704
705 coPos.X = List->Left + 1;
706 coPos.Y = List->Top + 1 + List->Line;
707
708 #if 0
709 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
710 {
711 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
712 Unit = "GB";
713 }
714 else
715 #endif
716 {
717 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
718 if (DiskSize == 0)
719 DiskSize = 1;
720 Unit = "MB";
721 }
722
723 if (DiskEntry->DriverName.Length > 0)
724 {
725 sprintf(LineBuffer,
726 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
727 DiskSize,
728 Unit,
729 DiskEntry->DiskNumber,
730 DiskEntry->Port,
731 DiskEntry->Bus,
732 DiskEntry->Id,
733 &DiskEntry->DriverName);
734 }
735 else
736 {
737 sprintf(LineBuffer,
738 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
739 DiskSize,
740 Unit,
741 DiskEntry->DiskNumber,
742 DiskEntry->Port,
743 DiskEntry->Bus,
744 DiskEntry->Id);
745 }
746
747 FillConsoleOutputAttribute(0x17,
748 Width,
749 coPos,
750 &Written);
751
752 FillConsoleOutputCharacter(' ',
753 Width,
754 coPos,
755 &Written);
756
757 coPos.X++;
758 WriteConsoleOutputCharacters(LineBuffer,
759 min(strlen(LineBuffer), Width - 2),
760 coPos);
761
762 List->Line++;
763
764 /* Print separator line */
765 PrintEmptyLine(List);
766
767 /* Print partition lines*/
768 for (PartIndex = 0; PartIndex < DiskEntry->PartCount; PartIndex++)
769 {
770 if (!DiskEntry->PartArray[PartIndex].HidePartEntry)
771 {
772 PrintPartitionData(List,
773 DiskEntry,
774 PartIndex);
775 }
776 }
777
778 /* Print separator line */
779 PrintEmptyLine(List);
780 }
781
782
783 VOID
784 DrawPartitionList(PPARTLIST List)
785 {
786 PLIST_ENTRY Entry;
787 PDISKENTRY DiskEntry;
788 CHAR LineBuffer[128];
789 COORD coPos;
790 ULONG Written;
791 SHORT i;
792 SHORT DiskIndex;
793
794 /* draw upper left corner */
795 coPos.X = List->Left;
796 coPos.Y = List->Top;
797 FillConsoleOutputCharacter(0xDA, // '+',
798 1,
799 coPos,
800 &Written);
801
802 /* draw upper edge */
803 coPos.X = List->Left + 1;
804 coPos.Y = List->Top;
805 FillConsoleOutputCharacter(0xC4, // '-',
806 List->Right - List->Left - 1,
807 coPos,
808 &Written);
809
810 /* draw upper right corner */
811 coPos.X = List->Right;
812 coPos.Y = List->Top;
813 FillConsoleOutputCharacter(0xBF, // '+',
814 1,
815 coPos,
816 &Written);
817
818 /* draw left and right edge */
819 for (i = List->Top + 1; i < List->Bottom; i++)
820 {
821 coPos.X = List->Left;
822 coPos.Y = i;
823 FillConsoleOutputCharacter(0xB3, // '|',
824 1,
825 coPos,
826 &Written);
827
828 coPos.X = List->Right;
829 FillConsoleOutputCharacter(0xB3, //'|',
830 1,
831 coPos,
832 &Written);
833 }
834
835 /* draw lower left corner */
836 coPos.X = List->Left;
837 coPos.Y = List->Bottom;
838 FillConsoleOutputCharacter(0xC0, // '+',
839 1,
840 coPos,
841 &Written);
842
843 /* draw lower edge */
844 coPos.X = List->Left + 1;
845 coPos.Y = List->Bottom;
846 FillConsoleOutputCharacter(0xC4, // '-',
847 List->Right - List->Left - 1,
848 coPos,
849 &Written);
850
851 /* draw lower right corner */
852 coPos.X = List->Right;
853 coPos.Y = List->Bottom;
854 FillConsoleOutputCharacter(0xD9, // '+',
855 1,
856 coPos,
857 &Written);
858
859 /* print list entries */
860 List->Line = 0;
861
862 Entry = List->DiskList.Flink;
863 while (Entry != &List->DiskList)
864 {
865 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
866
867 /* Print disk entry */
868 PrintDiskData (List,
869 DiskEntry);
870
871 Entry = Entry->Flink;
872 }
873 }
874
875
876 VOID
877 ScrollDownPartitionList(PPARTLIST List)
878 {
879 PLIST_ENTRY Entry;
880 PDISKENTRY DiskEntry;
881 ULONG i;
882
883 /* Check for empty disks */
884 if (IsListEmpty (&List->DiskList))
885 return;
886
887 /* check for next usable entry on current disk */
888 for (i = List->CurrentPartition + 1; i < List->CurrentDisk->PartCount; i++)
889 {
890 if (List->CurrentDisk->PartArray[i].HidePartEntry == FALSE)
891 {
892 List->CurrentPartition = i;
893 DrawPartitionList(List);
894 return;
895 }
896 }
897
898 /* check for first usable entry on next disk */
899 Entry = List->CurrentDisk->ListEntry.Flink;
900 while (Entry != &List->DiskList)
901 {
902 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
903 for (i = 0; i < DiskEntry->PartCount; i++)
904 {
905 if (DiskEntry->PartArray[i].HidePartEntry == FALSE)
906 {
907 List->CurrentDisk = DiskEntry;
908 List->CurrentPartition = i;
909 DrawPartitionList(List);
910 return;
911 }
912 }
913 Entry = Entry->Flink;
914 }
915 }
916
917
918 VOID
919 ScrollUpPartitionList(PPARTLIST List)
920 {
921 PLIST_ENTRY Entry;
922 PDISKENTRY DiskEntry;
923 ULONG i;
924
925 /* Check for empty disks */
926 if (IsListEmpty (&List->DiskList))
927 return;
928
929 /* check for previous usable entry on current disk */
930 for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
931 {
932 if (List->CurrentDisk->PartArray[i].HidePartEntry == FALSE)
933 {
934 List->CurrentPartition = i;
935 DrawPartitionList(List);
936 return;
937 }
938 }
939
940 /* check for last usable entry on previous disk */
941 Entry = List->CurrentDisk->ListEntry.Blink;
942 while (Entry != &List->DiskList)
943 {
944 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
945 for (i = DiskEntry->PartCount - 1; i != (ULONG)-1; i--)
946 {
947 if (DiskEntry->PartArray[i].HidePartEntry == FALSE)
948 {
949 List->CurrentDisk = DiskEntry;
950 List->CurrentPartition = i;
951 DrawPartitionList(List);
952 return;
953 }
954 }
955 Entry = Entry->Blink;
956 }
957 }
958
959
960 BOOLEAN
961 GetSelectedPartition(PPARTLIST List,
962 PPARTDATA Data)
963 {
964 PDISKENTRY DiskEntry;
965 PPARTENTRY PartEntry;
966
967 if (List->CurrentDisk == NULL)
968 return FALSE;
969
970 DiskEntry = List->CurrentDisk;
971
972 if (List->CurrentPartition >= DiskEntry->PartCount)
973 return(FALSE);
974
975 PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
976
977 if (PartEntry->Used == FALSE)
978 {
979 return(FALSE);
980 }
981
982 /* Copy disk-specific data */
983 Data->DiskSize = DiskEntry->DiskSize;
984 Data->DiskNumber = DiskEntry->DiskNumber;
985 Data->Port = DiskEntry->Port;
986 Data->Bus = DiskEntry->Bus;
987 Data->Id = DiskEntry->Id;
988
989 /* Copy driver name */
990 RtlInitUnicodeString(&Data->DriverName,
991 NULL);
992 if (DiskEntry->DriverName.Length != 0)
993 {
994 Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
995 0,
996 DiskEntry->DriverName.MaximumLength);
997 if (Data->DriverName.Buffer != NULL)
998 {
999 Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
1000 Data->DriverName.Length = DiskEntry->DriverName.Length;
1001 RtlCopyMemory(Data->DriverName.Buffer,
1002 DiskEntry->DriverName.Buffer,
1003 DiskEntry->DriverName.MaximumLength);
1004 }
1005 }
1006
1007 /* Copy partition-specific data */
1008 Data->CreatePartition = FALSE;
1009 Data->NewPartSize = 0;
1010 Data->PartSize = PartEntry->PartSize;
1011 Data->PartNumber = PartEntry->PartNumber;
1012 Data->PartType = PartEntry->PartType;
1013 Data->DriveLetter = PartEntry->DriveLetter;
1014
1015 return(TRUE);
1016 }
1017
1018
1019 BOOLEAN
1020 GetActiveBootPartition(PPARTLIST List,
1021 PPARTDATA Data)
1022 {
1023 PDISKENTRY DiskEntry;
1024 PPARTENTRY PartEntry;
1025 ULONG i;
1026
1027 if (List->CurrentDisk == NULL)
1028 return FALSE;
1029
1030 DiskEntry = List->CurrentDisk;
1031
1032 for (i = 0; i < DiskEntry->PartCount; i++)
1033 {
1034 if (DiskEntry->PartArray[i].Active)
1035 {
1036 PartEntry = &DiskEntry->PartArray[i];
1037
1038 if (PartEntry->Used == FALSE)
1039 {
1040 return(FALSE);
1041 }
1042
1043 /* Copy disk-specific data */
1044 Data->DiskSize = DiskEntry->DiskSize;
1045 Data->DiskNumber = DiskEntry->DiskNumber;
1046 Data->Port = DiskEntry->Port;
1047 Data->Bus = DiskEntry->Bus;
1048 Data->Id = DiskEntry->Id;
1049
1050 /* Copy driver name */
1051 RtlInitUnicodeString(&Data->DriverName,
1052 NULL);
1053 if (DiskEntry->DriverName.Length != 0)
1054 {
1055 Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
1056 0,
1057 DiskEntry->DriverName.MaximumLength);
1058 if (Data->DriverName.Buffer != NULL)
1059 {
1060 Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
1061 Data->DriverName.Length = DiskEntry->DriverName.Length;
1062 RtlCopyMemory(Data->DriverName.Buffer,
1063 DiskEntry->DriverName.Buffer,
1064 DiskEntry->DriverName.MaximumLength);
1065 }
1066 }
1067
1068 /* Copy partition-specific data */
1069 Data->PartSize = PartEntry->PartSize;
1070 Data->PartNumber = PartEntry->PartNumber;
1071 Data->PartType = PartEntry->PartType;
1072 Data->DriveLetter = PartEntry->DriveLetter;
1073
1074 return(TRUE);
1075 }
1076 }
1077
1078 return(FALSE);
1079 }
1080
1081
1082 BOOLEAN
1083 CreateSelectedPartition(PPARTLIST List,
1084 ULONG PartType,
1085 ULONGLONG NewPartSize)
1086 {
1087 PDISKENTRY DiskEntry;
1088 PPARTENTRY PartEntry;
1089 ULONG PartEntryNumber;
1090 OBJECT_ATTRIBUTES ObjectAttributes;
1091 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
1092 IO_STATUS_BLOCK Iosb;
1093 NTSTATUS Status;
1094 WCHAR Buffer[MAX_PATH];
1095 UNICODE_STRING Name;
1096 HANDLE FileHandle;
1097 LARGE_INTEGER li;
1098
1099 DiskEntry = List->CurrentDisk;
1100 PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
1101 PartEntry->PartType = PartType;
1102 PartEntryNumber = List->CurrentPartition;
1103
1104 DPRINT("NewPartSize %d (%d MB)\n", NewPartSize, NewPartSize / (1024 * 1024));
1105 DPRINT("PartEntry->StartingOffset %d\n", PartEntry->StartingOffset);
1106 DPRINT("PartEntry->PartSize %d\n", PartEntry->PartSize);
1107 DPRINT("PartEntry->PartNumber %d\n", PartEntry->PartNumber);
1108 DPRINT("PartEntry->PartType 0x%x\n", PartEntry->PartType);
1109 DPRINT("PartEntry->FileSystemName %s\n", PartEntry->FileSystemName);
1110
1111 swprintf(Buffer,
1112 L"\\Device\\Harddisk%d\\Partition0",
1113 DiskEntry->DiskNumber);
1114 RtlInitUnicodeString(&Name, Buffer);
1115
1116 InitializeObjectAttributes(&ObjectAttributes,
1117 &Name,
1118 0,
1119 NULL,
1120 NULL);
1121
1122 Status = NtOpenFile(&FileHandle,
1123 0x10001,
1124 &ObjectAttributes,
1125 &Iosb,
1126 1,
1127 FILE_SYNCHRONOUS_IO_NONALERT);
1128 if (NT_SUCCESS(Status))
1129 {
1130 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
1131
1132 Status = NtDeviceIoControlFile(FileHandle,
1133 NULL,
1134 NULL,
1135 NULL,
1136 &Iosb,
1137 IOCTL_DISK_GET_DRIVE_LAYOUT,
1138 NULL,
1139 0,
1140 LayoutBuffer,
1141 8192);
1142 if (!NT_SUCCESS(Status))
1143 {
1144 DPRINT("IOCTL_DISK_GET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
1145 NtClose(FileHandle);
1146 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1147 return FALSE;
1148 }
1149
1150 li.QuadPart = PartEntry->StartingOffset;
1151 LayoutBuffer->PartitionEntry[PartEntryNumber].StartingOffset = li;
1152 /* FIXME: Adjust PartitionLength so the partition will end on the last sector of a track */
1153 li.QuadPart = NewPartSize;
1154 LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionLength = li;
1155 LayoutBuffer->PartitionEntry[PartEntryNumber].HiddenSectors =
1156 PartEntry->StartingOffset / DiskEntry->BytesPerSector;
1157 LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionType = PartType;
1158 LayoutBuffer->PartitionEntry[PartEntryNumber].RecognizedPartition = TRUE;
1159 LayoutBuffer->PartitionEntry[PartEntryNumber].RewritePartition = TRUE;
1160
1161 Status = NtDeviceIoControlFile(FileHandle,
1162 NULL,
1163 NULL,
1164 NULL,
1165 &Iosb,
1166 IOCTL_DISK_SET_DRIVE_LAYOUT,
1167 LayoutBuffer,
1168 8192,
1169 NULL,
1170 0);
1171 if (!NT_SUCCESS(Status))
1172 {
1173 DPRINT("IOCTL_DISK_SET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
1174 NtClose(FileHandle);
1175 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1176 return FALSE;
1177 }
1178 }
1179 else
1180 {
1181 DPRINT("NtOpenFile failed() 0x%.08x\n", Status);
1182 NtClose(FileHandle);
1183 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1184 return FALSE;
1185 }
1186
1187 NtClose(FileHandle);
1188 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1189
1190 return TRUE;
1191 }
1192
1193
1194 BOOLEAN
1195 DeleteSelectedPartition(PPARTLIST List)
1196 {
1197 PDISKENTRY DiskEntry;
1198 PPARTENTRY PartEntry;
1199 ULONG PartEntryNumber;
1200 OBJECT_ATTRIBUTES ObjectAttributes;
1201 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
1202 IO_STATUS_BLOCK Iosb;
1203 NTSTATUS Status;
1204 WCHAR Buffer[MAX_PATH];
1205 UNICODE_STRING Name;
1206 HANDLE FileHandle;
1207 LARGE_INTEGER li;
1208
1209 DiskEntry = List->CurrentDisk;
1210 PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
1211 PartEntry->PartType = PARTITION_ENTRY_UNUSED;
1212 PartEntryNumber = List->CurrentPartition;
1213
1214 DPRINT1("DeleteSelectedPartition(PartEntryNumber = %d)\n", PartEntryNumber);
1215 DPRINT1("PartEntry->StartingOffset %d\n", PartEntry->StartingOffset);
1216 DPRINT1("PartEntry->PartSize %d\n", PartEntry->PartSize);
1217 DPRINT1("PartEntry->PartNumber %d\n", PartEntry->PartNumber);
1218 DPRINT1("PartEntry->PartType 0x%x\n", PartEntry->PartType);
1219 DPRINT1("PartEntry->FileSystemName %s\n", PartEntry->FileSystemName);
1220
1221 swprintf(Buffer,
1222 L"\\Device\\Harddisk%d\\Partition0",
1223 DiskEntry->DiskNumber);
1224 RtlInitUnicodeString(&Name, Buffer);
1225
1226 InitializeObjectAttributes(&ObjectAttributes,
1227 &Name,
1228 0,
1229 NULL,
1230 NULL);
1231
1232 Status = NtOpenFile(&FileHandle,
1233 0x10001,
1234 &ObjectAttributes,
1235 &Iosb,
1236 1,
1237 FILE_SYNCHRONOUS_IO_NONALERT);
1238 if (NT_SUCCESS(Status))
1239 {
1240 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
1241
1242 Status = NtDeviceIoControlFile(FileHandle,
1243 NULL,
1244 NULL,
1245 NULL,
1246 &Iosb,
1247 IOCTL_DISK_GET_DRIVE_LAYOUT,
1248 NULL,
1249 0,
1250 LayoutBuffer,
1251 8192);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 DPRINT("IOCTL_DISK_GET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
1255 NtClose(FileHandle);
1256 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1257 return FALSE;
1258 }
1259
1260 li.QuadPart = 0;
1261 LayoutBuffer->PartitionEntry[PartEntryNumber].StartingOffset = li;
1262 li.QuadPart = 0;
1263 LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionLength = li;
1264 LayoutBuffer->PartitionEntry[PartEntryNumber].HiddenSectors = 0;
1265 LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionType = 0;
1266 LayoutBuffer->PartitionEntry[PartEntryNumber].RecognizedPartition = FALSE;
1267 LayoutBuffer->PartitionEntry[PartEntryNumber].RewritePartition = TRUE;
1268
1269 Status = NtDeviceIoControlFile(FileHandle,
1270 NULL,
1271 NULL,
1272 NULL,
1273 &Iosb,
1274 IOCTL_DISK_SET_DRIVE_LAYOUT,
1275 LayoutBuffer,
1276 8192,
1277 NULL,
1278 0);
1279 if (!NT_SUCCESS(Status))
1280 {
1281 DPRINT("IOCTL_DISK_SET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
1282 NtClose(FileHandle);
1283 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1284 return FALSE;
1285 }
1286 }
1287 else
1288 {
1289 DPRINT("NtOpenFile failed() 0x%.08x\n", Status);
1290 NtClose(FileHandle);
1291 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1292 return FALSE;
1293 }
1294
1295 NtClose(FileHandle);
1296 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1297
1298 return TRUE;
1299 }
1300
1301 #if 0
1302 BOOLEAN
1303 MarkPartitionActive (ULONG DiskNumber,
1304 ULONG PartitionNumber,
1305 PPARTDATA ActivePartition)
1306 {
1307 PPARTLIST List;
1308 PPARTENTRY PartEntry;
1309 ULONG PartEntryNumber;
1310 OBJECT_ATTRIBUTES ObjectAttributes;
1311 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
1312 IO_STATUS_BLOCK Iosb;
1313 NTSTATUS Status;
1314 WCHAR Buffer[MAX_PATH];
1315 UNICODE_STRING Name;
1316 HANDLE FileHandle;
1317
1318 List = InitializePartitionList ();
1319 if (List == NULL)
1320 {
1321 return(FALSE);
1322 }
1323
1324 PartEntry = GetPartitionInformation(List,
1325 DiskNumber,
1326 PartitionNumber,
1327 &PartEntryNumber);
1328 if (List == NULL)
1329 {
1330 DestroyPartitionList(List);
1331 return(FALSE);
1332 }
1333
1334
1335 swprintf(Buffer,
1336 L"\\Device\\Harddisk%d\\Partition0",
1337 DiskNumber);
1338 RtlInitUnicodeString(&Name, Buffer);
1339
1340 InitializeObjectAttributes(&ObjectAttributes,
1341 &Name,
1342 0,
1343 NULL,
1344 NULL);
1345
1346 Status = NtOpenFile(&FileHandle,
1347 0x10001,
1348 &ObjectAttributes,
1349 &Iosb,
1350 1,
1351 FILE_SYNCHRONOUS_IO_NONALERT);
1352 if (NT_SUCCESS(Status))
1353 {
1354 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
1355
1356 Status = NtDeviceIoControlFile(FileHandle,
1357 NULL,
1358 NULL,
1359 NULL,
1360 &Iosb,
1361 IOCTL_DISK_GET_DRIVE_LAYOUT,
1362 NULL,
1363 0,
1364 LayoutBuffer,
1365 8192);
1366 if (!NT_SUCCESS(Status))
1367 {
1368 NtClose(FileHandle);
1369 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1370 DestroyPartitionList(List);
1371 return FALSE;
1372 }
1373
1374
1375 LayoutBuffer->PartitionEntry[PartEntryNumber].BootIndicator = TRUE;
1376
1377 Status = NtDeviceIoControlFile(FileHandle,
1378 NULL,
1379 NULL,
1380 NULL,
1381 &Iosb,
1382 IOCTL_DISK_SET_DRIVE_LAYOUT,
1383 LayoutBuffer,
1384 8192,
1385 NULL,
1386 0);
1387 if (!NT_SUCCESS(Status))
1388 {
1389 NtClose(FileHandle);
1390 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1391 DestroyPartitionList(List);
1392 return FALSE;
1393 }
1394 }
1395 else
1396 {
1397 NtClose(FileHandle);
1398 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1399 DestroyPartitionList(List);
1400 return FALSE;
1401 }
1402
1403 NtClose(FileHandle);
1404 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
1405
1406 PartEntry->Active = TRUE;
1407 if (!GetActiveBootPartition(List, ActivePartition))
1408 {
1409 DestroyPartitionList(List);
1410 DPRINT("GetActiveBootPartition() failed\n");
1411 return FALSE;
1412 }
1413
1414 DestroyPartitionList(List);
1415
1416 return TRUE;
1417 }
1418 #endif
1419
1420 /* EOF */