[FREELDR] Optimize and refactor the FAT driver.

Do not read the whole cluster chain for file on opening.
This removes restriction for opening files which span
within a large amount of clusters (>65k). That happened because
FrLdrTempAlloc cannot allocate more than about 256 KiB of memory.

Adjacent clusters for file are now read using one disk driver call.
This commit is contained in:
Victor Perevertkin 2019-07-19 02:57:11 +03:00
parent 195dc30484
commit 220bc820eb
2 changed files with 152 additions and 178 deletions

View file

@ -147,11 +147,12 @@ typedef struct _FAT_VOLUME_INFO *PFAT_VOLUME_INFO;
typedef struct
{
UCHAR Attributes; /* File attributes */
PFAT_VOLUME_INFO Volume;
ULONG FileSize; /* File size */
ULONG FilePointer; /* File pointer */
ULONG* FileFatChain; /* File fat chain array */
PFAT_VOLUME_INFO Volume;
ULONG CurrentCluster; /* The cluster for file pointer */
ULONG StartCluster; /* The first cluster for file */
UCHAR Attributes; /* File attributes */
} FAT_FILE_INFO, * PFAT_FILE_INFO;
#define ATTR_NORMAL 0x00

View file

@ -1,21 +1,10 @@
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
* Copyright (C) 2009 Hervé Poussineau
*
* 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.
* PROJECT: FreeLoader
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: FAT filesystem driver for FreeLoader
* COPYRIGHT: Copyright 1998-2003 Brian Palmer (brianp@sginet.com)
* Copyright 2009 Hervé Poussineau
* Copyright 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include <freeldr.h>
@ -28,13 +17,17 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster
BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer);
ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer);
void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry);
BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer);
ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster);
ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster);
BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer);
static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer);
static ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, UINT32 StartCluster);
static BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber);
BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer);
BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer);
#define FAT_IS_END_CLUSTER(clnumber) \
(((Volume->FatType == FAT12) && (clnumber >= 0xff8)) || \
((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (clnumber >= 0xfff8)) || \
((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (clnumber >= 0x0ffffff8)))
#define TAG_FAT_CHAIN 'CtaT'
#define TAG_FAT_FILE 'FtaF'
#define TAG_FAT_VOLUME 'VtaF'
@ -494,7 +487,7 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, U
}
else
{
if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer->Data))
if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer->Data, NULL))
{
FrLdrTempFree(DirectoryBuffer, TAG_FAT_BUFFER);
return NULL;
@ -682,6 +675,9 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
FatFileInfoPointer->Attributes = DirEntry->Attr;
FatFileInfoPointer->FileSize = DirEntry->Size;
FatFileInfoPointer->FilePointer = 0;
StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
FatFileInfoPointer->CurrentCluster = StartCluster;
FatFileInfoPointer->StartCluster = StartCluster;
TRACE("MSDOS Directory Entry:\n");
TRACE("FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n", DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4], DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]);
@ -696,21 +692,7 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
TRACE("Date = %d\n", DirEntry->Date);
TRACE("ClusterLow = 0x%x\n", DirEntry->ClusterLow);
TRACE("Size = %d\n", DirEntry->Size);
//
// Get the cluster chain
//
StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
TRACE("StartCluster = 0x%x\n", StartCluster);
FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(Volume, StartCluster);
//
// See if memory allocation failed
//
if (FatFileInfoPointer->FileFatChain == NULL)
{
return FALSE;
}
return TRUE;
}
@ -761,6 +743,8 @@ static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID D
FatFileInfoPointer->Attributes = DirEntry->Attr;
FatFileInfoPointer->FileSize = DirEntry->Size;
FatFileInfoPointer->FilePointer = 0;
FatFileInfoPointer->CurrentCluster = DirEntry->StartCluster;
FatFileInfoPointer->StartCluster = DirEntry->StartCluster;
TRACE("FATX Directory Entry:\n");
TRACE("FileNameSize = %d\n", DirEntry->FileNameSize);
@ -774,19 +758,6 @@ static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID D
TRACE("LastAccessTime = %d\n", DirEntry->LastAccessTime);
TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate);
/*
* Get the cluster chain
*/
FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(Volume, DirEntry->StartCluster);
/*
* See if memory allocation failed
*/
if (NULL == FatFileInfoPointer->FileFatChain)
{
return FALSE;
}
return TRUE;
}
}
@ -875,12 +846,9 @@ ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO
//
if (!(FatFileInfo.Attributes & ATTR_DIRECTORY))
{
FrLdrTempFree(FatFileInfo.FileFatChain, TAG_FAT_CHAIN);
return ENOTDIR;
}
DirectoryStartCluster = FatFileInfo.FileFatChain[0];
FrLdrTempFree(FatFileInfo.FileFatChain, TAG_FAT_CHAIN);
FatFileInfo.FileFatChain = NULL;
DirectoryStartCluster = FatFileInfo.StartCluster;
}
}
@ -979,7 +947,8 @@ PUCHAR FatGetFatSector(PFAT_VOLUME_INFO Volume, UINT32 FatSectorNumber)
* FatGetFatEntry()
* returns the Fat entry for a given cluster number
*/
BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer)
static
BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer)
{
UINT32 FatOffset, ThisFatSecNum, ThisFatEntOffset, fat;
PUCHAR ReadBuffer;
@ -1047,8 +1016,7 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
if (!ReadBuffer)
{
Success = FALSE;
break;
return FALSE;
}
// Get the fat entry
@ -1069,7 +1037,8 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
return TRUE;
}
ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
static
ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, UINT32 StartCluster)
{
ULONG ClusterCount = 0;
@ -1080,9 +1049,7 @@ ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
//
// If end of chain then break out of our cluster counting loop
//
if (((Volume->FatType == FAT12) && (StartCluster >= 0xff8)) ||
((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartCluster >= 0xfff8)) ||
((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
if (FAT_IS_END_CLUSTER(StartCluster))
{
break;
}
@ -1106,119 +1073,76 @@ ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
return ClusterCount;
}
ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
static
BOOLEAN FatReadAdjacentClusters(
PFAT_VOLUME_INFO Volume,
UINT32 StartClusterNumber,
UINT32 MaxClusters,
PVOID Buffer,
PUINT32 ClustersRead,
PUINT32 LastClusterNumber)
{
ULONG ClusterCount;
ULONG ArraySize;
ULONG* ArrayPointer;
ULONG Idx;
UINT32 NextClusterNumber;
UINT32 ClustersToRead = 1;
UINT32 PrevClusterNumber = StartClusterNumber;
UINT32 ClusterStartSector = ((PrevClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
TRACE("FatGetClusterChainArray() StartCluster = %d\n", StartCluster);
*ClustersRead = 0;
*LastClusterNumber = 0;
ClusterCount = FatCountClustersInChain(Volume, StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array
ArraySize = ClusterCount * sizeof(ULONG);
//
// Allocate array memory
//
ArrayPointer = FrLdrTempAlloc(ArraySize, TAG_FAT_CHAIN);
if (ArrayPointer == NULL)
if (!FatGetFatEntry(Volume, StartClusterNumber, &NextClusterNumber))
{
return NULL;
return FALSE;
}
//
// Loop through and set array values
//
for (Idx=0; Idx<ClusterCount; Idx++)
// getting the number of adjacent clusters
while (!FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters && (NextClusterNumber == PrevClusterNumber + 1))
{
//
// Set current cluster
//
ArrayPointer[Idx] = StartCluster;
//
// Don't try to get next cluster for last cluster
//
if (((Volume->FatType == FAT12) && (StartCluster >= 0xff8)) ||
((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartCluster >= 0xfff8)) ||
((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
ClustersToRead++;
PrevClusterNumber = NextClusterNumber;
if (!FatGetFatEntry(Volume, PrevClusterNumber, &NextClusterNumber))
{
Idx++;
break;
}
//
// Get next cluster
//
if (!FatGetFatEntry(Volume, StartCluster, &StartCluster))
{
FrLdrTempFree(ArrayPointer, TAG_FAT_CHAIN);
return NULL;
return FALSE;
}
}
return ArrayPointer;
if (!FatReadVolumeSectors(Volume, ClusterStartSector, ClustersToRead * Volume->SectorsPerCluster, Buffer))
{
return FALSE;
}
*ClustersRead = ClustersToRead;
*LastClusterNumber = NextClusterNumber;
return !FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters;
}
/*
* FatReadClusterChain()
* Reads the specified clusters into memory
*/
BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer)
static
BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber)
{
ULONG ClusterStartSector;
UINT32 ClustersRead, NextClusterNumber, ClustersLeft = NumberOfClusters;
TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
while (NumberOfClusters > 0)
ASSERT(NumberOfClusters > 0);
while (FatReadAdjacentClusters(Volume, StartClusterNumber, ClustersLeft, Buffer, &ClustersRead, &NextClusterNumber))
{
//TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
//
// Calculate starting sector for cluster
//
ClusterStartSector = ((StartClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
//
// Read cluster into memory
//
if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, Buffer))
{
return FALSE;
}
//
// Decrement count of clusters left to read
//
NumberOfClusters--;
//
// Increment buffer address by cluster size
//
Buffer = (PVOID)((ULONG_PTR)Buffer + (Volume->SectorsPerCluster * Volume->BytesPerSector));
//
// Get next cluster
//
if (!FatGetFatEntry(Volume, StartClusterNumber, &StartClusterNumber))
{
return FALSE;
}
//
// If end of chain then break out of our cluster reading loop
//
if (((Volume->FatType == FAT12) && (StartClusterNumber >= 0xff8)) ||
((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartClusterNumber >= 0xfff8)) ||
((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartClusterNumber >= 0x0ffffff8)))
{
break;
}
ClustersLeft -= ClustersRead;
Buffer = (PVOID)((ULONG_PTR)Buffer + (ClustersRead * Volume->SectorsPerCluster * Volume->BytesPerSector));
StartClusterNumber = NextClusterNumber;
}
return TRUE;
if (LastClusterNumber)
{
*LastClusterNumber = NextClusterNumber;
}
return (ClustersRead > 0);
}
/*
@ -1268,14 +1192,11 @@ BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULON
* Reads BytesToRead from open file and
* returns the number of bytes read in BytesRead
*/
static
BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
{
PFAT_VOLUME_INFO Volume = FatFileInfo->Volume;
ULONG ClusterNumber;
ULONG OffsetInCluster;
ULONG LengthInCluster;
ULONG NumberOfClusters;
ULONG BytesPerCluster;
UINT32 NextClusterNumber, BytesPerCluster;
TRACE("FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer);
@ -1342,15 +1263,15 @@ BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesR
//
// Do the math for our first read
//
ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
OffsetInCluster = (FatFileInfo->FilePointer % BytesPerCluster);
LengthInCluster = (BytesToRead > (BytesPerCluster - OffsetInCluster)) ? (BytesPerCluster - OffsetInCluster) : BytesToRead;
UINT32 OffsetInCluster = FatFileInfo->FilePointer % BytesPerCluster;
UINT32 LengthInCluster = min(BytesToRead, BytesPerCluster - OffsetInCluster);
ASSERT(LengthInCluster <= BytesPerCluster && LengthInCluster > 0);
//
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
//
if (!FatReadPartialCluster(Volume, ClusterNumber, OffsetInCluster, LengthInCluster, Buffer))
if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, OffsetInCluster, LengthInCluster, Buffer))
{
return FALSE;
}
@ -1361,6 +1282,18 @@ BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesR
BytesToRead -= LengthInCluster;
FatFileInfo->FilePointer += LengthInCluster;
Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster);
// get the next cluster if needed
if ((LengthInCluster + OffsetInCluster) == BytesPerCluster)
{
if (!FatGetFatEntry(Volume, FatFileInfo->CurrentCluster, &NextClusterNumber))
{
return FALSE;
}
FatFileInfo->CurrentCluster = NextClusterNumber;
TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
}
}
//
@ -1371,27 +1304,33 @@ BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesR
//
// Determine how many full clusters we need to read
//
NumberOfClusters = (BytesToRead / BytesPerCluster);
UINT32 NumberOfClusters = BytesToRead / BytesPerCluster;
TRACE("Going to read: %u clusters\n", NumberOfClusters);
if (NumberOfClusters > 0)
{
ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
UINT32 BytesReadHere = NumberOfClusters * BytesPerCluster;
//
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
//
if (!FatReadClusterChain(Volume, ClusterNumber, NumberOfClusters, Buffer))
ASSERT(!FAT_IS_END_CLUSTER(FatFileInfo->CurrentCluster));
if (!FatReadClusterChain(Volume, FatFileInfo->CurrentCluster, NumberOfClusters, Buffer, &NextClusterNumber))
{
return FALSE;
}
if (BytesRead != NULL)
{
*BytesRead += (NumberOfClusters * BytesPerCluster);
*BytesRead += BytesReadHere;
}
BytesToRead -= (NumberOfClusters * BytesPerCluster);
FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster);
Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfClusters * BytesPerCluster));
BytesToRead -= BytesReadHere;
Buffer = (PVOID)((ULONG_PTR)Buffer + BytesReadHere);
ASSERT(!FAT_IS_END_CLUSTER(NextClusterNumber) || BytesToRead == 0);
FatFileInfo->FilePointer += BytesReadHere;
FatFileInfo->CurrentCluster = NextClusterNumber;
TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
}
}
@ -1400,13 +1339,12 @@ BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesR
//
if (BytesToRead > 0)
{
ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
ASSERT(!FAT_IS_END_CLUSTER(FatFileInfo->CurrentCluster));
//
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
//
if (!FatReadPartialCluster(Volume, ClusterNumber, 0, BytesToRead, Buffer))
if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, 0, BytesToRead, Buffer))
{
return FALSE;
}
@ -1460,7 +1398,6 @@ ARC_STATUS FatClose(ULONG FileId)
{
PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
if (FileHandle->FileFatChain) FrLdrTempFree(FileHandle->FileFatChain, TAG_FAT_CHAIN);
FrLdrTempFree(FileHandle, TAG_FAT_FILE);
return ESUCCESS;
@ -1544,6 +1481,7 @@ ARC_STATUS FatRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
ARC_STATUS FatSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
{
PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
PFAT_VOLUME_INFO Volume = FileHandle->Volume;
LARGE_INTEGER NewPosition = *Position;
switch (SeekMode)
@ -1551,7 +1489,7 @@ ARC_STATUS FatSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
case SeekAbsolute:
break;
case SeekRelative:
NewPosition.QuadPart += (ULONGLONG)FileHandle->FilePointer;
NewPosition.QuadPart += (UINT64)FileHandle->FilePointer;
break;
default:
ASSERT(FALSE);
@ -1563,7 +1501,42 @@ ARC_STATUS FatSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
if (NewPosition.LowPart >= FileHandle->FileSize)
return EINVAL;
TRACE("FatSeek() NewPosition = %u, OldPointer = %u, SeekMode = %d\n", NewPosition.LowPart, FileHandle->FilePointer, SeekMode);
{
UINT32 OldClusterIdx = FileHandle->FilePointer / (Volume->SectorsPerCluster * Volume->BytesPerSector);
UINT32 NewClusterIdx = NewPosition.LowPart / (Volume->SectorsPerCluster * Volume->BytesPerSector);
TRACE("FatSeek() OldClusterIdx: %u, NewClusterIdx: %u\n", OldClusterIdx, NewClusterIdx);
if (NewClusterIdx != OldClusterIdx)
{
UINT32 CurrentClusterIdx, ClusterNumber;
if (NewClusterIdx > OldClusterIdx)
{
CurrentClusterIdx = OldClusterIdx;
ClusterNumber = FileHandle->CurrentCluster;
}
else
{
CurrentClusterIdx = 0;
ClusterNumber = FileHandle->StartCluster;
}
for (; CurrentClusterIdx < NewClusterIdx; CurrentClusterIdx++)
{
if (!FatGetFatEntry(Volume, ClusterNumber, &ClusterNumber))
{
return EIO;
}
}
FileHandle->CurrentCluster = ClusterNumber;
}
}
FileHandle->FilePointer = NewPosition.LowPart;
return ESUCCESS;
}