reactos/base/setup/usetup/partlist.c
Hermès Bélusca-Maïto b7ad4a2298
[SETUPLIB][USETUP] Some cleanup for partition code.
- Make the Create*Partition helpers take a size in bytes, not in sectors.

  This allows them to be easier to use by the caller, alleviating the
  need for making the size conversion into sectors. Instead it is done
  internally by the helpers.

- Introduce helper macros to easily retrieve the size of a partition
  entry or a disk in bytes, from their internal representation in number
  of sectors.

- The 'AutoCreate' variable being USETUP-specific, remove it from the
  PARTENTRY structure and use instead a flag set into the 'New' member.

- Rename IsDiskSizeValid to IsPartitionLargeEnough, to better describe
  what the function is for.
2024-02-20 15:52:37 +01:00

863 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;
/* 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) ",
(PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
(PartEntry->DriveLetter == 0) ? '-' : ':',
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 (!PartEntry->New && *PartEntry->FileSystem &&
_wcsicmp(PartEntry->FileSystem, L"RAW") != 0)
{
size_t cchLabelSize = 0;
if (*PartEntry->VolumeLabel)
{
RtlStringCchPrintfExA(pBuffer, cchBufferSize,
&pBuffer, &cchLabelSize, 0,
"\"%-.11S\" ",
PartEntry->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),
PartEntry->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 (*PartEntry->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);
}
}
VOID
ScrollDownPartitionList(
IN PPARTLIST_UI ListUi)
{
PPARTENTRY NextPart = GetNextPartition(ListUi->List, ListUi->CurrentPartition);
if (NextPart)
{
ListUi->CurrentPartition = NextPart;
ListUi->CurrentDisk = NextPart->DiskEntry;
DrawPartitionList(ListUi);
}
}
VOID
ScrollUpPartitionList(
IN PPARTLIST_UI ListUi)
{
PPARTENTRY PrevPart = GetPrevPartition(ListUi->List, ListUi->CurrentPartition);
if (PrevPart)
{
ListUi->CurrentPartition = PrevPart;
ListUi->CurrentDisk = PrevPart->DiskEntry;
DrawPartitionList(ListUi);
}
}
/* EOF */