https://git.reactos.org/?p=reactos.git;a=commitdiff;h=220bc820eb888455c8d8d5...
commit 220bc820eb888455c8d8d554962c273f5f602188 Author: Victor Perevertkin victor@perevertkin.ru AuthorDate: Fri Jul 19 02:57:11 2019 +0300 Commit: Victor Perevertkin victor@perevertkin.ru CommitDate: Sun Sep 29 13:24:31 2019 +0300
[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. --- boot/freeldr/freeldr/include/fs/fat.h | 7 +- boot/freeldr/freeldr/lib/fs/fat.c | 319 ++++++++++++++++------------------ 2 files changed, 150 insertions(+), 176 deletions(-)
diff --git a/boot/freeldr/freeldr/include/fs/fat.h b/boot/freeldr/freeldr/include/fs/fat.h index 7117cb2bad8..85e2998ecb8 100644 --- a/boot/freeldr/freeldr/include/fs/fat.h +++ b/boot/freeldr/freeldr/include/fs/fat.h @@ -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 diff --git a/boot/freeldr/freeldr/lib/fs/fat.c b/boot/freeldr/freeldr/lib/fs/fat.c index b973a64dd70..35233c414b5 100644 --- a/boot/freeldr/freeldr/lib/fs/fat.c +++ b/boot/freeldr/freeldr/lib/fs/fat.c @@ -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); - - 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); + *ClustersRead = 0; + *LastClusterNumber = 0;
- 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; + return FALSE; } + }
- // - // Get next cluster - // - if (!FatGetFatEntry(Volume, StartCluster, &StartCluster)) - { - FrLdrTempFree(ArrayPointer, TAG_FAT_CHAIN); - return NULL; - } + if (!FatReadVolumeSectors(Volume, ClusterStartSector, ClustersToRead * Volume->SectorsPerCluster, Buffer)) + { + return FALSE; }
- return ArrayPointer; + *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);
- //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; - } + while (FatReadAdjacentClusters(Volume, StartClusterNumber, ClustersLeft, Buffer, &ClustersRead, &NextClusterNumber)) + { + ClustersLeft -= ClustersRead; + Buffer = (PVOID)((ULONG_PTR)Buffer + (ClustersRead * Volume->SectorsPerCluster * Volume->BytesPerSector)); + StartClusterNumber = NextClusterNumber; + }
- // - // 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; - } + if (LastClusterNumber) + { + *LastClusterNumber = NextClusterNumber; }
- return TRUE; + 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; }