[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / fs / fat.c
index c4f5aba..79c3dd3 100644 (file)
@@ -370,9 +370,21 @@ ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSect
        }
 }
 
+typedef struct _DIRECTORY_BUFFER
+{
+       LIST_ENTRY Link;
+       PVOID Volume;
+       ULONG DirectoryStartCluster;
+       ULONG DirectorySize;
+       UCHAR Data[];
+} DIRECTORY_BUFFER, *PDIRECTORY_BUFFER;
+
+LIST_ENTRY DirectoryBufferListHead = {&DirectoryBufferListHead, &DirectoryBufferListHead};
+
 PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOLEAN RootDirectory)
 {
-       PVOID   DirectoryBuffer;
+       PDIRECTORY_BUFFER DirectoryBuffer;
+       PLIST_ENTRY Entry;
 
        TRACE("FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE"));
 
@@ -386,6 +398,23 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, U
                RootDirectory = FALSE;
        }
 
+       /* Search the list for a match */
+       for (Entry = DirectoryBufferListHead.Flink;
+            Entry != &DirectoryBufferListHead;
+            Entry = Entry->Flink)
+       {
+               DirectoryBuffer = CONTAINING_RECORD(Entry, DIRECTORY_BUFFER, Link);
+
+               /* Check if it matches */
+               if ((DirectoryBuffer->Volume == Volume) &&
+                   (DirectoryBuffer->DirectoryStartCluster == DirectoryStartCluster))
+               {
+                       TRACE("Found cached buffer\n");
+                       *DirectorySize = DirectoryBuffer->DirectorySize;
+                       return DirectoryBuffer->Data;
+               }
+       }
+
        //
        // Calculate the size of the directory
        //
@@ -402,7 +431,7 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, U
        // Attempt to allocate memory for directory buffer
        //
        TRACE("Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize);
-       DirectoryBuffer = MmAllocateMemory(*DirectorySize);
+       DirectoryBuffer = MmHeapAlloc(*DirectorySize + sizeof(DIRECTORY_BUFFER));
 
        if (DirectoryBuffer == NULL)
        {
@@ -414,22 +443,28 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, U
        //
        if (RootDirectory)
        {
-               if (!FatReadVolumeSectors(Volume, Volume->RootDirSectorStart, Volume->RootDirSectors, DirectoryBuffer))
+               if (!FatReadVolumeSectors(Volume, Volume->RootDirSectorStart, Volume->RootDirSectors, DirectoryBuffer->Data))
                {
-                       MmFreeMemory(DirectoryBuffer);
+                       MmHeapFree(DirectoryBuffer);
                        return NULL;
                }
        }
        else
        {
-               if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer))
+               if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer->Data))
                {
-                       MmFreeMemory(DirectoryBuffer);
+                       MmHeapFree(DirectoryBuffer);
                        return NULL;
                }
        }
 
-       return DirectoryBuffer;
+       /* Enqueue it in the list */
+       DirectoryBuffer->Volume = Volume;
+       DirectoryBuffer->DirectoryStartCluster = DirectoryStartCluster;
+       DirectoryBuffer->DirectorySize = *DirectorySize;
+       InsertTailList(&DirectoryBufferListHead, &DirectoryBuffer->Link);
+
+       return DirectoryBuffer->Data;
 }
 
 BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
@@ -774,7 +809,6 @@ LONG FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, ULONG DeviceId, PFAT
                {
                        if (!FatXSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
                        {
-                               MmFreeMemory(DirectoryBuffer);
                                return ENOENT;
                        }
                }
@@ -782,13 +816,10 @@ LONG FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, ULONG DeviceId, PFAT
                {
                        if (!FatSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
                        {
-                               MmFreeMemory(DirectoryBuffer);
                                return ENOENT;
                        }
                }
 
-               MmFreeMemory(DirectoryBuffer);
-
                //
                // If we have another sub-directory to go then
                // grab the start cluster and free the fat chain array
@@ -800,12 +831,13 @@ LONG FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, ULONG DeviceId, PFAT
                        //
                        if (!(FatFileInfo.Attributes & ATTR_DIRECTORY))
                        {
-                               MmFreeMemory(FatFileInfo.FileFatChain);
+                               MmHeapFree(FatFileInfo.FileFatChain);
                                return ENOTDIR;
                        }
                        DirectoryStartCluster = FatFileInfo.FileFatChain[0];
+                       MmHeapFree(FatFileInfo.FileFatChain);
+                       FatFileInfo.FileFatChain = NULL;
                }
-               MmFreeMemory(FatFileInfo.FileFatChain);
        }
 
        memcpy(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
@@ -872,9 +904,19 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
        UINT32          FatOffset;
        UINT32          ThisFatSecNum;
        UINT32          ThisFatEntOffset;
+       ULONG SectorCount;
+       PUCHAR ReadBuffer;
+       BOOLEAN status = TRUE;
 
        //TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
 
+       // We need a buffer for 2 secors
+       ReadBuffer = HeapAllocate(FrLdrTempHeap, 2 * Volume->BytesPerSector, 'xTAF');
+       if (!ReadBuffer)
+       {
+               return FALSE;
+       }
+
        switch(Volume->FatType)
        {
        case FAT12:
@@ -889,20 +931,20 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
 
                if (ThisFatEntOffset == (Volume->BytesPerSector - 1))
                {
-                       if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 2, (PVOID)FILESYSBUFFER))
-                       {
-                               return FALSE;
-                       }
+                   SectorCount = 2;
                }
                else
                {
-                       if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
-                       {
-                               return FALSE;
-                       }
+                   SectorCount = 1;
+               }
+
+               if (!FatReadVolumeSectors(Volume, ThisFatSecNum, SectorCount, ReadBuffer))
+               {
+                       status = FALSE;
+                       break;
                }
 
