mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
6f15802af7
CORE-13525 This greatly helps in reducing code complexity in some areas: code that previously iterated over all partitions of a given disk, just to find which ones were partitioned and contained a valid file system, now just have to iterate over mounted volumes. See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` . - Remove FORMATSTATE "Preformatted" enum value; - Cleanup osdetect code after introducing Volume support; - Some simplifications for FormatState. - Differentiate between 'new' partition and 'new' volume: * "New" partition: it has been created and added in the cached list, but not yet actually written into the disk. * "New" volume: newly-created volume (may be backed by a partition or not), not yet formatted. May exist on either new, or not new partition, or elsewhere. - Cache partition and volume NT device names. These do not change across repartitioning operations, as long as the partition or the filesystem volume hasn't been deleted/recreated. This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime we need to retrieve the given partition or volume device name. When a partition/fileysystem volume is "virtually" created (i.e. in the partition list, but not yet committed to disk and exposed to the OS), no device partition number and device name are available yet. In particular, validate that no manipulation of \Device\HarddiskM\Partition0 (i.e. the whole disk) is being made.
856 lines
26 KiB
C
856 lines
26 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS text-mode setup
|
|
* FILE: base/setup/usetup/partlist.c
|
|
* PURPOSE: Partition list functions
|
|
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
*/
|
|
|
|
#include "usetup.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* HELPERS FOR DISK AND PARTITION DESCRIPTIONS ******************************/
|
|
|
|
VOID
|
|
GetPartitionTypeString(
|
|
IN PPARTENTRY PartEntry,
|
|
OUT PSTR strBuffer,
|
|
IN ULONG cchBuffer)
|
|
{
|
|
if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED)
|
|
{
|
|
RtlStringCchCopyA(strBuffer, cchBuffer,
|
|
MUIGetString(STRING_FORMATUNUSED));
|
|
}
|
|
else if (IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
RtlStringCchCopyA(strBuffer, cchBuffer,
|
|
MUIGetString(STRING_EXTENDED_PARTITION));
|
|
}
|
|
else
|
|
{
|
|
UINT i;
|
|
|
|
/* Do the table lookup */
|
|
if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_MBR)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(MbrPartitionTypes); ++i)
|
|
{
|
|
if (PartEntry->PartitionType == MbrPartitionTypes[i].Type)
|
|
{
|
|
RtlStringCchCopyA(strBuffer, cchBuffer,
|
|
MbrPartitionTypes[i].Description);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#if 0 // TODO: GPT support!
|
|
else if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(GptPartitionTypes); ++i)
|
|
{
|
|
if (IsEqualPartitionType(PartEntry->PartitionType,
|
|
GptPartitionTypes[i].Guid))
|
|
{
|
|
RtlStringCchCopyA(strBuffer, cchBuffer,
|
|
GptPartitionTypes[i].Description);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* We are here because the partition type is unknown */
|
|
if (cchBuffer > 0) *strBuffer = '\0';
|
|
}
|
|
|
|
if ((cchBuffer > 0) && (*strBuffer == '\0'))
|
|
{
|
|
RtlStringCchPrintfA(strBuffer, cchBuffer,
|
|
MUIGetString(STRING_PARTTYPE),
|
|
PartEntry->PartitionType);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PrettifySize1(
|
|
IN OUT PULONGLONG Size,
|
|
OUT PCSTR* Unit)
|
|
{
|
|
ULONGLONG DiskSize = *Size;
|
|
|
|
if (DiskSize >= 10 * GB) /* 10 GB */
|
|
{
|
|
DiskSize = RoundingDivide(DiskSize, GB);
|
|
*Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
{
|
|
DiskSize = RoundingDivide(DiskSize, MB);
|
|
if (DiskSize == 0)
|
|
DiskSize = 1;
|
|
*Unit = MUIGetString(STRING_MB);
|
|
}
|
|
|
|
*Size = DiskSize;
|
|
}
|
|
|
|
VOID
|
|
PrettifySize2(
|
|
IN OUT PULONGLONG Size,
|
|
OUT PCSTR* Unit)
|
|
{
|
|
ULONGLONG PartSize = *Size;
|
|
|
|
#if 0
|
|
if (PartSize >= 10 * GB) /* 10 GB */
|
|
{
|
|
PartSize = RoundingDivide(PartSize, GB);
|
|
*Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
if (PartSize >= 10 * MB) /* 10 MB */
|
|
{
|
|
PartSize = RoundingDivide(PartSize, MB);
|
|
*Unit = MUIGetString(STRING_MB);
|
|
}
|
|
else
|
|
{
|
|
PartSize = RoundingDivide(PartSize, KB);
|
|
*Unit = MUIGetString(STRING_KB);
|
|
}
|
|
|
|
*Size = PartSize;
|
|
}
|
|
|
|
VOID
|
|
PartitionDescription(
|
|
IN PPARTENTRY PartEntry,
|
|
OUT PSTR strBuffer,
|
|
IN SIZE_T cchBuffer)
|
|
{
|
|
PSTR pBuffer = strBuffer;
|
|
size_t cchBufferSize = cchBuffer;
|
|
ULONGLONG PartSize;
|
|
PCSTR Unit;
|
|
PVOLINFO VolInfo = (PartEntry->Volume ? &PartEntry->Volume->Info : NULL);
|
|
|
|
/* Get the partition size */
|
|
PartSize = GetPartEntrySizeInBytes(PartEntry);
|
|
PrettifySize2(&PartSize, &Unit);
|
|
|
|
if (PartEntry->IsPartitioned == FALSE)
|
|
{
|
|
/* Unpartitioned space: Just display the description and size */
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchBufferSize, 0,
|
|
" %s%-.30s",
|
|
PartEntry->LogicalPartition ? " " : "", // Optional indentation
|
|
MUIGetString(STRING_UNPSPACE));
|
|
|
|
RtlStringCchPrintfA(pBuffer, cchBufferSize,
|
|
"%*s%6I64u %s",
|
|
38 - min(strlen(strBuffer), 38), "", // Indentation
|
|
PartSize,
|
|
Unit);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// NOTE: This could be done with the next case.
|
|
//
|
|
if ((PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_MBR) &&
|
|
IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
/* Extended partition container: Just display the partition's type and size */
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchBufferSize, 0,
|
|
" %-.30s",
|
|
MUIGetString(STRING_EXTENDED_PARTITION));
|
|
|
|
RtlStringCchPrintfA(pBuffer, cchBufferSize,
|
|
"%*s%6I64u %s",
|
|
38 - min(strlen(strBuffer), 38), "", // Indentation
|
|
PartSize,
|
|
Unit);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Not an extended partition container.
|
|
*/
|
|
|
|
/* Drive letter and partition number */
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchBufferSize, 0,
|
|
"%c%c %c %s(%lu) ",
|
|
!(VolInfo && VolInfo->DriveLetter) ? '-' : (CHAR)VolInfo->DriveLetter,
|
|
!(VolInfo && VolInfo->DriveLetter) ? '-' : ':',
|
|
PartEntry->BootIndicator ? '*' : ' ',
|
|
PartEntry->LogicalPartition ? " " : "", // Optional indentation
|
|
PartEntry->PartitionNumber);
|
|
|
|
/*
|
|
* If the volume's file system is recognized, display the volume label
|
|
* (if any) and the file system name. Otherwise, display the partition
|
|
* type if it's not a new partition.
|
|
*/
|
|
if (VolInfo && IsFormatted(VolInfo))
|
|
{
|
|
size_t cchLabelSize = 0;
|
|
if (*VolInfo->VolumeLabel)
|
|
{
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchLabelSize, 0,
|
|
"\"%-.11S\" ",
|
|
VolInfo->VolumeLabel);
|
|
cchLabelSize = cchBufferSize - cchLabelSize; // Actual length of the label part.
|
|
cchBufferSize -= cchLabelSize; // And reset cchBufferSize to what it should be.
|
|
}
|
|
|
|
// TODO: Group this part together with the similar one
|
|
// from below once the strings are in the same encoding...
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchBufferSize, 0,
|
|
"[%-.*S]",
|
|
/* The minimum length can be at most 11 since
|
|
* cchLabelSize can be at most == 11 + 3 == 14 */
|
|
25 - min(cchLabelSize, 25),
|
|
VolInfo->FileSystem);
|
|
}
|
|
else
|
|
{
|
|
CHAR PartTypeString[32];
|
|
PCSTR PartType = PartTypeString;
|
|
|
|
if (PartEntry->New)
|
|
{
|
|
/* Use this description if the partition is new (and thus, not formatted) */
|
|
PartType = MUIGetString(STRING_UNFORMATTED);
|
|
}
|
|
else
|
|
{
|
|
/* If the partition is not new but its file system is not recognized
|
|
* (or is not formatted), use the partition type description. */
|
|
GetPartitionTypeString(PartEntry,
|
|
PartTypeString,
|
|
ARRAYSIZE(PartTypeString));
|
|
PartType = PartTypeString;
|
|
}
|
|
if (!PartType || !*PartType)
|
|
{
|
|
PartType = MUIGetString(STRING_FORMATUNKNOWN);
|
|
}
|
|
|
|
// TODO: Group this part together with the similar one
|
|
// from above once the strings are in the same encoding...
|
|
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
|
|
&pBuffer, &cchBufferSize, 0,
|
|
"[%-.*s]",
|
|
25,
|
|
PartType);
|
|
}
|
|
|
|
/* Show the remaining free space only if a FS is mounted */
|
|
// FIXME: We don't support that yet!
|
|
#if 0
|
|
if (VolInfo && *VolInfo->FileSystem)
|
|
{
|
|
RtlStringCchPrintfA(pBuffer, cchBufferSize,
|
|
"%*s%6I64u %s (%6I64u %s %s)",
|
|
38 - min(strlen(strBuffer), 38), "", // Indentation
|
|
PartSize,
|
|
Unit,
|
|
PartFreeSize,
|
|
Unit,
|
|
"free");
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
RtlStringCchPrintfA(pBuffer, cchBufferSize,
|
|
"%*s%6I64u %s",
|
|
38 - min(strlen(strBuffer), 38), "", // Indentation
|
|
PartSize,
|
|
Unit);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DiskDescription(
|
|
IN PDISKENTRY DiskEntry,
|
|
OUT PSTR strBuffer,
|
|
IN SIZE_T cchBuffer)
|
|
{
|
|
ULONGLONG DiskSize;
|
|
PCSTR Unit;
|
|
|
|
/* Get the disk size */
|
|
DiskSize = GetDiskSizeInBytes(DiskEntry);
|
|
PrettifySize1(&DiskSize, &Unit);
|
|
|
|
//
|
|
// FIXME: We *MUST* use TXTSETUP.SIF strings from section "DiskDriverMap" !!
|
|
//
|
|
if (DiskEntry->DriverName.Length > 0)
|
|
{
|
|
RtlStringCchPrintfA(strBuffer, cchBuffer,
|
|
MUIGetString(STRING_HDDINFO1),
|
|
DiskSize,
|
|
Unit,
|
|
DiskEntry->DiskNumber,
|
|
DiskEntry->Port,
|
|
DiskEntry->Bus,
|
|
DiskEntry->Id,
|
|
&DiskEntry->DriverName,
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
|
|
"RAW");
|
|
}
|
|
else
|
|
{
|
|
RtlStringCchPrintfA(strBuffer, cchBuffer,
|
|
MUIGetString(STRING_HDDINFO2),
|
|
DiskSize,
|
|
Unit,
|
|
DiskEntry->DiskNumber,
|
|
DiskEntry->Port,
|
|
DiskEntry->Bus,
|
|
DiskEntry->Id,
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
|
|
"RAW");
|
|
}
|
|
}
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
VOID
|
|
InitPartitionListUi(
|
|
IN OUT PPARTLIST_UI ListUi,
|
|
IN PPARTLIST List,
|
|
IN PPARTENTRY CurrentEntry OPTIONAL,
|
|
IN SHORT Left,
|
|
IN SHORT Top,
|
|
IN SHORT Right,
|
|
IN SHORT Bottom)
|
|
{
|
|
ListUi->List = List;
|
|
// ListUi->FirstShown = NULL;
|
|
// ListUi->LastShown = NULL;
|
|
|
|
ListUi->Left = Left;
|
|
ListUi->Top = Top;
|
|
ListUi->Right = Right;
|
|
ListUi->Bottom = Bottom;
|
|
|
|
ListUi->Line = 0;
|
|
ListUi->Offset = 0;
|
|
|
|
// ListUi->Redraw = TRUE;
|
|
|
|
/* Search for first usable disk and partition */
|
|
if (!CurrentEntry)
|
|
{
|
|
ListUi->CurrentDisk = NULL;
|
|
ListUi->CurrentPartition = NULL;
|
|
|
|
if (!IsListEmpty(&List->DiskListHead))
|
|
{
|
|
ListUi->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
|
|
DISKENTRY, ListEntry);
|
|
|
|
if (!IsListEmpty(&ListUi->CurrentDisk->PrimaryPartListHead))
|
|
{
|
|
ListUi->CurrentPartition = CONTAINING_RECORD(ListUi->CurrentDisk->PrimaryPartListHead.Flink,
|
|
PARTENTRY, ListEntry);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The CurrentEntry must belong to the associated partition list,
|
|
* and the latter must therefore not be empty.
|
|
*/
|
|
ASSERT(!IsListEmpty(&List->DiskListHead));
|
|
ASSERT(CurrentEntry->DiskEntry->PartList == List);
|
|
|
|
ListUi->CurrentPartition = CurrentEntry;
|
|
ListUi->CurrentDisk = CurrentEntry->DiskEntry;
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
PrintEmptyLine(
|
|
IN PPARTLIST_UI ListUi)
|
|
{
|
|
COORD coPos;
|
|
ULONG Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
|
|
Width = ListUi->Right - ListUi->Left - 1;
|
|
Height = ListUi->Bottom - ListUi->Top - 2;
|
|
|
|
coPos.X = ListUi->Left + 1;
|
|
coPos.Y = ListUi->Top + 1 + ListUi->Line;
|
|
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
ListUi->Line++;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
PrintPartitionData(
|
|
IN PPARTLIST_UI ListUi,
|
|
IN PDISKENTRY DiskEntry,
|
|
IN PPARTENTRY PartEntry)
|
|
{
|
|
COORD coPos;
|
|
ULONG Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
UCHAR Attribute;
|
|
CHAR LineBuffer[100];
|
|
|
|
PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
|
|
|
|
Width = ListUi->Right - ListUi->Left - 1;
|
|
Height = ListUi->Bottom - ListUi->Top - 2;
|
|
|
|
coPos.X = ListUi->Left + 1;
|
|
coPos.Y = ListUi->Top + 1 + ListUi->Line;
|
|
|
|
Attribute = (ListUi->CurrentDisk == DiskEntry &&
|
|
ListUi->CurrentPartition == PartEntry) ?
|
|
FOREGROUND_BLUE | BACKGROUND_WHITE :
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE;
|
|
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X += 4;
|
|
Width -= 8;
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
Attribute,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X++;
|
|
Width -= 2;
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
LineBuffer,
|
|
min(strlen(LineBuffer), Width),
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
ListUi->Line++;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
PrintDiskData(
|
|
IN PPARTLIST_UI ListUi,
|
|
IN PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
|
|
PLIST_ENTRY PrimaryEntry, LogicalEntry;
|
|
COORD coPos;
|
|
ULONG Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
CHAR LineBuffer[100];
|
|
|
|
DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
|
|
|
|
Width = ListUi->Right - ListUi->Left - 1;
|
|
Height = ListUi->Bottom - ListUi->Top - 2;
|
|
|
|
coPos.X = ListUi->Left + 1;
|
|
coPos.Y = ListUi->Top + 1 + ListUi->Line;
|
|
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
coPos.X++;
|
|
if (ListUi->Line >= 0 && ListUi->Line <= Height)
|
|
{
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
LineBuffer,
|
|
min((USHORT)strlen(LineBuffer), Width - 2),
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
ListUi->Line++;
|
|
|
|
/* Print separator line */
|
|
PrintEmptyLine(ListUi);
|
|
|
|
/* Print partition lines */
|
|
for (PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
PrimaryEntry != &DiskEntry->PrimaryPartListHead;
|
|
PrimaryEntry = PrimaryEntry->Flink)
|
|
{
|
|
PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
|
|
|
|
PrintPartitionData(ListUi,
|
|
DiskEntry,
|
|
PrimaryPartEntry);
|
|
|
|
if (IsContainerPartition(PrimaryPartEntry->PartitionType))
|
|
{
|
|
for (LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
|
|
LogicalEntry != &DiskEntry->LogicalPartListHead;
|
|
LogicalEntry = LogicalEntry->Flink)
|
|
{
|
|
LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
|
|
|
|
PrintPartitionData(ListUi,
|
|
DiskEntry,
|
|
LogicalPartEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Print separator line */
|
|
PrintEmptyLine(ListUi);
|
|
}
|
|
|
|
VOID
|
|
DrawPartitionList(
|
|
IN PPARTLIST_UI ListUi)
|
|
{
|
|
PPARTLIST List = ListUi->List;
|
|
PLIST_ENTRY Entry, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry = NULL;
|
|
COORD coPos;
|
|
ULONG Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
SHORT i;
|
|
SHORT CurrentDiskLine;
|
|
SHORT CurrentPartLine;
|
|
SHORT LastLine;
|
|
BOOLEAN CurrentPartLineFound = FALSE;
|
|
BOOLEAN CurrentDiskLineFound = FALSE;
|
|
|
|
Width = ListUi->Right - ListUi->Left - 1;
|
|
Height = ListUi->Bottom - ListUi->Top - 2;
|
|
|
|
/* Calculate the line of the current disk and partition */
|
|
CurrentDiskLine = 0;
|
|
CurrentPartLine = 0;
|
|
LastLine = 0;
|
|
|
|
for (Entry = List->DiskListHead.Flink;
|
|
Entry != &List->DiskListHead;
|
|
Entry = Entry->Flink)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
LastLine += 2;
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine += 2;
|
|
}
|
|
|
|
for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
Entry2 != &DiskEntry->PrimaryPartListHead;
|
|
Entry2 = Entry2->Flink)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry == ListUi->CurrentPartition)
|
|
{
|
|
CurrentPartLineFound = TRUE;
|
|
}
|
|
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine++;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
|
|
Entry2 != &DiskEntry->LogicalPartListHead;
|
|
Entry2 = Entry2->Flink)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry == ListUi->CurrentPartition)
|
|
{
|
|
CurrentPartLineFound = TRUE;
|
|
}
|
|
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine++;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
}
|
|
|
|
if (DiskEntry == ListUi->CurrentDisk)
|
|
{
|
|
CurrentDiskLineFound = TRUE;
|
|
}
|
|
|
|
if (Entry->Flink != &List->DiskListHead)
|
|
{
|
|
if (CurrentDiskLineFound == FALSE)
|
|
{
|
|
CurrentPartLine++;
|
|
CurrentDiskLine = CurrentPartLine;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
else
|
|
{
|
|
LastLine--;
|
|
}
|
|
}
|
|
|
|
/* If it possible, make the disk name visible */
|
|
if (CurrentPartLine < ListUi->Offset)
|
|
{
|
|
ListUi->Offset = CurrentPartLine;
|
|
}
|
|
else if (CurrentPartLine - ListUi->Offset > Height)
|
|
{
|
|
ListUi->Offset = CurrentPartLine - Height;
|
|
}
|
|
|
|
if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < Height)
|
|
{
|
|
ListUi->Offset = CurrentDiskLine;
|
|
}
|
|
|
|
/* Draw upper left corner */
|
|
coPos.X = ListUi->Left;
|
|
coPos.Y = ListUi->Top;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharUpperLeftCorner, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* Draw upper edge */
|
|
coPos.X = ListUi->Left + 1;
|
|
coPos.Y = ListUi->Top;
|
|
if (ListUi->Offset == 0)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
else
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
Width - 4,
|
|
coPos,
|
|
&Written);
|
|
{
|
|
CHAR szBuff[] = "(.)"; // "(up)"
|
|
szBuff[1] = CharUpArrow;
|
|
coPos.X = ListUi->Right - 5;
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
szBuff,
|
|
3,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X = ListUi->Right - 2;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
2,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* Draw upper right corner */
|
|
coPos.X = ListUi->Right;
|
|
coPos.Y = ListUi->Top;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharUpperRightCorner, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* Draw left and right edge */
|
|
for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
|
|
{
|
|
coPos.X = ListUi->Left;
|
|
coPos.Y = i;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharVerticalLine, // '|',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
coPos.X = ListUi->Right;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharVerticalLine, //'|',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* Draw lower left corner */
|
|
coPos.X = ListUi->Left;
|
|
coPos.Y = ListUi->Bottom;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharLowerLeftCorner, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* Draw lower edge */
|
|
coPos.X = ListUi->Left + 1;
|
|
coPos.Y = ListUi->Bottom;
|
|
if (LastLine - ListUi->Offset <= Height)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
else
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
Width - 4,
|
|
coPos,
|
|
&Written);
|
|
{
|
|
CHAR szBuff[] = "(.)"; // "(down)"
|
|
szBuff[1] = CharDownArrow;
|
|
coPos.X = ListUi->Right - 5;
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
szBuff,
|
|
3,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X = ListUi->Right - 2;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharHorizontalLine, // '-',
|
|
2,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* Draw lower right corner */
|
|
coPos.X = ListUi->Right;
|
|
coPos.Y = ListUi->Bottom;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
CharLowerRightCorner, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* Print list entries */
|
|
ListUi->Line = -ListUi->Offset;
|
|
|
|
for (Entry = List->DiskListHead.Flink;
|
|
Entry != &List->DiskListHead;
|
|
Entry = Entry->Flink)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
/* Print disk entry */
|
|
PrintDiskData(ListUi, DiskEntry);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param[in] Direction
|
|
* TRUE or FALSE to scroll to the next (down) or previous (up) entry, respectively.
|
|
**/
|
|
VOID
|
|
ScrollUpDownPartitionList(
|
|
_In_ PPARTLIST_UI ListUi,
|
|
_In_ BOOLEAN Direction)
|
|
{
|
|
PPARTENTRY PartEntry =
|
|
(Direction ? GetNextPartition
|
|
: GetPrevPartition)(ListUi->List, ListUi->CurrentPartition);
|
|
if (PartEntry)
|
|
{
|
|
ListUi->CurrentPartition = PartEntry;
|
|
ListUi->CurrentDisk = PartEntry->DiskEntry;
|
|
DrawPartitionList(ListUi);
|
|
}
|
|
}
|
|
|
|
/* EOF */
|