windows-nt/Source/XPSP1/NT/base/efiutil/efilib/efisrc/layout.cxx

328 lines
9.9 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
layout.cxx
Abstract:
This module contains the functions used to determine the disk layout for the EFI filesystem (FAT).
--*/
#include <pch.cxx>
#include "efiwintypes.hxx"
#include "layout.hxx"
BOOLEAN // TRUE if success, FALSE if failure
ChooseLayout(
PPART_DESCRIPTOR PartDes // Pointer to characteristic description of partition
)
{
UINT32 FatType;
UINT32 SectorsPerCluster;
UINT32 FatSectorCount;
//
// Prove that a well formed layout is possible
//
if ( ! ((PartDes->SectorSize == 512) || (PartDes->SectorSize == 1024) ||
(PartDes->SectorSize == 2048) || (PartDes->SectorSize == 4096)) )
{
PartDes->FatType = FAT_TYPE_ILLEGAL;
return FALSE;
}
FatType = FAT_TYPE_ILLEGAL;
if (PartDes->SectorCount >= MinSectorsFat16(PartDes->SectorSize)) {
FatType = FAT_TYPE_F16;
}
if (PartDes->SectorCount >= MinSectorsFat32(PartDes->SectorSize)) {
FatType = FAT_TYPE_F32;
}
PartDes->FatType = FatType;
switch (FatType) {
case FAT_TYPE_F32:
//
// Fill in PartDes completely...
//
//
// SectorCount is already set
// SectorSize is already set
PartDes->HeaderCount = HEADER_F32;
PartDes->FatEntrySize = 4;
PartDes->MinClusterCount = MIN_CLUSTER_F32;
PartDes->MaxClusterCount = MAX_CLUSTER_F32;
// SectorsPerCluster set below
// FatSectorCount set below
// FatType set above
if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
PartDes->SectorsPerCluster = SectorsPerCluster;
PartDes->FatSectorCount = FatSectorCount;
return TRUE;
} else {
DebugPrint("It did not work\n");
return FALSE;
}
break;
case FAT_TYPE_F16:
//
// Fill in PartDes completely...
//
//
// SectorCount is already set
// SectorSize is already set
PartDes->HeaderCount = HEADER_F16 ;
PartDes->FatEntrySize = 2;
PartDes->MinClusterCount = MIN_CLUSTER_F16;
PartDes->MaxClusterCount = MAX_CLUSTER_F16;
// SectorsPerCluster set below
// FatSectorCount set below
// FatType set above
if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
PartDes->SectorsPerCluster = SectorsPerCluster;
PartDes->FatSectorCount = FatSectorCount;
return TRUE;
} else {
DebugPrint("It did not work\n");
return FALSE;
}
break;
default:
DebugAbort("Really Weird Terrible Error...\n");
break;
}
return FALSE;
}
UINT32 // Min. # of sectors for Fat32 part. for given sector size
MinSectorsFat32(
UINT32 SectorSize // The Sector size in question
)
{
UINT32 MinFatSectors32;
UINT32 SectorMin32;
MinFatSectors32 = (SMALLEST_FAT32_BYTES + (SectorSize-1)) / SectorSize;
SectorMin32 =
HEADER_F32 +
(MinFatSectors32*2) + // 2 fats
SAFE_MIN_CLUSTER_F32; // 1 sector for each cluster min
return SectorMin32;
}
UINT32 // Min. # of sectors for Fat16 part. for given sector size
MinSectorsFat16(
UINT32 SectorSize // Sector size to compute for
)
{
UINT32 MinFatSectors16;
UINT32 SectorMin16;
MinFatSectors16 = (SMALLEST_FAT16_BYTES + (SectorSize-1)) / SectorSize;
SectorMin16 =
HEADER_F16 +
(MinFatSectors16*2) + // 2 fats
SAFE_MIN_CLUSTER_F16; // 1 sector for each cluster min
return SectorMin16;
}
BOOLEAN // TRUE for success, FALSE for failure
PickClusterSize(
PPART_DESCRIPTOR PartDes, // characteristics of part. at hand
PUINT32 ReturnedSectorsPerCluster, // RETURNED = number of sectors per cluster
PUINT32 ReturnedFatSectorCount // RETURNED = number of sectors for FAT
)
{
//
// we need a Cluster size >= SectorSize and <= 32K
// we need MinClusterCount <= ClusterCount <= MaxClusterCount
// we want the FAT size to be reasonable.
//
//
// How do we do this? We cheat.
//
// If it's a FAT32 partition (FatEntrySize == 4) we know that we'll
// always have at least approximately 64k clusters, and therefore allow
// at least that many files. So keep upping the cluster size until
// the count falls as low as it can go. This gives a minimum size
// FAT.
//
// If it's a FAT16 partition, we know the FAT table can't take up
// more than 128K of data, so we go for the smallest cluster size we
// can, to make sure there can be as many different files as may be
// needed.
//
// This routine will not work for FAT12 partitions.
//
UINT32 SavedSectorsPerCluster = 0;
UINT32 SavedFatSectorCount = 0;
UINT32 SectorsPerCluster;
UINT32 FatSectorCount;
if (PartDes->FatEntrySize == 4) {
//
// It's a FAT32 partition
//
// Loop along looking for the largest cluster size we can
// get away with
//
SectorsPerCluster = 1;
while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
//
// ComputeFatSize found a FatSectorCount that works with
// this cluster size, so save it, it might be the best one.
//
SavedFatSectorCount = FatSectorCount;
SavedSectorsPerCluster = SectorsPerCluster;
}
//
// If ComputeFatSize returns FALSE, that cluster size didn't work.
// If it returns TRUE, it did work, but the next might work better.
// Keep going until we run out of legal sizes in either case
//
SectorsPerCluster = SectorsPerCluster * 2;
}
} else if (PartDes->FatEntrySize = 2) {
//
// It's a FAT16 partition
//
// Find the *first* (smallest) cluster size that is legal, and use that.
// (Note difference from FAT32 case above)
//
SectorsPerCluster = 1;
while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
//
// ComputeFatSize found a FatSectorCount that works with
// this cluster size, for this loop it's the first one, and
// therefore the smallest cluster size, which is what we
// want for this case. So we are done.
//
SavedFatSectorCount = FatSectorCount;
SavedSectorsPerCluster = SectorsPerCluster;
break;
}
//
// If ComputeFatSize returns FALSE, that cluster size didn't work.
// Keep going until we run out of legal sizes.
//
SectorsPerCluster = SectorsPerCluster * 2;
}
} else {
//
// TERRIBLE ERROR
//
DebugAbort("TERRIBLE ERROR");
return FALSE;
}
//
// At this point, if we have found a workable set of cluster size and
// fat size, it is in the Saved vars. If they are 0, we have found
// nothing that will work.
//
if ((SavedSectorsPerCluster) && (SavedFatSectorCount)) {
*ReturnedSectorsPerCluster = SavedSectorsPerCluster;
*ReturnedFatSectorCount = SavedFatSectorCount;
return TRUE;
} else {
*ReturnedSectorsPerCluster = 0;
*ReturnedSectorsPerCluster = 0;
return FALSE;
}
}
BOOLEAN // FALSE if ERROR, TRUE if SUCCESS
ComputeFatSize(
PPART_DESCRIPTOR PartDes, // partition characteristics to compute for
UINT32 SectorsPerCluster, // number of sectors per cluster
PUINT32 ReturnedFatSectorCount // RETURN Number of FAT sectors in each fat
)
{
UINT32 FatSectorCount;
UINT32 EntryCount;
UINT64 SectorsLeft;
UINT64 SpanCount;
UINT64 ClusterCount;
//
// Start with 1 sector of FAT entries, see if it spans. Keep adding
// 1 sector at a time to the FAT size (and reducing data sectors as we go)
// until the remaining data is spanned (or overspanned) by the number
// of cluster entries that fit in the fat.
//
// If entry count runs out of bounds before we find a working answer,
// report an error. (caller must try again with a different cluster size)
//
FatSectorCount = 1;
while (TRUE) {
EntryCount = ((FatSectorCount * PartDes->SectorSize) / PartDes->FatEntrySize) - 2;
if (EntryCount > PartDes->MaxClusterCount) {
return FALSE; // this cluster size is too small
}
SectorsLeft = PartDes->SectorCount - (PartDes->HeaderCount + (FatSectorCount * 2));
SpanCount = (UINT64)EntryCount * (UINT64)SectorsPerCluster;
if (SpanCount >= (UINT64)SectorsLeft) {
//
// This might work, check it out for sure.
//
ClusterCount = (SectorsLeft / SectorsPerCluster);
if ((ClusterCount >= PartDes->MinClusterCount) &&
(ClusterCount <= PartDes->MaxClusterCount))
{
//
// yup, we found it.
//
*ReturnedFatSectorCount = FatSectorCount;
return TRUE;
} else {
//
// something weird has happened, but the basic result
// is that this cluster size won't work, so fail
//
*ReturnedFatSectorCount = 0;
return FALSE;
}
}
FatSectorCount = FatSectorCount + 1;
}
}