-               fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
+               fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
                fat = SWAPW(fat);
                if (Cluster & 0x0001)
                        fat = fat >> 4; /* Cluster number is ODD */
@@ -918,12 +960,13 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
                ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector);
                ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
 
-               if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
+               if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
                {
-                       return FALSE;
+                       status = FALSE;
+                       break;
                }
 
-               fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
+               fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
                fat = SWAPW(fat);
 
                break;
@@ -935,28 +978,30 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
                ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector);
                ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
 
-               if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
+               if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
                {
                        return FALSE;
                }
 
                // Get the fat entry
-               fat = (*((ULONG *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF;
+               fat = (*((ULONG *) (ReadBuffer + ThisFatEntOffset))) & 0x0FFFFFFF;
                fat = SWAPD(fat);
 
                break;
 
        default:
-               TRACE("Unknown FAT type %d\n", Volume->FatType);
-               return FALSE;
-
+               ERR("Unknown FAT type %d\n", Volume->FatType);
+               status = FALSE;
+               break;
        }
 
        //TRACE("FAT entry is 0x%x.\n", fat);
 
+       HeapFree(FrLdrTempHeap, ReadBuffer, 'xTAF');
+
        *ClusterPointer = fat;
 
-       return TRUE;
+       return status;
 }
 
 ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
@@ -1011,7 +1056,7 @@ ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
        //
        // Allocate array memory
        //
-       ArrayPointer = MmAllocateMemory(ArraySize);
+       ArrayPointer = MmHeapAlloc(ArraySize);
 
        if (ArrayPointer == NULL)
        {
@@ -1044,7 +1089,7 @@ ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
                //
                if (!FatGetFatEntry(Volume, StartCluster, &StartCluster))
                {
-                       MmFreeMemory(ArrayPointer);
+                       MmHeapFree(ArrayPointer);
                        return NULL;
                }
        }
@@ -1074,13 +1119,11 @@ BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, U
                //
                // Read cluster into memory
                //
-               if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, (PVOID)FILESYSBUFFER))
+               if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, Buffer))
                {
                        return FALSE;
                }
 
-               memcpy(Buffer, (PVOID)FILESYSBUFFER, Volume->SectorsPerCluster * Volume->BytesPerSector);
-
                //
                // Decrement count of clusters left to read
                //
@@ -1120,19 +1163,39 @@ BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, U
 BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
 {
        ULONG           ClusterStartSector;
+       ULONG SectorOffset, ReadSize, SectorCount;
+       PUCHAR ReadBuffer;
+       BOOLEAN status = FALSE;
 
        //TRACE("FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer);
 
        ClusterStartSector = ((ClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
 
-       if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, (PVOID)FILESYSBUFFER))
+    // This is the offset of the data in sectors
+    SectorOffset = (StartingOffset / Volume->BytesPerSector);
+    StartingOffset %= Volume->BytesPerSector;
+
+    // Calculate how many sectors we need to read
+    SectorCount = (StartingOffset + Length + Volume->BytesPerSector - 1) / Volume->BytesPerSector;
+
+    // Calculate rounded up read size
+    ReadSize = SectorCount * Volume->BytesPerSector;
+
+    ReadBuffer = HeapAllocate(FrLdrTempHeap, ReadSize, 'xTAF');
+    if (!ReadBuffer)
+    {
+        return FALSE;
+    }
+
+       if (FatReadVolumeSectors(Volume, ClusterStartSector + SectorOffset, SectorCount, ReadBuffer))
        {
-               return FALSE;
+               memcpy(Buffer, ReadBuffer + StartingOffset, Length);
+               status = TRUE;
        }
 
-       memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
+       HeapFree(FrLdrTempHeap, ReadBuffer, 'xTAF');
 
-       return TRUE;
+       return status;
 }
 
 /*
@@ -1306,7 +1369,7 @@ BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG
        //
        // Seek to right position
        //
-       Position.QuadPart = SectorNumber * 512;
+       Position.QuadPart = (ULONGLONG)SectorNumber * 512;
        ret = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
        if (ret != ESUCCESS)
        {
@@ -1332,6 +1395,7 @@ LONG FatClose(ULONG FileId)
 {
        PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
 
+       if (FileHandle->FileFatChain) MmHeapFree(FileHandle->FileFatChain);
        MmHeapFree(FileHandle);
 
        return ESUCCESS;