mirror of
https://github.com/reactos/reactos.git
synced 2025-01-02 12:32:47 +00:00
59f1842f56
- Added F8 options menu - Added custom Boot functionality - Moved all OS= settings from [FreeLoader] section to [Operating Systems] section. - Removed MessageLine= setting. MessageBox= now accepts "\n" as an escape character for newlines. - Added descriptions for disk error codes returned by the BIOS. - Device names like "fd0" and "hd0" and "hd1" as well as BIOS drive numbers can now be used as BootDrive= settings. svn path=/trunk/; revision=4038
1214 lines
38 KiB
C
1214 lines
38 KiB
C
/*
|
|
* FreeLoader
|
|
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
|
|
*
|
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include <freeldr.h>
|
|
#include <fs.h>
|
|
#include "fat.h"
|
|
#include <disk.h>
|
|
#include <rtl.h>
|
|
#include <ui.h>
|
|
#include <arch.h>
|
|
#include <mm.h>
|
|
#include <debug.h>
|
|
#include <cache.h>
|
|
|
|
|
|
PFAT_BOOTSECTOR FatVolumeBootSector = NULL;
|
|
PFAT32_BOOTSECTOR Fat32VolumeBootSector = NULL;
|
|
|
|
U32 RootDirSectorStart; // Starting sector of the root directory (fat12/16)
|
|
U32 DataSectorStart; // Starting sector of the data area
|
|
U32 SectorsPerFat; // Sectors per FAT table
|
|
U32 RootDirSectors; // Number of sectors of the root directory (fat32)
|
|
|
|
U32 FatType = 0; // FAT12, FAT16, or FAT32
|
|
U32 FatDriveNumber = 0;
|
|
|
|
BOOL FatOpenVolume(U32 DriveNumber, U32 VolumeStartSector)
|
|
{
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
|
|
|
|
// Store the drive number
|
|
FatDriveNumber = DriveNumber;
|
|
|
|
//
|
|
// Free any memory previously allocated
|
|
//
|
|
if (FatVolumeBootSector != NULL)
|
|
{
|
|
MmFreeMemory(FatVolumeBootSector);
|
|
|
|
FatVolumeBootSector = NULL;
|
|
Fat32VolumeBootSector = NULL;
|
|
}
|
|
|
|
//
|
|
// Now allocate the memory to hold the boot sector
|
|
//
|
|
FatVolumeBootSector = (PFAT_BOOTSECTOR) MmAllocateMemory(512);
|
|
Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector;
|
|
|
|
//
|
|
// Make sure we got the memory
|
|
//
|
|
if (FatVolumeBootSector == NULL)
|
|
{
|
|
FileSystemError("Out of memory.");
|
|
return FALSE;
|
|
}
|
|
|
|
// Now try to read the boot sector
|
|
// If this fails then abort
|
|
if (!DiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PVOID)DISKREADBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
RtlCopyMemory(FatVolumeBootSector, (PVOID)DISKREADBUFFER, 512);
|
|
|
|
// Get the FAT type
|
|
FatType = FatDetermineFatType(FatVolumeBootSector);
|
|
|
|
#ifdef DEBUG
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "Dumping boot sector:\n"));
|
|
|
|
if (FatType == FAT32)
|
|
{
|
|
DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR)));
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->OemName[0], Fat32VolumeBootSector->OemName[1], Fat32VolumeBootSector->OemName[2], Fat32VolumeBootSector->OemName[3], Fat32VolumeBootSector->OemName[4], Fat32VolumeBootSector->OemName[5], Fat32VolumeBootSector->OemName[6], Fat32VolumeBootSector->OemName[7]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats));
|
|
DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries));
|
|
DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack));
|
|
DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads));
|
|
DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags));
|
|
DbgPrint((DPRINT_FILESYSTEM, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion));
|
|
DbgPrint((DPRINT_FILESYSTEM, "RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster));
|
|
DbgPrint((DPRINT_FILESYSTEM, "FsInfo: %d\n", Fat32VolumeBootSector->FsInfo));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved));
|
|
DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature));
|
|
DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber));
|
|
DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->VolumeLabel[0], Fat32VolumeBootSector->VolumeLabel[1], Fat32VolumeBootSector->VolumeLabel[2], Fat32VolumeBootSector->VolumeLabel[3], Fat32VolumeBootSector->VolumeLabel[4], Fat32VolumeBootSector->VolumeLabel[5], Fat32VolumeBootSector->VolumeLabel[6], Fat32VolumeBootSector->VolumeLabel[7], Fat32VolumeBootSector->VolumeLabel[8], Fat32VolumeBootSector->VolumeLabel[9], Fat32VolumeBootSector->VolumeLabel[10]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->FileSystemType[0], Fat32VolumeBootSector->FileSystemType[1], Fat32VolumeBootSector->FileSystemType[2], Fat32VolumeBootSector->FileSystemType[3], Fat32VolumeBootSector->FileSystemType[4], Fat32VolumeBootSector->FileSystemType[5], Fat32VolumeBootSector->FileSystemType[6], Fat32VolumeBootSector->FileSystemType[7]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic));
|
|
}
|
|
else
|
|
{
|
|
DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR)));
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->OemName[0], FatVolumeBootSector->OemName[1], FatVolumeBootSector->OemName[2], FatVolumeBootSector->OemName[3], FatVolumeBootSector->OemName[4], FatVolumeBootSector->OemName[5], FatVolumeBootSector->OemName[6], FatVolumeBootSector->OemName[7]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats));
|
|
DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries));
|
|
DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", FatVolumeBootSector->TotalSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat));
|
|
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack));
|
|
DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads));
|
|
DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors));
|
|
DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig));
|
|
DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature));
|
|
DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber));
|
|
DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector->VolumeLabel[0], FatVolumeBootSector->VolumeLabel[1], FatVolumeBootSector->VolumeLabel[2], FatVolumeBootSector->VolumeLabel[3], FatVolumeBootSector->VolumeLabel[4], FatVolumeBootSector->VolumeLabel[5], FatVolumeBootSector->VolumeLabel[6], FatVolumeBootSector->VolumeLabel[7], FatVolumeBootSector->VolumeLabel[8], FatVolumeBootSector->VolumeLabel[9], FatVolumeBootSector->VolumeLabel[10]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->FileSystemType[0], FatVolumeBootSector->FileSystemType[1], FatVolumeBootSector->FileSystemType[2], FatVolumeBootSector->FileSystemType[3], FatVolumeBootSector->FileSystemType[4], FatVolumeBootSector->FileSystemType[5], FatVolumeBootSector->FileSystemType[6], FatVolumeBootSector->FileSystemType[7]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic));
|
|
}
|
|
|
|
#endif // defined DEBUG
|
|
|
|
//
|
|
// Set the correct partition offset
|
|
//
|
|
FatVolumeBootSector->HiddenSectors = VolumeStartSector;
|
|
|
|
//
|
|
// Check the boot sector magic
|
|
//
|
|
if (FatVolumeBootSector->BootSectorMagic != 0xaa55)
|
|
{
|
|
FileSystemError("Invalid boot sector magic (0xaa55)");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check the FAT cluster size
|
|
// We do not support clusters bigger than 64k
|
|
//
|
|
if ((FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector) > (64 * 1024))
|
|
{
|
|
FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Clear our variables
|
|
//
|
|
RootDirSectorStart = 0;
|
|
DataSectorStart = 0;
|
|
SectorsPerFat = 0;
|
|
RootDirSectors = 0;
|
|
|
|
//
|
|
// Get the sectors per FAT,
|
|
// root directory starting sector,
|
|
// and data sector start
|
|
//
|
|
if (FatType != FAT32)
|
|
{
|
|
SectorsPerFat = FatVolumeBootSector->SectorsPerFat;
|
|
|
|
RootDirSectorStart = (FatVolumeBootSector->NumberOfFats * SectorsPerFat) + FatVolumeBootSector->ReservedSectors;
|
|
RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (FatVolumeBootSector->BytesPerSector - 1)) / FatVolumeBootSector->BytesPerSector;
|
|
|
|
DataSectorStart = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * FatVolumeBootSector->SectorsPerFat) + RootDirSectors;
|
|
}
|
|
else
|
|
{
|
|
SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig;
|
|
|
|
DataSectorStart = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * Fat32VolumeBootSector->SectorsPerFatBig) + RootDirSectors;
|
|
|
|
|
|
//
|
|
// Check version
|
|
// we only work with version 0
|
|
//
|
|
if (Fat32VolumeBootSector->FileSystemVersion != 0)
|
|
{
|
|
FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the disk cache for this drive
|
|
//
|
|
if (!CacheInitializeDrive(DriveNumber))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Force the FAT sectors into the cache
|
|
// as long as it is FAT12 or FAT16. FAT32 can
|
|
// have a multi-megabyte FAT so we don't want that.
|
|
//
|
|
if (FatType != FAT32)
|
|
{
|
|
if (!CacheForceDiskSectorsIntoCache(DriveNumber, FatVolumeBootSector->HiddenSectors + FatVolumeBootSector->ReservedSectors, FatVolumeBootSector->SectorsPerFat))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
U32 FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector)
|
|
{
|
|
U32 RootDirSectors;
|
|
U32 DataSectorCount;
|
|
U32 SectorsPerFat;
|
|
U32 TotalSectors;
|
|
U32 CountOfClusters;
|
|
PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector;
|
|
|
|
RootDirSectors = ((FatBootSector->RootDirEntries * 32) + (FatBootSector->BytesPerSector - 1)) / FatBootSector->BytesPerSector;
|
|
SectorsPerFat = FatBootSector->SectorsPerFat ? FatBootSector->SectorsPerFat : Fat32BootSector->SectorsPerFatBig;
|
|
TotalSectors = FatBootSector->TotalSectors ? FatBootSector->TotalSectors : FatBootSector->TotalSectorsBig;
|
|
DataSectorCount = TotalSectors - (FatBootSector->ReservedSectors + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors);
|
|
|
|
//mjl
|
|
if (FatBootSector->SectorsPerCluster == 0)
|
|
CountOfClusters = 0;
|
|
else
|
|
CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster;
|
|
|
|
if (CountOfClusters < 4085)
|
|
{
|
|
/* Volume is FAT12 */
|
|
return FAT12;
|
|
}
|
|
else if (CountOfClusters < 65525)
|
|
{
|
|
/* Volume is FAT16 */
|
|
return FAT16;
|
|
}
|
|
else
|
|
{
|
|
/* Volume is FAT32 */
|
|
return FAT32;
|
|
}
|
|
}
|
|
|
|
PVOID FatBufferDirectory(U32 DirectoryStartCluster, U32* EntryCountPointer, BOOL RootDirectory)
|
|
{
|
|
U32 RootDirectoryStartSector;
|
|
U32 RootDirectorySectorCount;
|
|
PVOID DirectoryBuffer;
|
|
U32 DirectorySize;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE")));
|
|
|
|
//
|
|
// Calculate the size of the directory
|
|
//
|
|
if ((RootDirectory) && (FatType != FAT32))
|
|
{
|
|
DirectorySize = ROUND_UP((FatVolumeBootSector->RootDirEntries * 32), FatVolumeBootSector->BytesPerSector);
|
|
}
|
|
else
|
|
{
|
|
if (RootDirectory)
|
|
{
|
|
DirectorySize = (FatCountClustersInChain(Fat32VolumeBootSector->RootDirStartCluster) * Fat32VolumeBootSector->SectorsPerCluster) * Fat32VolumeBootSector->BytesPerSector;
|
|
}
|
|
else
|
|
{
|
|
DirectorySize = (FatCountClustersInChain(DirectoryStartCluster) * FatVolumeBootSector->SectorsPerCluster) * FatVolumeBootSector->BytesPerSector;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attempt to allocate memory for directory buffer
|
|
//
|
|
DbgPrint((DPRINT_FILESYSTEM, "Trying to allocate (DirectorySize) %d bytes.\n", DirectorySize));
|
|
DirectoryBuffer = MmAllocateMemory(DirectorySize);
|
|
|
|
if (DirectoryBuffer == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Now read directory contents into DirectoryBuffer
|
|
//
|
|
if (RootDirectory)
|
|
{
|
|
if (FatType == FAT32)
|
|
{
|
|
if (!FatReadClusterChain(Fat32VolumeBootSector->RootDirStartCluster, 0xFFFFFFFF, DirectoryBuffer))
|
|
{
|
|
MmFreeMemory(DirectoryBuffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// FAT type is not FAT32 so the root directory comes right after the fat table
|
|
//
|
|
RootDirectoryStartSector = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * FatVolumeBootSector->SectorsPerFat);
|
|
RootDirectorySectorCount = (DirectorySize / FatVolumeBootSector->BytesPerSector);
|
|
|
|
if (!FatReadVolumeSectors(FatDriveNumber, RootDirectoryStartSector, RootDirectorySectorCount, DirectoryBuffer))
|
|
{
|
|
MmFreeMemory(DirectoryBuffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer))
|
|
{
|
|
MmFreeMemory(DirectoryBuffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
*EntryCountPointer = (DirectorySize / 32);
|
|
|
|
return DirectoryBuffer;
|
|
}
|
|
|
|
BOOL FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, U32 EntryCount, PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
|
|
{
|
|
U32 CurrentEntry;
|
|
PDIRENTRY DirEntry;
|
|
PLFN_DIRENTRY LfnDirEntry;
|
|
UCHAR LfnNameBuffer[265];
|
|
UCHAR ShortNameBuffer[20];
|
|
U32 StartCluster;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName));
|
|
|
|
memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
|
|
memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
|
|
|
|
for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++)
|
|
{
|
|
DirEntry = (PDIRENTRY)(DirectoryBuffer + (CurrentEntry * 32) );
|
|
LfnDirEntry = (PLFN_DIRENTRY)DirEntry;
|
|
|
|
//DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry));
|
|
//DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
|
|
|
|
//
|
|
// Check if this is the last file in the directory
|
|
// If DirEntry[0] == 0x00 then that means all the
|
|
// entries after this one are unused. If this is the
|
|
// last entry then we didn't find the file in this directory.
|
|
//
|
|
if (DirEntry->FileName[0] == 0x00)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check if this is a deleted entry or not
|
|
//
|
|
if (DirEntry->FileName[0] == 0xE5)
|
|
{
|
|
memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
|
|
memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check if this is a LFN entry
|
|
// If so it needs special handling
|
|
//
|
|
if (DirEntry->Attr == ATTR_LONG_NAME)
|
|
{
|
|
//
|
|
// Check to see if this is a deleted LFN entry, if so continue
|
|
//
|
|
if (LfnDirEntry->SequenceNumber & 0x80)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Mask off high two bits of sequence number
|
|
// and make the sequence number zero-based
|
|
//
|
|
LfnDirEntry->SequenceNumber &= 0x3F;
|
|
LfnDirEntry->SequenceNumber--;
|
|
|
|
//
|
|
// Get all 13 LFN entry characters
|
|
//
|
|
if (LfnDirEntry->Name0_4[0] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0];
|
|
}
|
|
if (LfnDirEntry->Name0_4[1] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1];
|
|
}
|
|
if (LfnDirEntry->Name0_4[2] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2];
|
|
}
|
|
if (LfnDirEntry->Name0_4[3] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3];
|
|
}
|
|
if (LfnDirEntry->Name0_4[4] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4];
|
|
}
|
|
if (LfnDirEntry->Name5_10[0] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0];
|
|
}
|
|
if (LfnDirEntry->Name5_10[1] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1];
|
|
}
|
|
if (LfnDirEntry->Name5_10[2] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2];
|
|
}
|
|
if (LfnDirEntry->Name5_10[3] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3];
|
|
}
|
|
if (LfnDirEntry->Name5_10[4] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4];
|
|
}
|
|
if (LfnDirEntry->Name5_10[5] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5];
|
|
}
|
|
if (LfnDirEntry->Name11_12[0] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0];
|
|
}
|
|
if (LfnDirEntry->Name11_12[1] != 0xFFFF)
|
|
{
|
|
LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1];
|
|
}
|
|
|
|
//DbgPrint((DPRINT_FILESYSTEM, "Dumping long name buffer:\n"));
|
|
//DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check for the volume label attribute
|
|
// and skip over this entry if found
|
|
//
|
|
if (DirEntry->Attr & ATTR_VOLUMENAME)
|
|
{
|
|
memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
|
|
memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If we get here then we've found a short file name
|
|
// entry and LfnNameBuffer contains the long file
|
|
// name or zeroes. All we have to do now is see if the
|
|
// file name matches either the short or long file name
|
|
// and fill in the FAT_FILE_INFO structure if it does
|
|
// or zero our buffers and continue looking.
|
|
//
|
|
|
|
//
|
|
// Get short file name
|
|
//
|
|
FatParseShortFileName(ShortNameBuffer, DirEntry);
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer));
|
|
|
|
//
|
|
// See if the file name matches either the short or long name
|
|
//
|
|
if (((strlen(FileName) == strlen(LfnNameBuffer)) && (stricmp(FileName, LfnNameBuffer) == 0)) ||
|
|
((strlen(FileName) == strlen(ShortNameBuffer)) && (stricmp(FileName, ShortNameBuffer) == 0)))
|
|
{
|
|
//
|
|
// We found the entry, now fill in the FAT_FILE_INFO struct
|
|
//
|
|
FatFileInfoPointer->FileSize = DirEntry->Size;
|
|
FatFileInfoPointer->FilePointer = 0;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "MSDOS Directory Entry:\n"));
|
|
DbgPrint((DPRINT_FILESYSTEM, "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]));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Attr = 0x%x\n", DirEntry->Attr));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ReservedNT = 0x%x\n", DirEntry->ReservedNT));
|
|
DbgPrint((DPRINT_FILESYSTEM, "TimeInTenths = %d\n", DirEntry->TimeInTenths));
|
|
DbgPrint((DPRINT_FILESYSTEM, "CreateTime = %d\n", DirEntry->CreateTime));
|
|
DbgPrint((DPRINT_FILESYSTEM, "CreateDate = %d\n", DirEntry->CreateDate));
|
|
DbgPrint((DPRINT_FILESYSTEM, "LastAccessDate = %d\n", DirEntry->LastAccessDate));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ClusterHigh = 0x%x\n", DirEntry->ClusterHigh));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Time = %d\n", DirEntry->Time));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Date = %d\n", DirEntry->Date));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ClusterLow = 0x%x\n", DirEntry->ClusterLow));
|
|
DbgPrint((DPRINT_FILESYSTEM, "Size = %d\n", DirEntry->Size));
|
|
|
|
//
|
|
// Get the cluster chain
|
|
//
|
|
StartCluster = ((U32)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
|
|
DbgPrint((DPRINT_FILESYSTEM, "StartCluster = 0x%x\n", StartCluster));
|
|
FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(StartCluster);
|
|
|
|
//
|
|
// See if memory allocation failed
|
|
//
|
|
if (FatFileInfoPointer->FileFatChain == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Nope, no match - zero buffers and continue looking
|
|
//
|
|
memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
|
|
memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
|
|
continue;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* FatLookupFile()
|
|
* This function searches the file system for the
|
|
* specified filename and fills in a FAT_STRUCT structure
|
|
* with info describing the file, etc. returns true
|
|
* if the file exists or false otherwise
|
|
*/
|
|
BOOL FatLookupFile(PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
|
|
{
|
|
int i;
|
|
U32 NumberOfPathParts;
|
|
UCHAR PathPart[261];
|
|
PVOID DirectoryBuffer;
|
|
U32 DirectoryStartCluster = 0;
|
|
U32 DirectoryEntryCount;
|
|
FAT_FILE_INFO FatFileInfo;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatLookupFile() FileName = %s\n", FileName));
|
|
|
|
memset(FatFileInfoPointer, 0, sizeof(FAT_FILE_INFO));
|
|
|
|
//
|
|
// Figure out how many sub-directories we are nested in
|
|
//
|
|
NumberOfPathParts = FsGetNumPathParts(FileName);
|
|
|
|
//
|
|
// Loop once for each part
|
|
//
|
|
for (i=0; i<NumberOfPathParts; i++)
|
|
{
|
|
//
|
|
// Get first path part
|
|
//
|
|
FsGetFirstNameFromPath(PathPart, FileName);
|
|
|
|
//
|
|
// Advance to the next part of the path
|
|
//
|
|
for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
|
|
{
|
|
}
|
|
FileName++;
|
|
|
|
//
|
|
// Buffer the directory contents
|
|
//
|
|
DirectoryBuffer = FatBufferDirectory(DirectoryStartCluster, &DirectoryEntryCount, (i == 0) );
|
|
if (DirectoryBuffer == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Search for file name in directory
|
|
//
|
|
if (!FatSearchDirectoryBufferForFile(DirectoryBuffer, DirectoryEntryCount, PathPart, &FatFileInfo))
|
|
{
|
|
MmFreeMemory(DirectoryBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
MmFreeMemory(DirectoryBuffer);
|
|
|
|
//
|
|
// If we have another sub-directory to go then
|
|
// grab the start cluster and free the fat chain array
|
|
//
|
|
if ((i+1) < NumberOfPathParts)
|
|
{
|
|
DirectoryStartCluster = FatFileInfo.FileFatChain[0];
|
|
MmFreeMemory(FatFileInfo.FileFatChain);
|
|
}
|
|
}
|
|
|
|
memcpy(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FatParseFileName()
|
|
* This function parses a directory entry name which
|
|
* is in the form of "FILE EXT" and puts it in Buffer
|
|
* in the form of "file.ext"
|
|
*/
|
|
void FatParseShortFileName(PUCHAR Buffer, PDIRENTRY DirEntry)
|
|
{
|
|
U32 Idx;
|
|
|
|
Idx = 0;
|
|
RtlZeroMemory(Buffer, 13);
|
|
|
|
//
|
|
// Fixup first character
|
|
//
|
|
if (DirEntry->FileName[0] == 0x05)
|
|
{
|
|
DirEntry->FileName[0] = 0xE5;
|
|
}
|
|
|
|
//
|
|
// Get the file name
|
|
//
|
|
while (Idx < 8)
|
|
{
|
|
if (DirEntry->FileName[Idx] == ' ')
|
|
{
|
|
break;
|
|
}
|
|
|
|
Buffer[Idx] = DirEntry->FileName[Idx];
|
|
Idx++;
|
|
}
|
|
|
|
//
|
|
// Get extension
|
|
//
|
|
if ((DirEntry->FileName[8] != ' '))
|
|
{
|
|
Buffer[Idx++] = '.';
|
|
Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8];
|
|
Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9];
|
|
Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10];
|
|
}
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatParseShortFileName() ShortName = %s\n", Buffer));
|
|
}
|
|
|
|
/*
|
|
* FatGetFatEntry()
|
|
* returns the Fat entry for a given cluster number
|
|
*/
|
|
BOOL FatGetFatEntry(U32 Cluster, U32* ClusterPointer)
|
|
{
|
|
U32 fat = 0;
|
|
int FatOffset;
|
|
int ThisFatSecNum;
|
|
int ThisFatEntOffset;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster));
|
|
|
|
switch(FatType)
|
|
{
|
|
case FAT12:
|
|
|
|
FatOffset = Cluster + (Cluster / 2);
|
|
ThisFatSecNum = FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector);
|
|
ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector);
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatOffset: %d\n", FatOffset));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ThisFatSecNum: %d\n", ThisFatSecNum));
|
|
DbgPrint((DPRINT_FILESYSTEM, "ThisFatEntOffset: %d\n", ThisFatEntOffset));
|
|
|
|
if (ThisFatEntOffset == (FatVolumeBootSector->BytesPerSector - 1))
|
|
{
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 2, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
fat = *((U16 *) ((PVOID)FILESYSBUFFER + ThisFatEntOffset));
|
|
if (Cluster & 0x0001)
|
|
fat = fat >> 4; /* Cluster number is ODD */
|
|
else
|
|
fat = fat & 0x0FFF; /* Cluster number is EVEN */
|
|
|
|
break;
|
|
|
|
case FAT16:
|
|
|
|
FatOffset = (Cluster * 2);
|
|
ThisFatSecNum = FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector);
|
|
ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector);
|
|
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
fat = *((U16 *) ((PVOID)FILESYSBUFFER + ThisFatEntOffset));
|
|
|
|
break;
|
|
|
|
case FAT32:
|
|
|
|
FatOffset = (Cluster * 4);
|
|
ThisFatSecNum = (Fat32VolumeBootSector->ExtendedFlags & 0x80) ? ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0; // Get the active fat sector offset
|
|
ThisFatSecNum += FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector);
|
|
ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector);
|
|
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fat entry
|
|
fat = (*((U32 *) ((PVOID)FILESYSBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FAT entry is 0x%x.\n", fat));
|
|
|
|
*ClusterPointer = fat;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FatOpenFile()
|
|
* Tries to open the file 'name' and returns true or false
|
|
* for success and failure respectively
|
|
*/
|
|
FILE* FatOpenFile(PUCHAR FileName)
|
|
{
|
|
FAT_FILE_INFO TempFatFileInfo;
|
|
PFAT_FILE_INFO FileHandle;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatOpenFile() FileName = %s\n", FileName));
|
|
|
|
if (!FatLookupFile(FileName, &TempFatFileInfo))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
FileHandle = MmAllocateMemory(sizeof(FAT_FILE_INFO));
|
|
|
|
if (FileHandle == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(FileHandle, &TempFatFileInfo, sizeof(FAT_FILE_INFO));
|
|
|
|
return (FILE*)FileHandle;
|
|
}
|
|
|
|
U32 FatCountClustersInChain(U32 StartCluster)
|
|
{
|
|
U32 ClusterCount = 0;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() StartCluster = %d\n", StartCluster));
|
|
|
|
while (1)
|
|
{
|
|
//
|
|
// If end of chain then break out of our cluster counting loop
|
|
//
|
|
if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
|
|
((FatType == FAT16) && (StartCluster >= 0xfff8)) ||
|
|
((FatType == FAT32) && (StartCluster >= 0x0ffffff8)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Increment count
|
|
//
|
|
ClusterCount++;
|
|
|
|
//
|
|
// Get next cluster
|
|
//
|
|
if (!FatGetFatEntry(StartCluster, &StartCluster))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount));
|
|
|
|
return ClusterCount;
|
|
}
|
|
|
|
U32* FatGetClusterChainArray(U32 StartCluster)
|
|
{
|
|
U32 ClusterCount;
|
|
U32 ArraySize;
|
|
U32* ArrayPointer;
|
|
U32 Idx;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster));
|
|
|
|
ClusterCount = FatCountClustersInChain(StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array
|
|
ArraySize = ClusterCount * sizeof(U32);
|
|
|
|
//
|
|
// Allocate array memory
|
|
//
|
|
ArrayPointer = MmAllocateMemory(ArraySize);
|
|
|
|
if (ArrayPointer == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Loop through and set array values
|
|
//
|
|
for (Idx=0; Idx<ClusterCount; Idx++)
|
|
{
|
|
//
|
|
// Set current cluster
|
|
//
|
|
ArrayPointer[Idx] = StartCluster;
|
|
|
|
//
|
|
// Don't try to get next cluster for last cluster
|
|
//
|
|
if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
|
|
((FatType == FAT16) && (StartCluster >= 0xfff8)) ||
|
|
((FatType == FAT32) && (StartCluster >= 0x0ffffff8)))
|
|
{
|
|
Idx++;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get next cluster
|
|
//
|
|
if (!FatGetFatEntry(StartCluster, &StartCluster))
|
|
{
|
|
MmFreeMemory(ArrayPointer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return ArrayPointer;
|
|
}
|
|
|
|
/*
|
|
* FatReadCluster()
|
|
* Reads the specified cluster into memory
|
|
* and returns the number of bytes read
|
|
*/
|
|
BOOL FatReadCluster(U32 ClusterNumber, PVOID Buffer)
|
|
{
|
|
U32 ClusterStartSector;
|
|
|
|
ClusterStartSector = ((ClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber, Buffer, ClusterStartSector));
|
|
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(Buffer, (PVOID)FILESYSBUFFER, FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FatReadClusterChain()
|
|
* Reads the specified clusters into memory
|
|
*/
|
|
BOOL FatReadClusterChain(U32 StartClusterNumber, U32 NumberOfClusters, PVOID Buffer)
|
|
{
|
|
U32 ClusterStartSector;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer));
|
|
|
|
while (NumberOfClusters > 0)
|
|
{
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer));
|
|
//
|
|
// Calculate starting sector for cluster
|
|
//
|
|
ClusterStartSector = ((StartClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart;
|
|
|
|
//
|
|
// Read cluster into memory
|
|
//
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(Buffer, (PVOID)FILESYSBUFFER, FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector);
|
|
|
|
//
|
|
// Decrement count of clusters left to read
|
|
//
|
|
NumberOfClusters--;
|
|
|
|
//
|
|
// Increment buffer address by cluster size
|
|
//
|
|
Buffer += (FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector);
|
|
|
|
//
|
|
// Get next cluster
|
|
//
|
|
if (!FatGetFatEntry(StartClusterNumber, &StartClusterNumber))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If end of chain then break out of our cluster reading loop
|
|
//
|
|
if (((FatType == FAT12) && (StartClusterNumber >= 0xff8)) ||
|
|
((FatType == FAT16) && (StartClusterNumber >= 0xfff8)) ||
|
|
((FatType == FAT32) && (StartClusterNumber >= 0x0ffffff8)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FatReadPartialCluster()
|
|
* Reads part of a cluster into memory
|
|
*/
|
|
BOOL FatReadPartialCluster(U32 ClusterNumber, U32 StartingOffset, U32 Length, PVOID Buffer)
|
|
{
|
|
U32 ClusterStartSector;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer));
|
|
|
|
ClusterStartSector = ((ClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart;
|
|
|
|
if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, (PVOID)FILESYSBUFFER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(Buffer, ((PVOID)FILESYSBUFFER + StartingOffset), Length);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FatReadFile()
|
|
* Reads BytesToRead from open file and
|
|
* returns the number of bytes read in BytesRead
|
|
*/
|
|
BOOL FatReadFile(FILE *FileHandle, U32 BytesToRead, U32* BytesRead, PVOID Buffer)
|
|
{
|
|
PFAT_FILE_INFO FatFileInfo = (PFAT_FILE_INFO)FileHandle;
|
|
U32 ClusterNumber;
|
|
U32 OffsetInCluster;
|
|
U32 LengthInCluster;
|
|
U32 NumberOfClusters;
|
|
U32 BytesPerCluster;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer));
|
|
|
|
if (BytesRead != NULL)
|
|
{
|
|
*BytesRead = 0;
|
|
}
|
|
|
|
//
|
|
// If they are trying to read past the
|
|
// end of the file then return success
|
|
// with BytesRead == 0
|
|
//
|
|
if (FatFileInfo->FilePointer >= FatFileInfo->FileSize)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// If they are trying to read more than there is to read
|
|
// then adjust the amount to read
|
|
//
|
|
if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize)
|
|
{
|
|
BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer);
|
|
}
|
|
|
|
//
|
|
// Ok, now we have to perform at most 3 calculations
|
|
// I'll draw you a picture (using nifty ASCII art):
|
|
//
|
|
// CurrentFilePointer -+
|
|
// |
|
|
// +----------------+
|
|
// |
|
|
// +-----------+-----------+-----------+-----------+
|
|
// | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
|
|
// +-----------+-----------+-----------+-----------+
|
|
// | |
|
|
// +---------------+--------------------+
|
|
// |
|
|
// BytesToRead -------+
|
|
//
|
|
// 1 - The first calculation (and read) will align
|
|
// the file pointer with the next cluster.
|
|
// boundary (if we are supposed to read that much)
|
|
// 2 - The next calculation (and read) will read
|
|
// in all the full clusters that the requested
|
|
// amount of data would cover (in this case
|
|
// clusters 2 & 3).
|
|
// 3 - The last calculation (and read) would read
|
|
// in the remainder of the data requested out of
|
|
// the last cluster.
|
|
//
|
|
|
|
BytesPerCluster = (FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector);
|
|
|
|
//
|
|
// Only do the first read if we
|
|
// aren't aligned on a cluster boundary
|
|
//
|
|
if (FatFileInfo->FilePointer % BytesPerCluster)
|
|
{
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
|
|
//
|
|
if (!FatReadPartialCluster(ClusterNumber, OffsetInCluster, LengthInCluster, Buffer))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (BytesRead != NULL)
|
|
{
|
|
*BytesRead += LengthInCluster;
|
|
}
|
|
BytesToRead -= LengthInCluster;
|
|
FatFileInfo->FilePointer += LengthInCluster;
|
|
Buffer += LengthInCluster;
|
|
}
|
|
|
|
//
|
|
// Do the math for our second read (if any data left)
|
|
//
|
|
if (BytesToRead > 0)
|
|
{
|
|
//
|
|
// Determine how many full clusters we need to read
|
|
//
|
|
NumberOfClusters = (BytesToRead / BytesPerCluster);
|
|
|
|
if (NumberOfClusters > 0)
|
|
{
|
|
ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
|
|
ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
|
|
|
|
//
|
|
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
|
|
//
|
|
if (!FatReadClusterChain(ClusterNumber, NumberOfClusters, Buffer))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (BytesRead != NULL)
|
|
{
|
|
*BytesRead += (NumberOfClusters * BytesPerCluster);
|
|
}
|
|
BytesToRead -= (NumberOfClusters * BytesPerCluster);
|
|
FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster);
|
|
Buffer += (NumberOfClusters * BytesPerCluster);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do the math for our third read (if any data left)
|
|
//
|
|
if (BytesToRead > 0)
|
|
{
|
|
ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
|
|
ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
|
|
|
|
//
|
|
// Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
|
|
//
|
|
if (!FatReadPartialCluster(ClusterNumber, 0, BytesToRead, Buffer))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (BytesRead != NULL)
|
|
{
|
|
*BytesRead += BytesToRead;
|
|
}
|
|
FatFileInfo->FilePointer += BytesToRead;
|
|
BytesToRead -= BytesToRead;
|
|
Buffer += BytesToRead;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
U32 FatGetFileSize(FILE *FileHandle)
|
|
{
|
|
PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatGetFileSize() FileSize = %d\n", FatFileHandle->FileSize));
|
|
|
|
return FatFileHandle->FileSize;
|
|
}
|
|
|
|
VOID FatSetFilePointer(FILE *FileHandle, U32 NewFilePointer)
|
|
{
|
|
PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer));
|
|
|
|
FatFileHandle->FilePointer = NewFilePointer;
|
|
}
|
|
|
|
U32 FatGetFilePointer(FILE *FileHandle)
|
|
{
|
|
PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
|
|
|
|
DbgPrint((DPRINT_FILESYSTEM, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle->FilePointer));
|
|
|
|
return FatFileHandle->FilePointer;
|
|
}
|
|
|
|
BOOL FatReadVolumeSectors(U32 DriveNumber, U32 SectorNumber, U32 SectorCount, PVOID Buffer)
|
|
{
|
|
//GEOMETRY DiskGeometry;
|
|
//BOOL ReturnValue;
|
|
//if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
|
|
//{
|
|
// return FALSE;
|
|
//}
|
|
//ReturnValue = DiskReadLogicalSectors(DriveNumber, SectorNumber + FatVolumeBootSector->HiddenSectors, SectorCount, (PVOID)DISKREADBUFFER);
|
|
//RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
|
|
//return ReturnValue;
|
|
|
|
return CacheReadDiskSectors(DriveNumber, SectorNumber + FatVolumeBootSector->HiddenSectors, SectorCount, Buffer);
|
|
}
|