📄 fatparser.cpp
字号:
if (derr.IsntError())
{
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
}
// Write out the middle. Since the middle may be in any number of
// fragments on the disk, we have to use a while loop.
if (derr.IsntError())
{
blocksToWrite = nBytes / blockSize;
while (derr.IsntError() && (blocksToWrite > 0)) // is there a middle?
{
i = FindFragmentIndex(pos);
// Determine exactly how many sectors we can write before we must
// move onto the next file fragment.
//
// blockVolume = sector on disk where the current write begins
// sizeChunk = the most sectors we can write in this iteration
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
sizeChunk = min(blocksToWrite, (PGPUInt32)
((mFragArray[i].fileEnd - pos) / blockSize) + 1);
// Now we perform the write from the output buffer to disk.
derr = mHost.Write(buf + bufPos, blockVolume, sizeChunk);
if (derr.IsntError())
{
bufPos += sizeChunk * blockSize;
nBytes -= sizeChunk * blockSize;
pos += sizeChunk * blockSize;
blocksToWrite -= sizeChunk;
}
}
}
// Process the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
i = FindFragmentIndex(pos);
// Write out the tail.
//
// blockVolume = sector on disk containing the tail
// headSize = size of the tail, in bytes
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
derr = mHost.Read(mDataBuf, blockVolume, 1);
if (derr.IsntError())
{
pgpCopyMemory(buf, mDataBuf, nBytes);
derr = mHost.Write(mDataBuf, blockVolume, 1);
}
}
}
return derr;
}
// Read reads nBytes from the file at position pos (in bytes). It uses the
// previously initialized member variable mFragArray to map locations in the
// file to locations on disk, since a file on a FAT volume may be spread out
// in many fragments.
DualErr
FatParser::Read(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
pgpAssertAddrValid(buf, PGPUInt8);
if (upInfo)
ReadAsync(buf, pos, nBytes, upInfo);
else
derr = ReadSync(buf, pos, nBytes);
return derr;
}
// Write writes nBytes to the file at position pos (in bytes). It uses the
// previously initialized member variable mPFF to map locations in the file
// to locations on disk, since a file on a FAT volume may be spread out in
// many fragments.
DualErr
FatParser::Write(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
pgpAssertAddrValid(buf, PGPUInt8);
if (upInfo)
WriteAsync(buf, pos, nBytes, upInfo);
else
derr = WriteSync(buf, pos, nBytes);
return derr;
}
///////////////////////////////////////////
// Class FatParser private member functions
///////////////////////////////////////////
// CalcDiskSector calculates the sector on disk containing a certain location
// in a file, given that location and a pointer to a single FileFrag.
PGPUInt64
FatParser::CalcDiskSector(
PGPUInt64 filePos,
PFileFrag pFF,
PGPUInt16 blockSize)
{
PGPUInt64 diskPos;
pgpAssertAddrValid(pFF, FileFrag);
pgpAssert(filePos >= pFF->fileBegin);
pgpAssert(filePos <= pFF->fileEnd);
diskPos = pFF->diskBegin + (filePos - pFF->fileBegin);
return (diskPos / blockSize);
}
// ExpandFragArray allocated memory for more file fragments.
DualErr
FatParser::ExpandFragArray()
{
DualErr derr;
PFileFrag temp;
// Get memory for more fragments.
derr = GetByteBuffer(
(mSizeFragArray + kFPFragArrayChunkSize) * sizeof(FileFrag),
(PGPUInt8 **) &temp);
if (derr.IsntError())
{
// Copy the old fragments to the new memory.
pgpCopyMemory(mFragArray, temp, mSizeFragArray*sizeof(FileFrag));
// Delete the old memory.
FreeByteBuffer((PGPUInt8 *) mFragArray);
mFragArray = temp;
mSizeFragArray += kFPFragArrayChunkSize;
}
return derr;
}
// FindFragmentIndex will find and return the index of the file fragment that
// contains the file position specified.
PGPUInt32
FatParser::FindFragmentIndex(PGPUInt64 pos)
{
PGPBoolean foundFrag = FALSE;
PGPUInt32 i, j, x;
pgpAssertAddrValid(mFragArray, FileFrag);
pgpAssert(mSizeFragArray > 0);
i = 0;
j = mNumFragsInUse - 1;
// Binary search.
do
{
x = (i + j)/2;
if ((pos >= mFragArray[x].fileBegin) &&
(pos <= mFragArray[x].fileEnd))
{
foundFrag = TRUE;
break;
}
else
{
(pos > mFragArray[x].fileEnd ? i = x + 1: j = x - 1);
}
}
while (j >= i);
if (!foundFrag)
{
pgpDebugMsg("PGPdisk: FindFragment recieved an OOB position");
return 0xFFFFFFFF;
}
else
{
return x;
}
}
// InitFileFrag initializes a file fragment. It sets the beginning (and ending,
// since it is zero length) file and disk parameters according to the passed
// values.
void
FatParser::InitFileFrag(
PFileFrag pFF,
PGPUInt64 fileByte,
PGPUInt64 diskByte)
{
pgpAssertAddrValid(pFF, FileFrag);
pFF->fileBegin = pFF->fileEnd = fileByte;
pFF->diskBegin = pFF->diskEnd = diskByte;
pFF->next = pFF->prev = NULL;
}
#if PGP_DEBUG
// DumpFrags is a debugging procedure that will print out a list of the
// fragments in a file to the debugger.
void
FatParser::DumpFrags()
{
PGPUInt16 blockSize;
PGPUInt64 secBegin, secEnd;
blockSize = mHost.GetBlockSize();
DebugOut("\nPGPdisk: Frags Dump for %s:\n", GetPath());
if (mNumFragsInUse == 0)
{
DebugOut("\nPGPdisk: No frags to dump\n");
}
else
{
for (PGPUInt32 i=0; i < mNumFragsInUse; i++)
{
DebugOut("PGPdisk: Frag #%u", i);
secBegin = mFragArray[i].fileBegin/blockSize;
secEnd = mFragArray[i].fileEnd/blockSize;
DebugOut("PGPdisk: File begin: %u to file end: %u", secBegin,
secEnd);
secBegin = (PGPUInt32) (mFragArray[i].diskBegin/blockSize);
secEnd = (PGPUInt32) (mFragArray[i].diskEnd/blockSize);
DebugOut("PGPdisk: Disk begin: %u to disk end: %u", secBegin,
secEnd);
}
DebugOut("\nPGPdisk: Frag Dump completed\n");
}
}
#endif // PGP_DEBUG
// GetFatData acquires data specific to the FAT filesystem of the host drive
// and fills in the data member 'mFat'.
DualErr
FatParser::GetFatData()
{
DualErr derr;
pgpAssert(mHost.Mounted());
mFat.fdBlockSize = mHost.GetBlockSize();
mFat.fdFsId = mFsId;
switch (mFsId)
{
case kFS_FAT12:
case kFS_FAT16:
{
DevParams16 dp16;
derr = mHost.GetDevParams16(&dp16);
if (derr.IsntError())
{
mFat.fdActiveFat = 0; // always 0
mFat.fdFatCount = dp16.dpFats; // number of FATs
mFat.fdReservedSecs = dp16.dpResSectors; // reserved sectors
mFat.fdRootDirEnts = dp16.dpRootDirEnts; // root dir entries
mFat.fdSpc = dp16.dpSecPerClust; // sectors per cluster
mFat.fdFatSize = dp16.dpFatSecs; // sectors per FAT
mFat.fdFirstSecFat = dp16.dpResSectors; // FATs begin > rsrvd
CalcFatDataSec(&mFat);
}
break;
}
case kFS_FAT32:
{
DevParams32 dp32;
PGPUInt8 activeFat;
PGPUInt32 flags;
derr = mHost.GetDevParams32(&dp32);
if (derr.IsntError())
{
// Check for mirrored FAT tables in FAT32.
flags = dp32.dpExtFlags;
if (flags & BGBPB_F_NoFATMirror)
activeFat = 0;
else
activeFat = (PGPUInt8) (flags & BGBPB_F_ActiveFATMsk);
mFat.fdActiveFat = activeFat; // # of active FAT
mFat.fdFatCount = dp32.dpNumberOfFats; // number of FATs
mFat.fdReservedSecs = dp32.dpReservedSectors; // reserved seecs
mFat.fdSpc = dp32.dpSectorsPerClust; // sects per clust
mFat.fdFatSize = dp32.dpBigSectorsPerFat; // secs per FAT
mFat.fdFirstSecFat = dp32.dpReservedSectors; // FATs > reserved
CalcFatDataSec(&mFat);
}
break;
}
default:
pgpAssert(FALSE);
break;
}
// Finally we make a system call to determine the index of the first
// cluster in the FAT table for our file.
if (derr.IsntError())
{
derr = Driver->GetFirstClustFile(mPath, &mFat.fdFirstClustFile);
}
return derr;
}
// ParseNextCluster is a helper function for MakeFatFrags. Given a set of
// information about a file and its associated FAT table, and the index of
// a cluster in that FAT table, it reads in the next clusters and expands
// the file's fragment list as appropriate.
DualErr
FatParser::ParseNextCluster(ParseNextClusterInfo *pPNCI)
{
DualErr derr;
PGPUInt64 blockVolume;
pgpAssertAddrValid(pPNCI, ParseNextClusterInfo);
// Sanity checks.
if ((pPNCI->curClust > pPNCI->totalClusts) ||
((++pPNCI->overFlow) > kFPMaxLoops))
{
derr = DualErr(kPGDMinorError_CorruptFat);
}
// Check if we are still within the current fragment - that is, if the
// next cluster is 1 greater than the current cluster. If not, create a
// new file fragment.
if (derr.IsntError())
{
if (pPNCI->nextClust == (pPNCI->curClust + 1)) // within fragment?
{
// We are not at the end of a fragment. First increment curClust
// by 1, and expand our fragment by the size (in bytes) of 1
// cluster.
pPNCI->curClust++;
mFragArray[pPNCI->i].fileEnd += pPNCI->spc * pPNCI->blockSize;
mFragArray[pPNCI->i].diskEnd += pPNCI->spc * pPNCI->blockSize;
// Next update the offset to point to the new current cluster's
// data (which will hold the next cluster's index). If the offset
// runs over our buffer size, we have to read in the next buffer.
pPNCI->bitOffset += pPNCI->bitsClust;
if (pPNCI->bitOffset >=
(PGPUInt32) kFPDataBufSize * pPNCI->blockSize * kBitsPerByte)
{
GetClusterInfo(pPNCI->firstSecFat, pPNCI->curClust,
pPNCI->bitsClust, pPNCI->blockSize, &pPNCI->clustSec,
&pPNCI->bitOffset);
derr = mHost.Read(mDataBuf, pPNCI->clustSec,
kFPDataBufSize + 1);
}
}
else
{
PGPUInt64 oldSector;
// OK, we are at the end of a fragment. Set curClust to the index
// of the new cluster (which can be any valid cluster index), and
// expand the current fragment.
pPNCI->curClust = pPNCI->nextClust;
mFragArray[pPNCI->i].fileEnd +=
(pPNCI->spc * pPNCI->blockSize) - 1;
mFragArray[pPNCI->i].diskEnd +=
(pPNCI->spc * pPNCI->blockSize) - 1;
oldSector = pPNCI->clustSec;
// Find the new FAT sector.
GetClusterInfo(pPNCI->firstSecFat, pPNCI->curClust,
pPNCI->bitsClust, pPNCI->blockSize, &pPNCI->clustSec,
&pPNCI->bitOffset);
// If this lies in a different sector, read it in.
if (pPNCI->clustSec != oldSector)
{
derr = mHost.Read(mDataBuf, pPNCI->clustSec,
kFPDataBufSize + 1);
}
// Finally we calculate which sector on disk the new curClust
// refers to, and then we init a new fragment
if (derr.IsntError())
{
blockVolume = ClusterToSector(pPNCI->curClust,
pPNCI->firstSecData, pPNCI->spc, pPNCI->clustBias);
// See if we have to allocate a new frag.
if (pPNCI->i + 1 == mSizeFragArray)
derr = ExpandFragArray();
}
// Init a new file fragment.
if (derr.IsntError())
{
pPNCI->i++;
mNumFragsInUse++;
InitFileFrag(&mFragArray[pPNCI->i],
mFragArray[pPNCI->i - 1].fileEnd + 1,
blockVolume * pPNCI->blockSize);
}
}
}
// Extract the next cluster.
pPNCI->nextClust = ExtractCluster(mDataBuf, pPNCI->bitOffset,
pPNCI->curClust, mFsId);
return derr;
}
// MakeFATFrags constructs the file fragment array for the File being opened
// on its FAT host drive with direct disk access mode. This procedure reads
// directly from the FAT table of the host drive.
DualErr
FatParser::MakeFatFrags()
{
DualErr derr;
PGPUInt8 bitsClust, clustBias;
PGPUInt16 blockSize, spc;
PGPUInt32 bitOffset, clustSec, curClust, fatSize, firstSecFat;
PGPUInt32 firstClustFile, firstSecFile, firstSecData, i, maxClust;
PGPUInt32 minClust, totalClusts;
pgpAssertAddrValid(mDataBuf, PGPUInt8);
pgpAssert(mNumFragsInUse == 0);
// First fill in some filesystem specific data.
switch (mFsId)
{
case kFS_FAT12:
bitsClust = kBitsFat12Clust;
clustBias = kFat12ClustBias;
maxClust = kMaxFat12Clust;
minClust = kMinFat12Clust;
break;
case kFS_FAT16:
bitsClust = kBitsFat16Clust;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -