update for HEAD-2003021201
[reactos.git] / 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$
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  */
26
27 #include <ddk/ntddk.h>
28 #include <ddk/ntddscsi.h>
29
30 #include <ntdll/rtl.h>
31
32 #include <ntos/minmax.h>
33
34 #include "usetup.h"
35 #include "console.h"
36 #include "partlist.h"
37 #include "drivesup.h"
38
39
40 /* FUNCTIONS ****************************************************************/
41
42 static VOID
43 AddPartitionList(ULONG DiskNumber,
44                  PDISKENTRY DiskEntry,
45                  DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
46 {
47   PPARTENTRY PartEntry;
48   ULONG i;
49   ULONG EntryCount;
50
51
52   /*
53    * FIXME:
54    * Determine required number of partiton entries.
55    * This must include entries for unused disk space.
56    */
57
58   /* Check for unpartitioned disk */
59   if (LayoutBuffer->PartitionCount == 0)
60     {
61       EntryCount = 1;
62     }
63   else
64     {
65
66 #if 0
67   for (i = 0; i < LayoutBuffer->PartitionCount; i++)
68     {
69
70     }
71 #endif
72
73       EntryCount = LayoutBuffer->PartitionCount;
74     }
75
76
77   DiskEntry->PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
78                                                      0,
79                                                      EntryCount * sizeof(PARTENTRY));
80   DiskEntry->PartCount = EntryCount;
81
82   RtlZeroMemory(DiskEntry->PartArray,
83                 EntryCount * sizeof(PARTENTRY));
84
85   if (LayoutBuffer->PartitionCount == 0)
86     {
87       /* Initialize an 'Unpartitioned space' entry */
88       PartEntry = &DiskEntry->PartArray[0];
89
90       PartEntry->Unpartitioned = TRUE;
91       PartEntry->PartSize = 0; /* ?? */
92
93       PartEntry->Used = TRUE;
94     }
95   else
96     {
97       for (i = 0; i < LayoutBuffer->PartitionCount; i++)
98         {
99           PartEntry = &DiskEntry->PartArray[i];
100
101           if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
102               (!IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType)))
103             {
104               PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
105               PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
106               PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
107               PartEntry->Active = LayoutBuffer->PartitionEntry[i].BootIndicator;
108
109               PartEntry->DriveLetter = GetDriveLetter(DiskNumber,
110                                                       LayoutBuffer->PartitionEntry[i].PartitionNumber);
111
112               PartEntry->Unpartitioned = FALSE;
113
114               PartEntry->Used = TRUE;
115             }
116           else
117             {
118               PartEntry->Used = FALSE;
119             }
120         }
121     }
122 }
123
124
125 static VOID
126 GetDriverName(PDISKENTRY DiskEntry)
127 {
128   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
129   WCHAR KeyName[32];
130   NTSTATUS Status;
131
132   RtlInitUnicodeString(&DiskEntry->DriverName,
133                        NULL);
134
135   swprintf(KeyName,
136            L"\\Scsi\\Scsi Port %lu",
137            DiskEntry->Port);
138
139   RtlZeroMemory(&QueryTable,
140                 sizeof(QueryTable));
141
142   QueryTable[0].Name = L"Driver";
143   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
144   QueryTable[0].EntryContext = &DiskEntry->DriverName;
145
146   Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
147                                   KeyName,
148                                   QueryTable,
149                                   NULL,
150                                   NULL);
151   if (!NT_SUCCESS(Status))
152     {
153       DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
154     }
155 }
156
157
158 PPARTLIST
159 CreatePartitionList(SHORT Left,
160                     SHORT Top,
161                     SHORT Right,
162                     SHORT Bottom)
163 {
164   PPARTLIST List;
165   OBJECT_ATTRIBUTES ObjectAttributes;
166   SYSTEM_DEVICE_INFORMATION Sdi;
167   DISK_GEOMETRY DiskGeometry;
168   IO_STATUS_BLOCK Iosb;
169   ULONG ReturnSize;
170   NTSTATUS Status;
171   ULONG DiskNumber;
172   WCHAR Buffer[MAX_PATH];
173   UNICODE_STRING Name;
174   HANDLE FileHandle;
175   DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
176   SCSI_ADDRESS ScsiAddress;
177
178   List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
179   if (List == NULL)
180     return(NULL);
181
182   List->Left = Left;
183   List->Top = Top;
184   List->Right = Right;
185   List->Bottom = Bottom;
186
187   List->Line = 0;
188
189   List->TopDisk = (ULONG)-1;
190   List->TopPartition = (ULONG)-1;
191
192   List->CurrentDisk = (ULONG)-1;
193   List->CurrentPartition = (ULONG)-1;
194
195   List->DiskCount = 0;
196   List->DiskArray = NULL;
197
198
199   Status = NtQuerySystemInformation(SystemDeviceInformation,
200                                     &Sdi,
201                                     sizeof(SYSTEM_DEVICE_INFORMATION),
202                                     &ReturnSize);
203   if (!NT_SUCCESS(Status))
204     {
205       RtlFreeHeap(ProcessHeap, 0, List);
206       return(NULL);
207     }
208
209   List->DiskArray = (PDISKENTRY)RtlAllocateHeap(ProcessHeap,
210                                                 0,
211                                                 Sdi.NumberOfDisks * sizeof(DISKENTRY));
212   List->DiskCount = Sdi.NumberOfDisks;
213
214   for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
215     {
216       swprintf(Buffer,
217                L"\\Device\\Harddisk%d\\Partition0",
218                DiskNumber);
219       RtlInitUnicodeString(&Name,
220                            Buffer);
221
222       InitializeObjectAttributes(&ObjectAttributes,
223                                  &Name,
224                                  0,
225                                  NULL,
226                                  NULL);
227
228       Status = NtOpenFile(&FileHandle,
229                           0x10001,
230                           &ObjectAttributes,
231                           &Iosb,
232                           1,
233                           FILE_SYNCHRONOUS_IO_NONALERT);
234       if (NT_SUCCESS(Status))
235         {
236           Status = NtDeviceIoControlFile(FileHandle,
237                                          NULL,
238                                          NULL,
239                                          NULL,
240                                          &Iosb,
241                                          IOCTL_DISK_GET_DRIVE_GEOMETRY,
242                                          NULL,
243                                          0,
244                                          &DiskGeometry,
245                                          sizeof(DISK_GEOMETRY));
246           if (NT_SUCCESS(Status))
247             {
248               if (DiskGeometry.MediaType == FixedMedia)
249                 {
250                   Status = NtDeviceIoControlFile(FileHandle,
251                                                  NULL,
252                                                  NULL,
253                                                  NULL,
254                                                  &Iosb,
255                                                  IOCTL_SCSI_GET_ADDRESS,
256                                                  NULL,
257                                                  0,
258                                                  &ScsiAddress,
259                                                  sizeof(SCSI_ADDRESS));
260
261
262                   List->DiskArray[DiskNumber].DiskSize = 
263                     DiskGeometry.Cylinders.QuadPart *
264                     (ULONGLONG)DiskGeometry.TracksPerCylinder *
265                     (ULONGLONG)DiskGeometry.SectorsPerTrack *
266                     (ULONGLONG)DiskGeometry.BytesPerSector;
267                   List->DiskArray[DiskNumber].DiskNumber = DiskNumber;
268                   List->DiskArray[DiskNumber].Port = ScsiAddress.PortNumber;
269                   List->DiskArray[DiskNumber].Bus = ScsiAddress.PathId;
270                   List->DiskArray[DiskNumber].Id = ScsiAddress.TargetId;
271
272                   List->DiskArray[DiskNumber].FixedDisk = TRUE;
273
274                   GetDriverName(&List->DiskArray[DiskNumber]);
275
276                   LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
277
278                   Status = NtDeviceIoControlFile(FileHandle,
279                                                  NULL,
280                                                  NULL,
281                                                  NULL,
282                                                  &Iosb,
283                                                  IOCTL_DISK_GET_DRIVE_LAYOUT,
284                                                  NULL,
285                                                  0,
286                                                  LayoutBuffer,
287                                                  8192);
288                   if (NT_SUCCESS(Status))
289                     {
290                       AddPartitionList(DiskNumber,
291                                        &List->DiskArray[DiskNumber],
292                                        LayoutBuffer);
293                     }
294
295                   RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
296                 }
297               else
298                 {
299                   /* mark removable disk entry */
300                   List->DiskArray[DiskNumber].FixedDisk = FALSE;
301                   List->DiskArray[DiskNumber].PartCount = 0;
302                   List->DiskArray[DiskNumber].PartArray = NULL;
303                 }
304             }
305
306           NtClose(FileHandle);
307         }
308     }
309
310   List->TopDisk = 0;
311   List->TopPartition = 0;
312
313   /* FIXME: search for first usable disk and partition */
314   List->CurrentDisk = 0;
315   List->CurrentPartition = 0;
316
317   DrawPartitionList(List);
318
319   return(List);
320 }
321
322
323 VOID
324 DestroyPartitionList(PPARTLIST List)
325 {
326   ULONG i;
327 #if 0
328   COORD coPos;
329   USHORT Width;
330
331   /* clear occupied screen area */
332   coPos.X = List->Left;
333   Width = List->Right - List->Left + 1;
334   for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
335     {
336       FillConsoleOutputAttribute(0x17,
337                                  Width,
338                                  coPos,
339                                  &i);
340
341       FillConsoleOutputCharacter(' ',
342                                  Width,
343                                  coPos,
344                                  &i);
345     }
346 #endif
347
348   /* Release disk and partition info */
349   if (List->DiskArray != NULL)
350     {
351       for (i = 0; i < List->DiskCount; i++)
352         {
353           /* Release driver name */
354           RtlFreeUnicodeString(&List->DiskArray[i].DriverName);
355
356           /* Release partition array */
357           if (List->DiskArray[i].PartArray != NULL)
358             {
359               RtlFreeHeap(ProcessHeap, 0, List->DiskArray[i].PartArray);
360               List->DiskArray[i].PartCount = 0;
361               List->DiskArray[i].PartArray = NULL;
362             }
363         }
364
365       /* Release disk array */
366       RtlFreeHeap(ProcessHeap, 0, List->DiskArray);
367       List->DiskCount = 0;
368       List->DiskArray = NULL;
369     }
370
371   /* Release list head */
372   RtlFreeHeap(ProcessHeap, 0, List);
373 }
374
375
376 static VOID
377 PrintEmptyLine(PPARTLIST List)
378 {
379   COORD coPos;
380   ULONG Written;
381   USHORT Width;
382   USHORT Height;
383
384   Width = List->Right - List->Left - 1;
385   Height = List->Bottom - List->Top - 1;
386
387   if (List->Line < 0 || List->Line > Height)
388     return;
389
390   coPos.X = List->Left + 1;
391   coPos.Y = List->Top + 1 + List->Line;
392
393   FillConsoleOutputAttribute(0x17,
394                              Width,
395                              coPos,
396                              &Written);
397
398   FillConsoleOutputCharacter(' ',
399                              Width,
400                              coPos,
401                              &Written);
402
403   List->Line++;
404 }
405
406
407 static VOID
408 PrintPartitionData(PPARTLIST List,
409                    SHORT DiskIndex,
410                    SHORT PartIndex)
411 {
412   PPARTENTRY PartEntry;
413   CHAR LineBuffer[128];
414   COORD coPos;
415   ULONG Written;
416   USHORT Width;
417   USHORT Height;
418
419   ULONGLONG PartSize;
420   PCHAR Unit;
421   UCHAR Attribute;
422   PCHAR PartType;
423
424   Width = List->Right - List->Left - 1;
425   Height = List->Bottom - List->Top - 1;
426
427   if (List->Line < 0 || List->Line > Height)
428     return;
429
430   coPos.X = List->Left + 1;
431   coPos.Y = List->Top + 1 + List->Line;
432
433   PartEntry = &List->DiskArray[DiskIndex].PartArray[PartIndex];
434
435   /* Determine partition type */
436   PartType = NULL;
437   if (PartEntry->Unpartitioned == FALSE)
438     {
439       if ((PartEntry->PartType == PARTITION_FAT_12) ||
440           (PartEntry->PartType == PARTITION_FAT_16) ||
441           (PartEntry->PartType == PARTITION_HUGE) ||
442           (PartEntry->PartType == PARTITION_XINT13))
443         {
444           PartType = "FAT";
445         }
446       else if ((PartEntry->PartType == PARTITION_FAT32) ||
447                (PartEntry->PartType == PARTITION_FAT32_XINT13))
448         {
449           PartType = "FAT32";
450         }
451      else if (PartEntry->PartType == PARTITION_IFS)
452         {
453           PartType = "NTFS"; /* FIXME: Not quite correct! */
454         }
455     }
456
457
458 #if 0
459   if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
460     {
461       PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
462       Unit = "GB";
463     }
464   else
465 #endif
466   if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
467     {
468       PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
469       Unit = "MB";
470     }
471   else
472     {
473       PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
474       Unit = "KB";
475     }
476
477
478   if (PartEntry->Unpartitioned == TRUE)
479     {
480       sprintf(LineBuffer,
481               "    Unpartitioned space              %I64u %s",
482               PartSize,
483               Unit);
484     }
485   else if (PartEntry->DriveLetter != (CHAR)0)
486     {
487       if (PartType == NULL)
488         {
489           sprintf(LineBuffer,
490                   "%c:  Type %-3lu                        %I64u %s",
491                   PartEntry->DriveLetter,
492                   PartEntry->PartType,
493                   PartSize,
494                   Unit);
495         }
496       else
497         {
498           sprintf(LineBuffer,
499                   "%c:  %s                         %I64u %s",
500                   PartEntry->DriveLetter,
501                   PartType,
502                   PartSize,
503                   Unit);
504         }
505
506 #if 0
507       sprintf(LineBuffer,
508               "%c:  %s  (%d: nr: %d type: %x)  %I64u %s",
509               PartEntry->DriveLetter,
510               PartType,
511               PartIndex,
512               PartEntry->PartNumber,
513               PartEntry->PartType,
514               PartSize,
515               Unit);
516 #endif
517     }
518   else
519     {
520       sprintf(LineBuffer,
521               "--  %s  (%d: nr: %d type: %x)  %I64u %s",
522               PartEntry->FileSystemName,
523               PartIndex,
524               PartEntry->PartNumber,
525               PartEntry->PartType,
526               PartSize,
527               Unit);
528     }
529
530   Attribute = (List->CurrentDisk == DiskIndex &&
531                List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
532
533   FillConsoleOutputCharacter(' ',
534                              Width,
535                              coPos,
536                              &Written);
537
538   coPos.X += 4;
539   Width -= 8;
540   FillConsoleOutputAttribute(Attribute,
541                              Width,
542                              coPos,
543                              &Written);
544
545   coPos.X++;
546   Width -= 2;
547   WriteConsoleOutputCharacters(LineBuffer,
548                                min(strlen(LineBuffer), Width),
549                                coPos);
550
551   List->Line++;
552 }
553
554
555 static VOID
556 PrintDiskData(PPARTLIST List,
557               SHORT DiskIndex)
558 {
559   PDISKENTRY DiskEntry;
560   CHAR LineBuffer[128];
561   COORD coPos;
562   ULONG Written;
563   USHORT Width;
564   USHORT Height;
565   ULONGLONG DiskSize;
566   PCHAR Unit;
567   SHORT PartIndex;
568
569   DiskEntry = &List->DiskArray[DiskIndex];
570
571   Width = List->Right - List->Left - 1;
572   Height = List->Bottom - List->Top - 1;
573
574   if (List->Line < 0 || List->Line > Height)
575     return;
576
577   coPos.X = List->Left + 1;
578   coPos.Y = List->Top + 1 + List->Line;
579
580 #if 0
581   if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
582     {
583       DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
584       Unit = "GB";
585     }
586   else
587 #endif
588     {
589       DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
590       if (DiskSize == 0)
591         DiskSize = 1;
592       Unit = "MB";
593     }
594
595   if (DiskEntry->DriverName.Length > 0)
596     {
597       sprintf(LineBuffer,
598               "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
599               DiskSize,
600               Unit,
601               DiskEntry->DiskNumber,
602               DiskEntry->Port,
603               DiskEntry->Bus,
604               DiskEntry->Id,
605               &DiskEntry->DriverName);
606     }
607   else
608     {
609       sprintf(LineBuffer,
610               "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu)",
611               DiskSize,
612               Unit,
613               DiskEntry->DiskNumber,
614               DiskEntry->Port,
615               DiskEntry->Bus,
616               DiskEntry->Id);
617     }
618
619   FillConsoleOutputAttribute(0x17,
620                              Width,
621                              coPos,
622                              &Written);
623
624   FillConsoleOutputCharacter(' ',
625                              Width,
626                              coPos,
627                              &Written);
628
629   coPos.X++;
630   WriteConsoleOutputCharacters(LineBuffer,
631                                min(strlen(LineBuffer), Width - 2),
632                                coPos);
633
634   List->Line++;
635
636   /* Print separator line */
637   PrintEmptyLine(List);
638
639
640   /* Print partition lines*/
641   for (PartIndex = 0; PartIndex < DiskEntry->PartCount; PartIndex++)
642     {
643       if (DiskEntry->PartArray[PartIndex].Used == TRUE)
644         {
645           PrintPartitionData(List,
646                              DiskIndex,
647                              PartIndex);
648         }
649     }
650
651   /* Print separator line */
652   PrintEmptyLine(List);
653 }
654
655
656 VOID
657 DrawPartitionList(PPARTLIST List)
658 {
659   CHAR LineBuffer[128];
660   COORD coPos;
661   ULONG Written;
662   SHORT i;
663   SHORT DiskIndex;
664
665   /* draw upper left corner */
666   coPos.X = List->Left;
667   coPos.Y = List->Top;
668   FillConsoleOutputCharacter(0xDA, // '+',
669                              1,
670                              coPos,
671                              &Written);
672
673   /* draw upper edge */
674   coPos.X = List->Left + 1;
675   coPos.Y = List->Top;
676   FillConsoleOutputCharacter(0xC4, // '-',
677                              List->Right - List->Left - 1,
678                              coPos,
679                              &Written);
680
681   /* draw upper right corner */
682   coPos.X = List->Right;
683   coPos.Y = List->Top;
684   FillConsoleOutputCharacter(0xBF, // '+',
685                              1,
686                              coPos,
687                              &Written);
688
689   /* draw left and right edge */
690   for (i = List->Top + 1; i < List->Bottom; i++)
691     {
692       coPos.X = List->Left;
693       coPos.Y = i;
694       FillConsoleOutputCharacter(0xB3, // '|',
695                                  1,
696                                  coPos,
697                                  &Written);
698
699       coPos.X = List->Right;
700       FillConsoleOutputCharacter(0xB3, //'|',
701                                  1,
702                                  coPos,
703                                  &Written);
704     }
705
706   /* draw lower left corner */
707   coPos.X = List->Left;
708   coPos.Y = List->Bottom;
709   FillConsoleOutputCharacter(0xC0, // '+',
710                              1,
711                              coPos,
712                              &Written);
713
714   /* draw lower edge */
715   coPos.X = List->Left + 1;
716   coPos.Y = List->Bottom;
717   FillConsoleOutputCharacter(0xC4, // '-',
718                              List->Right - List->Left - 1,
719                              coPos,
720                              &Written);
721
722   /* draw lower right corner */
723   coPos.X = List->Right;
724   coPos.Y = List->Bottom;
725   FillConsoleOutputCharacter(0xD9, // '+',
726                              1,
727                              coPos,
728                              &Written);
729
730   /* print list entries */
731   List->Line = 0;
732   for (DiskIndex = 0; DiskIndex < List->DiskCount; DiskIndex++)
733     {
734       if (List->DiskArray[DiskIndex].FixedDisk == TRUE)
735         {
736           /* Print disk entry */
737           PrintDiskData(List,
738                         DiskIndex);
739         }
740     }
741 }
742
743
744 VOID
745 ScrollDownPartitionList(PPARTLIST List)
746 {
747   ULONG i;
748   ULONG j;
749
750   /* check for available disks */
751   if (List->DiskCount == 0)
752     return;
753
754   /* check for next usable entry on current disk */
755   for (i = List->CurrentPartition + 1; i < List->DiskArray[List->CurrentDisk].PartCount; i++)
756     {
757       if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
758         {
759           List->CurrentPartition = i;
760           DrawPartitionList(List);
761           return;
762         }
763     }
764
765   /* check for first usable entry on next disk */
766   for (j = List->CurrentDisk + 1; j < List->DiskCount; j++)
767     {
768       for (i = 0; i < List->DiskArray[j].PartCount; i++)
769         {
770           if (List->DiskArray[j].PartArray[i].Used == TRUE)
771             {
772               List->CurrentDisk = j;
773               List->CurrentPartition = i;
774               DrawPartitionList(List);
775               return;
776             }
777         }
778     }
779 }
780
781
782 VOID
783 ScrollUpPartitionList(PPARTLIST List)
784 {
785   ULONG i;
786   ULONG j;
787
788   /* check for available disks */
789   if (List->DiskCount == 0)
790     return;
791
792   /* check for previous usable entry on current disk */
793   for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
794     {
795       if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
796         {
797           List->CurrentPartition = i;
798           DrawPartitionList(List);
799           return;
800         }
801     }
802
803   /* check for last usable entry on previous disk */
804   for (j = List->CurrentDisk - 1; j != (ULONG)-1; j--)
805     {
806       for (i = List->DiskArray[j].PartCount - 1; i != (ULONG)-1; i--)
807         {
808           if (List->DiskArray[j].PartArray[i].Used == TRUE)
809             {
810               List->CurrentDisk = j;
811               List->CurrentPartition = i;
812               DrawPartitionList(List);
813               return;
814             }
815         }
816     }
817 }
818
819
820 BOOL
821 GetSelectedPartition(PPARTLIST List,
822                      PPARTDATA Data)
823 {
824   PDISKENTRY DiskEntry;
825   PPARTENTRY PartEntry;
826
827   if (List->CurrentDisk >= List->DiskCount)
828     return(FALSE);
829
830   DiskEntry = &List->DiskArray[List->CurrentDisk];
831
832   if (DiskEntry->FixedDisk == FALSE)
833     return(FALSE);
834
835   if (List->CurrentPartition >= DiskEntry->PartCount)
836     return(FALSE);
837
838   PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
839
840   if (PartEntry->Used == FALSE)
841     return(FALSE);
842
843   /* Copy disk-specific data */
844   Data->DiskSize = DiskEntry->DiskSize;
845   Data->DiskNumber = DiskEntry->DiskNumber;
846   Data->Port = DiskEntry->Port;
847   Data->Bus = DiskEntry->Bus;
848   Data->Id = DiskEntry->Id;
849
850   /* Copy driver name */
851   RtlInitUnicodeString(&Data->DriverName,
852                        NULL);
853   if (DiskEntry->DriverName.Length != 0)
854     {
855       Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
856                                                 0,
857                                                 DiskEntry->DriverName.MaximumLength);
858       if (Data->DriverName.Buffer != NULL)
859         {
860           Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
861           Data->DriverName.Length = DiskEntry->DriverName.Length;
862           RtlCopyMemory(Data->DriverName.Buffer,
863                         DiskEntry->DriverName.Buffer,
864                         DiskEntry->DriverName.MaximumLength);
865         }
866     }
867
868   /* Copy partition-specific data */
869   Data->PartSize = PartEntry->PartSize;
870   Data->PartNumber = PartEntry->PartNumber;
871   Data->PartType = PartEntry->PartType;
872   Data->DriveLetter = PartEntry->DriveLetter;
873
874   return(TRUE);
875 }
876
877
878 BOOL
879 GetActiveBootPartition(PPARTLIST List,
880                        PPARTDATA Data)
881 {
882   PDISKENTRY DiskEntry;
883   PPARTENTRY PartEntry;
884   ULONG i;
885
886   if (List->CurrentDisk >= List->DiskCount)
887     return(FALSE);
888
889   DiskEntry = &List->DiskArray[0];
890
891   if (DiskEntry->FixedDisk == FALSE)
892     return(FALSE);
893
894   for (i = 0; i < DiskEntry->PartCount; i++)
895     {
896       if (DiskEntry->PartArray[i].Active)
897         {
898           PartEntry = &DiskEntry->PartArray[i];
899
900           if (PartEntry->Used == FALSE)
901             return(FALSE);
902
903           /* Copy disk-specific data */
904           Data->DiskSize = DiskEntry->DiskSize;
905           Data->DiskNumber = DiskEntry->DiskNumber;
906           Data->Port = DiskEntry->Port;
907           Data->Bus = DiskEntry->Bus;
908           Data->Id = DiskEntry->Id;
909
910           /* Copy driver name */
911           RtlInitUnicodeString(&Data->DriverName,
912                                NULL);
913           if (DiskEntry->DriverName.Length != 0)
914             {
915               Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
916                                                         0,
917                                                         DiskEntry->DriverName.MaximumLength);
918               if (Data->DriverName.Buffer != NULL)
919                 {
920                   Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
921                   Data->DriverName.Length = DiskEntry->DriverName.Length;
922                   RtlCopyMemory(Data->DriverName.Buffer,
923                                 DiskEntry->DriverName.Buffer,
924                                 DiskEntry->DriverName.MaximumLength);
925                 }
926             }
927
928           /* Copy partition-specific data */
929           Data->PartSize = PartEntry->PartSize;
930           Data->PartNumber = PartEntry->PartNumber;
931           Data->PartType = PartEntry->PartType;
932           Data->DriveLetter = PartEntry->DriveLetter;
933
934           return(TRUE);
935         }
936     }
937
938   return(FALSE);
939 }
940
941
942 /* EOF */