591 lines
19 KiB
C++
591 lines
19 KiB
C++
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// fatdevice.cpp - Access Fat16/32 volumes from SINGLDR
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#include "fatdevice.h"
|
||
|
#include "fnames.h"
|
||
|
|
||
|
#pragma warning(disable: 4505) // Compiler generated constructor unreferenced
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Functions for reading the disk
|
||
|
|
||
|
// read the FAT to find the cluster that follows currentCluster
|
||
|
uint32 FatDevice::CalcNextCluster(uint32 currentCluster) __far
|
||
|
{
|
||
|
uint32 SectorToRead, OffsetInSector;
|
||
|
uint32 result32;
|
||
|
uint16 result16;
|
||
|
|
||
|
OffsetInSector = (currentCluster*FatOffsetMultiplier) % (BytesPerSec);
|
||
|
SectorToRead = ((currentCluster*FatOffsetMultiplier) / (BytesPerSec)) + (RsvdSecs) + (LBAStart);
|
||
|
|
||
|
uint8 __far * buffer = FatBuffer;
|
||
|
BiosDiskRead(buffer, SectorToRead, 1, BootDrive);
|
||
|
if (FatType == 32) {
|
||
|
result32 = *((uint32 __far *)(buffer+OffsetInSector));
|
||
|
result32 = result32 & 0x0FFFFFFF; // make it 28-bits
|
||
|
}
|
||
|
else {
|
||
|
result16 = *((uint16 __far *)(buffer+OffsetInSector));
|
||
|
result32 = result16; // implicit cast
|
||
|
}
|
||
|
return result32;
|
||
|
}
|
||
|
|
||
|
// read cluster # ClusterNum into a (pre-allocated) buffer
|
||
|
void FatDevice::ReadCluster(uint32 ClusterNum, uint8 __far * buffer) __far
|
||
|
{
|
||
|
// figure out the first sector:
|
||
|
uint32 startingSector = ((ClusterNum - 2) * SecsPerClus) + FirstDataSec + LBAStart;
|
||
|
|
||
|
// do the read
|
||
|
BiosDiskRead(buffer, startingSector, SecsPerClus, BootDrive);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Functions for matching filenames
|
||
|
|
||
|
// match a short filename (8.3, dot implicit)
|
||
|
int FatShortNameMatch(uint8 __far * buffer, LPCHAR filename)
|
||
|
{
|
||
|
int counter = 0;
|
||
|
|
||
|
// check up to the first dot or 8 chars, whatever comes first
|
||
|
while (counter < 8) {
|
||
|
if (*filename == '.' || *filename == 0) {
|
||
|
break;
|
||
|
}
|
||
|
if (UCase(buffer[counter]) != UCase(*filename)) {
|
||
|
return 0;
|
||
|
}
|
||
|
counter++;
|
||
|
filename++;
|
||
|
}
|
||
|
|
||
|
// pad out to 8 chars with spaces
|
||
|
while (counter < 8) {
|
||
|
if (UCase(buffer[counter++]) != ' ') {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*filename == '.') {
|
||
|
filename++;
|
||
|
}
|
||
|
// check the file extension
|
||
|
while (counter < 11) {
|
||
|
if (*filename == 0) {
|
||
|
break;
|
||
|
}
|
||
|
if (UCase(buffer[counter]) != UCase(*filename)) {
|
||
|
return 0;
|
||
|
}
|
||
|
filename++;
|
||
|
counter++;
|
||
|
}
|
||
|
|
||
|
// pad out to 11 chars with spaces
|
||
|
while (counter < 11) {
|
||
|
if (UCase(buffer[counter++]) != ' ') {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// match a piece of a long filename. This is case insensitive,
|
||
|
// and assumes ascii (high byte of 2-byte strings=0)
|
||
|
int FatLongNamePartialMatch(uint8 __far * buffer,
|
||
|
LPCHAR filename,
|
||
|
uint8 signature,
|
||
|
uint8 checksum)
|
||
|
{
|
||
|
// We don't really check 13 consecutive positions.
|
||
|
// These are the places to check in the dir entry.
|
||
|
int positions[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30};
|
||
|
int counter = 0;
|
||
|
|
||
|
// check entry signature in position 0
|
||
|
if (buffer[0] != signature) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// check FAT LFN signature in positions 11, 26, 27
|
||
|
if (buffer[11] != 0x0F || buffer[26] != 0 || buffer[27] != 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// verify checksum
|
||
|
if (buffer[13] != checksum) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// advance the filename to the current "segment" as indicated by signature
|
||
|
filename += (13 * ((signature & ~0x40)-1));
|
||
|
|
||
|
// compare the characters of the filename, and pad it out to 13
|
||
|
// with 0x0000 and 0xFFFF's
|
||
|
while (*filename != 0 && counter < 13) {
|
||
|
// if this char doesn't match, fail instantly
|
||
|
if ((UCase(buffer[positions[counter]]) != UCase(*filename)) ||
|
||
|
(buffer[positions[counter]+1] != 0))
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
counter++;
|
||
|
filename++;
|
||
|
}
|
||
|
|
||
|
// all that's left is to check the padding
|
||
|
if (counter < 13) {
|
||
|
if ((buffer[positions[counter]] != 0) ||
|
||
|
buffer[positions[counter]+1] != 0)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
counter++;
|
||
|
|
||
|
while (counter < 13) {
|
||
|
if ((buffer[positions[counter]] != 0xFF) ||
|
||
|
buffer[positions[counter]+1] != 0xFF)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
counter++;
|
||
|
}
|
||
|
}
|
||
|
return signature;
|
||
|
}
|
||
|
|
||
|
// this is straight out of the Fat docs: compute the checksum for
|
||
|
// an 8.3 filename
|
||
|
uint8 FatChecksum(uint8 __far * buffer)
|
||
|
{
|
||
|
uint8 checksum = 0;
|
||
|
for (int i = 0; i < 11; i++) {
|
||
|
checksum = (uint8)
|
||
|
(((checksum & 1) ? 0x80 : 0) + (checksum>>1) + buffer[i]);
|
||
|
}
|
||
|
return checksum;
|
||
|
}
|
||
|
|
||
|
// Search from the first cluster of a directory entry to find the Fat
|
||
|
// encoding of a filename. We accomplish this through a FSM. Fat16RootDir
|
||
|
// is a special flag because Fat16 and Fat32 differ on the representation
|
||
|
// of a root directory. The Fat32 code treats the root directory like any
|
||
|
// other. The Fat16 code does not.
|
||
|
int FatDevice::DirLookup(LPCHAR filename,
|
||
|
uint8 /* len */,
|
||
|
FilePtr Directory,
|
||
|
FilePtr File,
|
||
|
int Fat16RootDir) __far
|
||
|
{
|
||
|
// points into the data we've loaded from disk:
|
||
|
uint8 __far * buffer;
|
||
|
|
||
|
// we will use the generic term "block" to refer to a readable
|
||
|
// entity on the disk, since the Fat16 root dir is in sectors while
|
||
|
// the rest of Fat is in clusters
|
||
|
uint32 totalBlocks, blockCounter = 0;
|
||
|
uint32 nextBlock, entriesPerBlock, entryCounter = 0;
|
||
|
|
||
|
if (Fat16RootDir) {
|
||
|
totalBlocks = RootDirSecs;
|
||
|
entriesPerBlock = BytesPerSec / 32;
|
||
|
nextBlock = RootStartSec + LBAStart;
|
||
|
}
|
||
|
else {
|
||
|
totalBlocks = 2; // keep this less than blockCounter
|
||
|
entriesPerBlock = DirEntriesPerClus;
|
||
|
nextBlock = Directory->FirstBlock;
|
||
|
}
|
||
|
|
||
|
// "segment" will refer to the portion of the LongFileName
|
||
|
// about which we care, since it will be in 13-char chunks
|
||
|
uint8 totalSegs, segCounter, segsMatched = 0;
|
||
|
totalSegs = FullFNameLength(filename);
|
||
|
totalSegs = (uint8) ((totalSegs + 12) / 13);
|
||
|
segCounter = totalSegs;
|
||
|
|
||
|
// long file name verification requires a checksum, as well
|
||
|
// as matching a special "entry signature" in byte[0] of the
|
||
|
// directory entry
|
||
|
uint8 checksum = 0, signature = 0;
|
||
|
|
||
|
// the primary loop fetches data to check
|
||
|
while (blockCounter < totalBlocks) {
|
||
|
// read some data and set a counter for when we need more data
|
||
|
if (Fat16RootDir) {
|
||
|
BiosDiskRead(FatBuffer, nextBlock, 1, BootDrive);
|
||
|
entryCounter = BytesPerSec / 32;
|
||
|
}
|
||
|
else {
|
||
|
ReadCluster(nextBlock, FatBuffer);
|
||
|
entryCounter = DirEntriesPerClus;
|
||
|
}
|
||
|
buffer = FatBuffer;
|
||
|
|
||
|
// the inner loop checks entries
|
||
|
while (entryCounter > 0) {
|
||
|
// failure condition #1: if the first bit is zero,
|
||
|
// there are no more directory entries.
|
||
|
if (buffer[0] == 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// success condition #1: do we match on 8.3?
|
||
|
// success condition #2: if segCounter == 0, does checksum match?
|
||
|
if ((FatShortNameMatch(buffer, filename) == 1) ||
|
||
|
(segCounter == 0 && FatChecksum(buffer) == checksum))
|
||
|
{
|
||
|
File->FirstBlock = (*((uint16 __far *)(buffer+20))<<16) +
|
||
|
*((uint16 __far *)(buffer+26));
|
||
|
File->Size = *((uint32 __far *)(buffer+28));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// progress condition: do we match on the current
|
||
|
// segment of long file name?
|
||
|
// first calc checksum and the signature
|
||
|
if (segCounter == totalSegs) {
|
||
|
signature = (uint8) (segCounter | 0x40);
|
||
|
checksum = buffer[13];
|
||
|
}
|
||
|
else {
|
||
|
signature = segCounter;
|
||
|
}
|
||
|
// now do the check
|
||
|
if (signature == FatLongNamePartialMatch(buffer, filename, signature, checksum)) {
|
||
|
// advance to next directory entry and earlier
|
||
|
// segment in the filename
|
||
|
segCounter--;
|
||
|
buffer += 32;
|
||
|
entryCounter--;
|
||
|
}
|
||
|
else {
|
||
|
// if we were checking the first LFN entry then it's
|
||
|
// time to advance the counter
|
||
|
if (segCounter == totalSegs) {
|
||
|
buffer += 32;
|
||
|
entryCounter--;
|
||
|
}
|
||
|
else {
|
||
|
// otherwise this might just be the start of the
|
||
|
// correct entry, so don't advance the counter,
|
||
|
// just reset to the first segment of the filename
|
||
|
segCounter = totalSegs;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// calculate next data block
|
||
|
if (Fat16RootDir == 1) {
|
||
|
nextBlock++;
|
||
|
blockCounter++;
|
||
|
}
|
||
|
else {
|
||
|
nextBlock = CalcNextCluster(nextBlock);
|
||
|
if (nextBlock >= (EndOfClusterMarker))
|
||
|
blockCounter = 2;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Public Functions
|
||
|
|
||
|
int FatDevice::OpenDevice() __far
|
||
|
{
|
||
|
uint8 expectedType = FatType;
|
||
|
int entrycounter = 4; // up to 4 entries in partition table
|
||
|
|
||
|
// allocate memory for reading a sector (assume 512-byte sector size)
|
||
|
MbrBuffer = (uint8 __far *) alloc(512, 0);
|
||
|
|
||
|
// Read the MBR
|
||
|
BiosDiskRead(MbrBuffer, 0, 1, BootDrive);
|
||
|
|
||
|
// temp to make using far pointers easier
|
||
|
uint8 __far * buffer = MbrBuffer;
|
||
|
|
||
|
// search the partition table for a partition whose
|
||
|
// type matches our desired type
|
||
|
buffer += 446; // first entry is at offset 446
|
||
|
while (entrycounter > 0) {
|
||
|
// does the partition type match expectedtype
|
||
|
if (buffer[4] == 0x0c && expectedType == 32) {
|
||
|
FatType = 32;
|
||
|
break;
|
||
|
}
|
||
|
if (buffer[4] == 0x0e && expectedType == 16) {
|
||
|
FatType = 16;
|
||
|
break;
|
||
|
}// try the next entry
|
||
|
entrycounter--;
|
||
|
buffer += 16;
|
||
|
}
|
||
|
// exceptional condition, should never happen...
|
||
|
if (entrycounter == 0) {
|
||
|
printf("USB: Valid Fat partition not found\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// now get the first sector of the active partition, and the
|
||
|
// partition size
|
||
|
LBAStart = *((uint32 __far *)(buffer+8));
|
||
|
LBASize = *((uint32 __far *)(buffer+12));
|
||
|
|
||
|
// we are done with the MBR. now we need to read the boot sector
|
||
|
// to get the FAT parameters
|
||
|
BiosDiskRead(MbrBuffer, LBAStart, 1, BootDrive);
|
||
|
buffer = MbrBuffer;
|
||
|
|
||
|
// Verify the FileSystem type:
|
||
|
// the Microsoft Fat32 documentation is very specific about how this ought to be done.
|
||
|
// However, this is rather ugly, because it requires information that may not be in the bootsector.
|
||
|
// For example, suppose that the volume is Fat16, and the volume is in very bad shape.
|
||
|
// we may read 0 for a 16-bit value, and then look in an invalid portion of the boot sector for a 32-bit value.
|
||
|
// UGH! Well, we'll do it nonetheless:
|
||
|
|
||
|
// read data that should always be in the same place, no matter what
|
||
|
BytesPerSec = *((uint16 __far *)(buffer+11));
|
||
|
SecsPerClus = buffer[13];
|
||
|
RsvdSecs = *((uint16 __far *)(buffer+14));
|
||
|
NumFats = buffer[16];
|
||
|
RootDirEntries = *((uint16 __far *)(buffer+17));
|
||
|
HiddenSecs = *((uint32 __far *)(buffer+28));
|
||
|
|
||
|
// compute the NumFatSecs and TotalSecs fields
|
||
|
// (i.e. read one value, if it is zero, read another)
|
||
|
uint16 tmp16;
|
||
|
tmp16 = *((uint16 __far *)(buffer+19));
|
||
|
if (tmp16 == 0) {
|
||
|
TotalSecs = *((uint32 __far *)(buffer+32));
|
||
|
}
|
||
|
else {
|
||
|
TotalSecs = tmp16;
|
||
|
}
|
||
|
|
||
|
tmp16 = *((uint16 __far *)(buffer+22));
|
||
|
if (tmp16 == 0) {
|
||
|
NumFatSecs = *((uint32 __far *)(buffer+36));
|
||
|
}
|
||
|
else {
|
||
|
NumFatSecs = tmp16;
|
||
|
}
|
||
|
|
||
|
// now we may compute RootDirSectors =
|
||
|
// ((BPB_RootEntCnt*32) + (BPB_BytsPerSec-1))/BPB_BytesPerSec
|
||
|
RootDirSecs = ((RootDirEntries*32) + (BytesPerSec-1))/BytesPerSec;
|
||
|
|
||
|
// Next compute the total data sectors in the volume:
|
||
|
TotalDataSecs = TotalSecs - (RsvdSecs + (NumFats*NumFatSecs) + RootDirSecs);
|
||
|
|
||
|
// Finally, compute the # of clusters in the volume:
|
||
|
ClusterCount = TotalDataSecs / SecsPerClus;
|
||
|
|
||
|
// Do the verification:
|
||
|
if (!(ClusterCount >= 4085 && ClusterCount < 65525 && FatType == 16) && !(ClusterCount >= 65525 && FatType == 32)) {
|
||
|
printf("USB: File System Type does not match Partition Table\n");
|
||
|
return -1; // the partition table did not match the boot sector.
|
||
|
// we can't trust this filesystem.
|
||
|
}
|
||
|
|
||
|
// now we can set fields that are FAT-type specific:
|
||
|
if (FatType == 16) {
|
||
|
RootStartClus = 0;
|
||
|
EndOfClusterMarker = 0xFFF8;
|
||
|
BadClusterMarker = 0xFFF7;
|
||
|
FatOffsetMultiplier = 2;
|
||
|
RootStartSec = (RsvdSecs + (NumFats*NumFatSecs));
|
||
|
}
|
||
|
else {
|
||
|
RootStartClus = *((uint32 __far *)(buffer+44));
|
||
|
EndOfClusterMarker = 0x0FFFFFF8;
|
||
|
BadClusterMarker = 0x0FFFFFF7;
|
||
|
FatOffsetMultiplier = 4;
|
||
|
}
|
||
|
|
||
|
// final computations:
|
||
|
FirstDataSec = (NumFats*NumFatSecs) + RsvdSecs + RootDirSecs;
|
||
|
BytesPerClus = SecsPerClus * BytesPerSec;
|
||
|
DirEntriesPerClus = BytesPerClus/32;
|
||
|
|
||
|
// allocate data for remaining fs buffers:
|
||
|
FatBuffer = (uint8 __far *) alloc((uint16)BytesPerClus, 0); // exactly the size of a cluster
|
||
|
FileBuffer = (uint8 __far *) alloc(0x7FFF, 0); // 32KB
|
||
|
|
||
|
// display results
|
||
|
#if 0
|
||
|
printf("\nDisk Configuration\n");
|
||
|
printf("------------------------------\n");
|
||
|
printf("Boot Drive = %2xh\n", BootDrive);
|
||
|
printf("First Sector of Active Partition = %8lxh\n", LBAStart);
|
||
|
printf("Sectors in Partition = %8lxh\n", LBASize);
|
||
|
printf("Bytes/Sector = %4xh\n", BytesPerSec);
|
||
|
printf("\nFileSystem Configuration\n");
|
||
|
printf("------------------------------\n");
|
||
|
printf("Fat Type = FAT%d\n", FatType);
|
||
|
printf("Sectors/Cluster = %2xh\n", SecsPerClus);
|
||
|
printf("Reserved Sectors = %4xh\n", RsvdSecs);
|
||
|
printf("Number of Fats = %2xh\n", NumFats);
|
||
|
printf("Hidden Sectors = %8lxh\n", HiddenSecs);
|
||
|
printf("Sectors per Fat = %8lxh\n", NumFatSecs);
|
||
|
printf("First Cluster of Root Dir = %8lxh\n", RootStartClus);
|
||
|
printf("First Data Sector in Partition = %8lxh\n", FirstDataSec);
|
||
|
printf("Bytes/Cluster = %8lxh\n", BytesPerClus);
|
||
|
printf("Dir Entries/Cluster = %8lxh\n", DirEntriesPerClus);
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int FatDevice::CloseDevice() __far
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int FatDevice::GetFileProperties(LPCHAR filename,
|
||
|
FilePtr file,
|
||
|
FilePtr directory) __far
|
||
|
{
|
||
|
LPCHAR fname = filename;
|
||
|
uint8 len;
|
||
|
int result;
|
||
|
char c;
|
||
|
int Fat16RootDir = (FatType == 16); // Fat16 Root Dir is special.
|
||
|
// Flag 1st Fat16 read
|
||
|
|
||
|
// we'll continually recycle the File and Directory structs
|
||
|
file->Size = 0;
|
||
|
file->FirstBlock = 0;
|
||
|
directory->FirstBlock = RootStartClus;
|
||
|
|
||
|
// traverse through the filename, identifying tokens and
|
||
|
// looking them up in the current context
|
||
|
bool done = 0;
|
||
|
while (!done) {
|
||
|
// consume the leading '/'
|
||
|
while (fname[0] == '/') {
|
||
|
fname++;
|
||
|
}
|
||
|
|
||
|
// failure condition: whitespace
|
||
|
if (IsEndToken(fname[0])) {
|
||
|
printf("FAT: Invalid filename: ");
|
||
|
PutFName(filename);
|
||
|
printf("\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// find the next separator in the filename ('/' or whitespace),
|
||
|
// store it, and replace it with 0
|
||
|
len = ShortFNameLength(fname);
|
||
|
c = fname[len];
|
||
|
fname[len] = 0;
|
||
|
|
||
|
// look it up and put the results into File
|
||
|
result = DirLookup(fname, len, directory, file, Fat16RootDir);
|
||
|
|
||
|
// undo the change we made to the filename:
|
||
|
fname[len] = c;
|
||
|
|
||
|
// now shut off the Fat16RootDir flag for subsequent directory scans
|
||
|
Fat16RootDir = 0;
|
||
|
if (result == -1) {
|
||
|
printf("FAT: File not found: ");
|
||
|
PutFName(filename);
|
||
|
printf("\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// check loop termination condition
|
||
|
if (c != '/') {
|
||
|
done = 1;
|
||
|
}
|
||
|
else {
|
||
|
fname += len;
|
||
|
// transfer results from File into Directory
|
||
|
directory->FirstBlock = file->FirstBlock;
|
||
|
directory->Size = file->Size;
|
||
|
file->Size = 0;
|
||
|
file->FirstBlock = 0;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
INT16 FatDevice::ReadFileLow(LPCHAR /* filename */,
|
||
|
FilePtr file,
|
||
|
uint8 __far * buffer) __far
|
||
|
{
|
||
|
uint32 bytesread = 0;
|
||
|
uint8 __far * destination = buffer;
|
||
|
uint32 currentcluster = file->FirstBlock;
|
||
|
|
||
|
while (bytesread < file->Size) {
|
||
|
// read the current cluster
|
||
|
if (currentcluster == BadClusterMarker) {
|
||
|
printf("FAT: Bad Cluster encountered\n");
|
||
|
return -1;
|
||
|
}
|
||
|
ReadCluster(currentcluster, destination);
|
||
|
currentcluster = CalcNextCluster(currentcluster);
|
||
|
bytesread += BytesPerClus;
|
||
|
destination = (uint8 __far *) _MK_FP(_FP_SEG(destination), (_FP_OFF(destination)+BytesPerClus));
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UINT32 FatDevice::ReadFileHigh(LPCHAR /* filename */,
|
||
|
FilePtr file,
|
||
|
uint32 destinationAddress,
|
||
|
uint32 /* cbDestination */) __far
|
||
|
{
|
||
|
uint32 bytesread = 0;
|
||
|
uint32 nextdestination = destinationAddress;
|
||
|
uint32 currentcluster = file->FirstBlock;
|
||
|
uint32 sector;
|
||
|
|
||
|
uint32 bufferaddress = PointerToUint32(FileBuffer);
|
||
|
|
||
|
while (bytesread < file->Size) {
|
||
|
// ensure cluster is valid
|
||
|
if (currentcluster == BadClusterMarker) {
|
||
|
printf("FAT: Bad Cluster encountered\n");
|
||
|
return bytesread;
|
||
|
}
|
||
|
|
||
|
// calc true sector for this cluster
|
||
|
sector = ((currentcluster-2) * SecsPerClus)+ FirstDataSec + LBAStart;
|
||
|
|
||
|
// do the read
|
||
|
BiosDiskRead(FileBuffer, sector, SecsPerClus, BootDrive);
|
||
|
|
||
|
// move the data into extended memory
|
||
|
PModeTransfer(bufferaddress, nextdestination, BytesPerClus);
|
||
|
|
||
|
// get next cluster number
|
||
|
currentcluster = CalcNextCluster(currentcluster);
|
||
|
|
||
|
// update the count of bytes read
|
||
|
bytesread += BytesPerClus;
|
||
|
|
||
|
// and update the destination address
|
||
|
nextdestination += BytesPerClus;
|
||
|
}
|
||
|
|
||
|
// since we read full sectors at the bios level,
|
||
|
// we should trim our count back down a bit here
|
||
|
if (bytesread > file->Size)
|
||
|
bytesread = file->Size;
|
||
|
return bytesread;
|
||
|
}
|