📄 fatparser.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
// FatParser.cpp
//
// Implementation of class FatParser.
//////////////////////////////////////////////////////////////////////////////
// $Id: FatParser.cpp,v 1.7 1999/02/13 04:24:35 nryan Exp $
// Copyright (C) 1998 by Network Associates, Inc.
// All rights reserved.
#include <vtoolscp.h>
#include "Required.h"
#include "UtilityFunctions.h"
#include "FatParser.h"
#include "Globals.h"
////////////
// Constants
////////////
PGPUInt32 kFPFragArrayChunkSize = 20; // frags to allocate at once
PGPUInt32 kFPDataBufSize = 2; // # FAT secs at once
PGPUInt32 kFPMaxLoops = 0x500000; // max clusters to loop
//////////////////////////////////////////
// Class FatParser public member functions
//////////////////////////////////////////
// The FatParser path and Volume object overloaded constructor prepares for
// I/O to the specified file on the specified host.
FatParser::FatParser(LPCSTR path, PGPUInt8 hostDrive, PGPUInt32 bytesFile)
: FileSystemParser(path, hostDrive, bytesFile)
{
pgpAssert(mHost.Mounted());
pgpAssert(IsFatVolume(mFsId));
mDataBuf = NULL;
mNumFragsInUse = 0;
mSizeFragArray = 0;
mFragArray = NULL;
mFatParserReq.isInUse = FALSE;
mInitErr = FileSystemParser::mInitErr;
// Note how we allocate space for one extra sector in the main sector
// buffer. This is because FAT12 sectors can overflow sector boundaries.
if (mInitErr.IsntError())
{
mInitErr = GetByteBuffer((kFPDataBufSize + 1) * mHost.GetBlockSize(),
&mDataBuf);
}
if (mInitErr.IsntError())
{
mInitErr = GetByteBuffer(kFPFragArrayChunkSize*sizeof(FileFrag),
(PGPUInt8 **) &mFragArray);
mSizeFragArray = kFPFragArrayChunkSize;
}
if (mInitErr.IsntError())
{
mInitErr = GetFatData();
}
if (mInitErr.IsntError())
{
mInitErr = MakeFatFrags();
}
#if PGP_DEBUG
if (mInitErr.IsntError())
DumpFrags();
#endif // PGP_DEBUG
}
// The FatParser destructor is responsible for deallocating the list of frags
// and deleting the sector buffer.
FatParser::~FatParser()
{
if (mFragArray)
FreeByteBuffer((PGPUInt8 *) mFragArray);
if (mDataBuf)
FreeByteBuffer((PGPUInt8 *) mDataBuf);
}
// ReadAsync reads nBytes from the file at position pos (in bytes)
// asynchronously.
void
FatParser::ReadAsync(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
PGPUInt16 blockSize;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssertAddrValid(upInfo, GenericCallbackInfo);
pgpAssertAddrValid(upInfo->callback, PGPUInt8);
pgpAssertAddrValid(mFragArray, FileFrag);
pgpAssert(mHost.Mounted());
pgpAssert(mNumFragsInUse > 0);
pgpAssert(!mFatParserReq.isInUse);
mFatParserReq.isInUse = TRUE;
blockSize = mHost.GetBlockSize();
if (pos + nBytes > mBytesFile)
derr = DualErr(kPGDMinorError_OOBFileRequest);
// Prepare the request for execution.
if (derr.IsntError())
{
PGPBoolean doneWithRequest;
mFatParserReq.op = kFPOP_Read;
mFatParserReq.upInfo = upInfo;
mFatParserReq.downInfo.callback = FatParserCallback;
mFatParserReq.downInfo.refData[0] = (PGPUInt32) this;
// We start out by initializing the request so that all possible
// pieces of the request are marked as completed.
mFatParserReq.read.readHeader = TRUE;
mFatParserReq.read.readMiddle = TRUE;
mFatParserReq.read.readTail = TRUE;
// Now we analyze the request and determine what pieces must be
// read so that the entire request can be marked as done.
if (pos%blockSize > 0)
{
PGPUInt32 bytesInHeader;
// The request has a header - that is, it doesn't begin on a
// block boundary.
bytesInHeader = min(nBytes, blockSize - (PGPUInt32)
(pos%blockSize));
mFatParserReq.read.readHeader = FALSE;
mFatParserReq.read.bufHeader = buf;
mFatParserReq.read.posHeader = pos;
mFatParserReq.read.nBytesHeader = bytesInHeader;
buf += bytesInHeader;
pos += bytesInHeader;
nBytes -= bytesInHeader;
}
if (nBytes >= blockSize)
{
PGPUInt32 bytesInMiddle;
// The request has a middle - that is, a section that begins and
// ends on a block boundary and is more than one block in length.
bytesInMiddle = nBytes - nBytes%blockSize;
mFatParserReq.read.readMiddle = FALSE;
mFatParserReq.read.bufMiddle = buf;
mFatParserReq.read.posMiddle = pos;
mFatParserReq.read.nBytesMiddle = bytesInMiddle;
buf += bytesInMiddle;
pos += bytesInMiddle;
nBytes -= bytesInMiddle;
}
if (nBytes > 0)
{
// The request has a tail - that is, it doesn't end on a
// block boundary.
mFatParserReq.read.readTail = FALSE;
mFatParserReq.read.bufTail = buf;
mFatParserReq.read.posTail = pos;
mFatParserReq.read.nBytesTail = nBytes;
}
// Execute the request.
ExecuteRequest(&doneWithRequest);
// Should always have stuff to do at this point. But if we don't, then
// don't hang the computer by not calling back.
if (doneWithRequest)
{
pgpAssert(FALSE);
ScheduleAsyncCallback();
}
}
// Callback on error.
if (derr.IsError())
{
ScheduleAsyncCallback(derr);
}
}
// WriteAsync writes nBytes to the file at position pos (in bytes)
// asynchronously.
void
FatParser::WriteAsync(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
PGPUInt16 blockSize;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssertAddrValid(upInfo, GenericCallbackInfo);
pgpAssertAddrValid(upInfo->callback, PGPUInt8);
pgpAssertAddrValid(mFragArray, FileFrag);
pgpAssert(mHost.Mounted());
pgpAssert(mNumFragsInUse > 0);
pgpAssert(!mFatParserReq.isInUse);
mFatParserReq.isInUse = TRUE;
blockSize = mHost.GetBlockSize();
if (pos + nBytes > mBytesFile)
derr = DualErr(kPGDMinorError_OOBFileRequest);
// Prepare the request for execution.
if (derr.IsntError())
{
PGPBoolean doneWithRequest;
mFatParserReq.op = kFPOP_Write;
mFatParserReq.upInfo = upInfo;
mFatParserReq.downInfo.callback = FatParserCallback;
mFatParserReq.downInfo.refData[0] = (PGPUInt32) this;
// We start out by initializing the request so that all possible
// pieces of the request are marked as completed.
mFatParserReq.write.readHeader = TRUE;
mFatParserReq.write.wroteHeader = TRUE;
mFatParserReq.write.wroteMiddle = TRUE;
mFatParserReq.write.readTail = TRUE;
mFatParserReq.write.wroteTail = TRUE;
// Now we analyze the request and determine what pieces must be
// written so that the entire request can be marked as done.
if (pos%blockSize > 0)
{
PGPUInt32 bytesInHeader;
// The request has a header - that is, it doesn't begin on a
// block boundary.
bytesInHeader = min(nBytes, blockSize - (PGPUInt32)
(pos%blockSize));
mFatParserReq.write.readHeader = FALSE;
mFatParserReq.write.wroteHeader = FALSE;
mFatParserReq.write.bufHeader = buf;
mFatParserReq.write.posHeader = pos;
mFatParserReq.write.nBytesHeader = bytesInHeader;
buf += bytesInHeader;
pos += bytesInHeader;
nBytes -= bytesInHeader;
}
if (nBytes >= blockSize)
{
PGPUInt32 bytesInMiddle;
// The request has a middle - that is, a section that begins and
// ends on a block boundary and is more than one block in length.
bytesInMiddle = nBytes - nBytes%blockSize;
mFatParserReq.write.wroteMiddle = FALSE;
mFatParserReq.write.bufMiddle = buf;
mFatParserReq.write.posMiddle = pos;
mFatParserReq.write.nBytesMiddle = bytesInMiddle;
buf += bytesInMiddle;
pos += bytesInMiddle;
nBytes -= bytesInMiddle;
}
if (nBytes > 0)
{
// The request has a tail - that is, it doesn't end on a
// block boundary.
mFatParserReq.write.readTail = FALSE;
mFatParserReq.write.wroteTail = FALSE;
mFatParserReq.write.bufTail = buf;
mFatParserReq.write.posTail = pos;
mFatParserReq.write.nBytesTail = nBytes;
}
// Execute the request.
ExecuteRequest(&doneWithRequest);
// Should always have stuff to do at this point. But if we don't, then
// don't hang the computer by not calling back.
if (doneWithRequest)
{
pgpAssert(FALSE);
ScheduleAsyncCallback();
}
}
// Callback on error;
if (derr.IsError())
{
ScheduleAsyncCallback(derr);
}
}
// ReadSync reads nBytes from the file at position pos (in bytes)
// synchronously.
DualErr
FatParser::ReadSync(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
PGPUInt16 blockSize;
PGPUInt32 bufPos, i, blocksToRead, sizeChunk;
PGPUInt64 blockVolume;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssertAddrValid(mFragArray, FileFrag);
pgpAssert(mHost.Mounted());
pgpAssert(mNumFragsInUse > 0);
pgpAssert(nBytes > 0);
blockSize = mHost.GetBlockSize();
if (pos + nBytes > mBytesFile)
derr = DualErr(kPGDMinorError_OOBFileRequest);
// The position (pos) and size (nBytes) variables are in bytes, but we can
// only read from a volume in sectors. What we have to do is handle the
// request in at most three separate pieces - a head, middle, and end.
if (derr.IsntError())
{
bufPos = 0;
if (pos%blockSize > 0) // is there a head?
{
PGPUInt32 headOffset, headSize;
i = FindFragmentIndex(pos);
// Now read in the head.
//
// blockVolume = sector on disk containing the head.
// headOffset = byte offset into blockVolume where the head starts
// headSize = size of the head, in bytes
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
headOffset = (PGPUInt32) pos%blockSize;
headSize = min(nBytes, blockSize - headOffset);
derr = mHost.Read(mDataBuf, blockVolume, 1);
if (derr.IsntError())
{
pgpCopyMemory(mDataBuf + headOffset, buf, headSize);
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
}
// Read in 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())
{
blocksToRead = nBytes/blockSize;
while (derr.IsntError() && (blocksToRead > 0)) // is there a middle?
{
i = FindFragmentIndex(pos);
// Determine exactly how many sectors we can read before we must
// move onto the next file fragment.
//
// blockVolume = sector on disk where the current read begins
// sizeChunk = the most sectors we can read in this iteration
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
sizeChunk = min(blocksToRead, (PGPUInt32)
((mFragArray[i].fileEnd - pos) / blockSize) + 1);
derr = mHost.Read(buf + bufPos, blockVolume, sizeChunk);
if (derr.IsntError())
{
bufPos += sizeChunk * blockSize;
nBytes -= sizeChunk * blockSize;
pos += sizeChunk * blockSize;
blocksToRead -= sizeChunk;
}
}
}
// Process the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
i = FindFragmentIndex(pos);
// This read is very simple because we know the tail begins on a
// sector boundary.
//
// secsDisk = the sectors in disk containing the tail.
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
derr = mHost.Read(mDataBuf, blockVolume, 1);
if (derr.IsntError())
pgpCopyMemory(mDataBuf, buf + bufPos, nBytes);
}
}
return derr;
}
// WriteSync reads nBytes from the file at position pos (in bytes)
// synchronously.
DualErr
FatParser::WriteSync(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
PGPUInt16 blockSize;
PGPUInt32 bufPos, i, blocksToWrite, sizeChunk;
PGPUInt64 blockVolume;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssertAddrValid(mFragArray, FileFrag);
pgpAssert(mHost.Mounted());
pgpAssert(mNumFragsInUse > 0);
pgpAssert(nBytes > 0);
blockSize = mHost.GetBlockSize();
if (pos + nBytes > mBytesFile)
derr = DualErr(kPGDMinorError_OOBFileRequest);
// Process the head.
if (derr.IsntError())
{
bufPos = 0;
if (pos%blockSize > 0) // is there a head?
{
PGPUInt32 headOffset, headSize;
i = FindFragmentIndex(pos);
// Write out the head.
//
// blockVolume = sector on disk containing the head
// headOffset = byte offset into secsDisk where the head starts
// headSize = size of the head, in bytes
blockVolume = CalcDiskSector(pos, &mFragArray[i], blockSize);
headOffset = (PGPUInt32) pos%blockSize;
headSize = min(nBytes, blockSize - headOffset);
derr = mHost.Read(mDataBuf, blockVolume, 1);
if (derr.IsntError())
{
pgpCopyMemory(buf, mDataBuf + headOffset, headSize);
derr = mHost.Write(mDataBuf, blockVolume, 1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -