📄 pgpdisk.cpp
字号:
blocksToRead -= blocksChunk;
}
}
}
// Read in the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
// This read is very simple because we know the tail begins on a
// block boundary.
//
// blockPGPdisk = the block in the PGPdisk containing the tail.
blockPGPdisk = pos/kDefaultBlockSize;
derr = VolFile::Read(mDataBuf, blockPGPdisk*kDefaultBlockSize,
kDefaultBlockSize);
if (derr.IsntError())
{
SmartCipherBlocks(blockPGPdisk, 1, mDataBuf, mDataBuf,
kCipherOp_Decrypt);
pgpCopyMemory(mDataBuf, buf + bufPos, nBytes);
}
}
}
return derr;
}
// WriteSync performs a write request on the mounted PGPdisk synchronously.
DualErr
PGPdisk::WriteSync(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
PGPUInt32 blocksChunk, blocksToWrite, bufPos;
PGPUInt64 blockPGPdisk;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(Mounted());
// The position (pos) and size (nBytes) variables are in bytes, but we
// can only perform encryption in blocks. What we have to do is handle
// the request in at most three separate pieces - a head, middle, and
// end.
bufPos = 0;
if (pos%kDefaultBlockSize > 0) // is there a head?
{
PGPUInt32 headOffset, headSize;
// Now write the head.
//
// blockPGPdisk = block on PGPdisk containing the head.
// headOffset = byte offset into blockPGPdisk where head starts
// headSize = size of the head, in bytes
blockPGPdisk = pos/kDefaultBlockSize;
headOffset = (PGPUInt32) (pos%kDefaultBlockSize);
headSize = min(nBytes, kDefaultBlockSize - headOffset);
derr = VolFile::Read(mDataBuf, blockPGPdisk*kDefaultBlockSize,
kDefaultBlockSize);
if (derr.IsntError())
{
SmartCipherBlocks(blockPGPdisk, 1, mDataBuf, mDataBuf,
kCipherOp_Decrypt);
pgpCopyMemory(buf, mDataBuf + headOffset, headSize);
SmartCipherBlocks(blockPGPdisk, 1, mDataBuf, mDataBuf,
kCipherOp_Encrypt);
derr = VolFile::Write(mDataBuf, blockPGPdisk*kDefaultBlockSize,
kDefaultBlockSize);
}
if (derr.IsntError())
{
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
// Write the middle, in 'kPGDBlocksPerOp' chunks.
if (derr.IsntError())
{
blocksToWrite = nBytes/kDefaultBlockSize;
while (derr.IsntError() && (blocksToWrite > 0)) // is there a middle?
{
// Determine exactly how many blocks to write this iteration.
//
// blockPGPdisk = block on the PGPdisk where this write begins
// blocksChunk = the most blocks we can write in this iteration
blockPGPdisk = pos/kDefaultBlockSize;
blocksChunk = min(blocksToWrite, kPGDBlocksPerOp);
SmartCipherBlocks(blockPGPdisk, blocksChunk, buf + bufPos,
mDataBuf, kCipherOp_Encrypt);
derr = VolFile::Write(mDataBuf, blockPGPdisk*kDefaultBlockSize,
blocksChunk*kDefaultBlockSize);
if (derr.IsntError())
{
bufPos += blocksChunk * kDefaultBlockSize;
nBytes -= blocksChunk * kDefaultBlockSize;
pos += blocksChunk * kDefaultBlockSize;
blocksToWrite -= blocksChunk;
}
}
}
// Write in the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
// This read is very simple because we know the tail begins on a
// block boundary.
//
// blockPGPdisk = the block in the PGPdisk containing the tail.
blockPGPdisk = pos/kDefaultBlockSize;
derr = VolFile::Read(mDataBuf, blockPGPdisk*kDefaultBlockSize,
kDefaultBlockSize);
if (derr.IsntError())
{
SmartCipherBlocks(blockPGPdisk, 1, mDataBuf, mDataBuf,
kCipherOp_Decrypt);
pgpCopyMemory(buf, mDataBuf, nBytes);
SmartCipherBlocks(blockPGPdisk, 1, mDataBuf, mDataBuf,
kCipherOp_Encrypt);
derr = VolFile::Write(mDataBuf,
blockPGPdisk*kDefaultBlockSize, kDefaultBlockSize);
}
}
}
return derr;
}
// Read performs a read request on the mounted PGPdisk.
DualErr
PGPdisk::Read(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(Mounted());
DebugOut("PGPdisk: Reading PGPdisk %u at pos %u nBlocks %u", GetDrive(),
(PGPUInt32) (pos/kDefaultBlockSize),
(PGPUInt32) (nBytes/kDefaultBlockSize));
if (upInfo)
ReadAsync(buf, pos, nBytes, upInfo);
else
derr = ReadSync(buf, pos, nBytes);
return derr;
}
// Write performs a write request on the mounted PGPdisk.
DualErr
PGPdisk::Write(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
DualErr derr;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(Mounted());
DebugOut("PGPdisk: Writing PGPdisk %u at pos %u nBlocks %u", GetDrive(),
(PGPUInt32) (pos/kDefaultBlockSize),
(PGPUInt32) (nBytes/kDefaultBlockSize));
if (upInfo)
WriteAsync(buf, pos, nBytes, upInfo);
else
derr = WriteSync(buf, pos, nBytes);
return derr;
}
/////////////////////////////////////////
// Class PGPdisk private member functions
/////////////////////////////////////////
// SmartCipherBlocks performs the given cipher operation using whichever
// cipher context isn't flipped.
void
PGPdisk::SmartCipherBlocks(
PGPUInt64 startBlockIndex,
PGPUInt32 nBlocks,
const void *src,
void *dest,
CipherOp op)
{
pgpAssertAddrValid(mContextA, CipherContext);
pgpAssertAddrValid(mContextB, CipherContext);
if (mContextA->IsFlipped())
mContextB->CipherBlocks(startBlockIndex, nBlocks, src, dest, op);
else
mContextA->CipherBlocks(startBlockIndex, nBlocks, src, dest, op);
}
// ExecuteRequest executes the next 'piece' of the current request. If there
// nothing left to execute, 'doneWithRequest' is set to TRUE, otherwise FALSE.
void
PGPdisk::ExecuteRequest(PGPBoolean *doneWithRequest)
{
PGPUInt8 *buf;
PGPUInt32 nBytes;
PGPUInt64 pos;
pgpAssertAddrValid(doneWithRequest, PGPBoolean);
(* doneWithRequest) = FALSE;
pgpAssert(mPGPdiskReq.isInUse);
// Look for the next piece of the request and process it. Read requests
// can consist of reading the header, the tail, or any number of pieces
// in the middle. Write requests are similar except header and tail
// processing must be done in two parts.
switch (mPGPdiskReq.op)
{
case kPGDOP_Read:
if (!mPGPdiskReq.read.readHeader)
{
// Read in the header block.
pos = mPGPdiskReq.read.posHeader;
VolFile::Read(mDataBuf, pos - pos%kDefaultBlockSize,
kDefaultBlockSize, &mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.read.readMiddle)
{
PGPUInt32 bytesToRead;
// Read in as much of the middle as we can. Leave the rest for
// later.
pos = mPGPdiskReq.read.posMiddle;
nBytes = mPGPdiskReq.read.nBytesMiddle;
bytesToRead = min(nBytes, kPGDBlocksPerOp*kDefaultBlockSize);
VolFile::Read(mDataBuf, pos, bytesToRead, &mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.read.readTail)
{
// Read in the tail block.
pos = mPGPdiskReq.read.posTail;
VolFile::Read(mDataBuf, pos, kDefaultBlockSize,
&mPGPdiskReq.downInfo);
}
else
{
(* doneWithRequest) = TRUE;
}
break;
case kPGDOP_Write:
if (!mPGPdiskReq.write.readHeader)
{
// Read in the header block. This must be done because we can't
// encrypt in units smaller than one block. Once we've read in
// the header, we modify it with data from the input buffer,
// encrypt the whole block, and write it out.
pos = mPGPdiskReq.write.posHeader;
VolFile::Read(mDataBuf, pos - pos%kDefaultBlockSize,
kDefaultBlockSize, &mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.write.wroteHeader)
{
// We read in the header block, now modify it with the changed
// data from the input buffer, encrypt it, and write it out.
buf = mPGPdiskReq.write.bufHeader;
pos = mPGPdiskReq.write.posHeader;
nBytes = mPGPdiskReq.write.nBytesHeader;
pgpAssertAddrValid(buf, PGPUInt8);
pgpCopyMemory(buf, mDataBuf + pos%kDefaultBlockSize, nBytes);
SmartCipherBlocks(pos/kDefaultBlockSize, 1, mDataBuf, mDataBuf,
kCipherOp_Encrypt);
VolFile::Write(mDataBuf, pos - pos%kDefaultBlockSize,
kDefaultBlockSize, &mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.write.wroteMiddle)
{
PGPUInt32 bytesToWrite;
// Encrypt and write out as much of the middle as we can. Leave
// the rest for later.
buf = mPGPdiskReq.write.bufMiddle;
pos = mPGPdiskReq.write.posMiddle;
nBytes = mPGPdiskReq.write.nBytesMiddle;
bytesToWrite = min(nBytes, kPGDBlocksPerOp*kDefaultBlockSize);
SmartCipherBlocks(pos/kDefaultBlockSize,
bytesToWrite/kDefaultBlockSize, buf, mDataBuf,
kCipherOp_Encrypt);
VolFile::Write(mDataBuf, pos, bytesToWrite,
&mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.write.readTail)
{
// Read in the tail block. This must be done because we can't
// encrypt in units smaller than one block. Once we've read in
// the tail, we modify it with data from the input buffer,
// encrypt the whole block, and write it out.
pos = mPGPdiskReq.write.posTail;
VolFile::Read(mDataBuf, pos - pos%kDefaultBlockSize,
kDefaultBlockSize, &mPGPdiskReq.downInfo);
}
else if (!mPGPdiskReq.write.wroteTail)
{
// We read in the tail block, now modify it with the changed
// data from the input buffer, encrypt it, and write it out.
buf = mPGPdiskReq.write.bufTail;
pos = mPGPdiskReq.write.posTail;
nBytes = mPGPdiskReq.write.nBytesTail;
pgpAssertAddrValid(buf, PGPUInt8);
pgpCopyMemory(buf, mDataBuf, nBytes);
SmartCipherBlocks(pos/kDefaultBlockSize, 1, mDataBuf, mDataBuf,
kCipherOp_Encrypt);
VolFile::Write(mDataBuf, pos, kDefaultBlockSize,
&mPGPdiskReq.downInfo);
}
else
{
(* doneWithRequest) = TRUE;
}
break;
default:
pgpAssert(FALSE);
break;
}
}
// PGPdiskCallback is called as a callback by the routines who executed our
// read and write requests. We extract the address of the PGPdisk object in
// question and pass the callback to it.
void
PGPdisk::PGPdiskCallback(GenericCallbackInfo *downInfo)
{
PGPdisk *pPGD;
pgpAssertAddrValid(downInfo, GenericCallbackInfo);
pPGD = (PGPdisk *) downInfo->refData[0];
pgpAssertAddrValid(pPGD, PGPdisk);
pPGD->PGPdiskCallbackAux();
}
// PGPdiskCallbackAux is called by the static callback function
// 'PGPdiskCallback' so we don't have to type 'pPGD' before every reference
// to an object member or method.
void
PGPdisk::PGPdiskCallbackAux()
{
DualErr derr;
PGPBoolean doneWithRequest;
PGPUInt8 *buf;
PGPUInt32 nBytes;
PGPUInt64 pos;
pgpAssert(mPGPdiskReq.isInUse);
derr = mPGPdiskReq.downInfo.derr;
if (derr.IsntError())
{
// Before passing the request to 'ExecuteRequest' we perform some pre-
// processing on the data manipulated by the piece of the request that
// was just processed.
switch (mPGPdiskReq.op)
{
case kPGDOP_Read:
if (!mPGPdiskReq.read.readHeader)
{
// We read in the header block. Decrypt and copy just what the
// caller needs into his buffer.
mPGPdiskReq.read.readHeader = TRUE;
buf = mPGPdiskReq.read.bufHeader;
pos = mPGPdiskReq.read.posHeader;
nBytes = mPGPdiskReq.read.nBytesHeader;
pgpAssertAddrValid(buf, PGPUInt8);
SmartCipherBlocks(pos/kDefaultBlockSize, 1, mDataBuf,
mDataBuf, kCipherOp_Decrypt);
pgpCopyMemory(mDataBuf + pos%kDefaultBlockSize, buf, nBytes);
}
else if (!mPGPdiskReq.read.readMiddle)
{
PGPUInt32 bytesRead;
// We read in a piece of the middle. Decrypt it, copy it into
// the output buffer, and if there is still more middle left
// then adjust the variables.
buf = mPGPdiskReq.read.bufMiddle;
pos = mPGPdiskReq.read.posMiddle;
nBytes = mPGPdiskReq.read.nBytesMiddle;
pgpAssertAddrValid(buf, PGPUInt8);
bytesRead = min(nBytes, kPGDBlocksPerOp*kDefaultBlockSize);
SmartCipherBlocks(pos/kDefaultBlockSize,
bytesRead/kDefaultBlockSize, mDataBuf, buf,
kCipherOp_Decrypt);
if (nBytes - bytesRead > 0)
{
mPGPdiskReq.read.bufMiddle += bytesRead;
mPGPdiskReq.read.posMiddle += bytesRead;
mPGPdiskReq.read.nBytesMiddle -= bytesRead;
}
else
{
mPGPdiskReq.read.readMiddle = TRUE;
}
}
else if (!mPGPdiskReq.read.readTail)
{
// We read in the tail block. Decrypt and copy just what the
// caller needs into his buffer.
mPGPdiskReq.read.readTail = TRUE;
buf = mPGPdiskReq.read.bufTail;
pos = mPGPdiskReq.read.posTail;
nBytes = mPGPdiskReq.read.nBytesTail;
pgpAssertAddrValid(buf, PGPUInt8);
SmartCipherBlocks(pos/kDefaultBlockSize, 1, mDataBuf,
mDataBuf, kCipherOp_Decrypt);
pgpCopyMemory(mDataBuf, buf, nBytes);
}
break;
case kPGDOP_Write:
if (!mPGPdiskReq.write.readHeader)
{
// No pre-processing needed here.
mPGPdiskReq.write.readHeader = TRUE;
}
else if (!mPGPdiskReq.write.wroteHeader)
{
// No pre-processing needed here.
mPGPdiskReq.write.wroteHeader = TRUE;
}
else if (!mPGPdiskReq.write.wroteMiddle)
{
PGPUInt32 bytesWritten;
// We wrote out a piece of the middle. If there is still more
// middle left to write out then adjust the variables.
buf = mPGPdiskReq.write.bufMiddle;
pos = mPGPdiskReq.write.posMiddle;
nBytes = mPGPdiskReq.write.nBytesMiddle;
pgpAssertAddrValid(buf, PGPUInt8);
bytesWritten = min(nBytes, kPGDBlocksPerOp*kDefaultBlockSize);
if (nBytes - bytesWritten > 0)
{
mPGPdiskReq.write.bufMiddle += bytesWritten;
mPGPdiskReq.write.posMiddle += bytesWritten;
mPGPdiskReq.write.nBytesMiddle -= bytesWritten;
}
else
{
mPGPdiskReq.write.wroteMiddle = TRUE;
}
}
else if (!mPGPdiskReq.write.readTail)
{
// No pre-processing needed here.
mPGPdiskReq.write.readTail = TRUE;
}
else if (!mPGPdiskReq.write.wroteTail)
{
// No pre-processing needed here.
mPGPdiskReq.write.wroteTail = TRUE;
}
break;
default:
pgpAssert(FALSE);
break;
}
// Perform further processing on this request, if needed.
ExecuteRequest(&doneWithRequest);
}
// Callback if we're done or on error.
if (doneWithRequest || derr.IsError())
{
ScheduleAsyncCallback(derr);
}
}
// ScheduleAsyncCallback schedules a windows event that calls our function
// that will call the asynchronous request up.
void
PGPdisk::ScheduleAsyncCallback(DualErr derr)
{
static RestrictedEvent_THUNK callbackThunk;
pgpAssertAddrValid(mPGPdiskReq.upInfo, GenericCallbackInfo);
mPGPdiskReq.upInfo->derr = derr;
Call_Restricted_Event(0, NULL, PEF_ALWAYS_SCHED, (PVOID) this,
AsyncExecuteCallback, 0, &callbackThunk);
}
// AsyncExecuteCallback was scheduled by 'ScheduleAsyncCallback' for the
// purpose of calling back up the asynchronous request we received.
VOID
__stdcall
PGPdisk::AsyncExecuteCallback(
VMHANDLE hVM,
THREADHANDLE hThread,
PVOID Refdata,
PCLIENT_STRUCT pRegs)
{
PGPdisk *pPGD;
pPGD = (PGPdisk *) Refdata;
pgpAssertAddrValid(pPGD, PGPdisk);
pgpAssert(pPGD->mPGPdiskReq.isInUse);
pPGD->mPGPdiskReq.isInUse = FALSE;
pgpAssertAddrValid(pPGD->mPGPdiskReq.upInfo, GenericCallbackInfo);
pPGD->mPGPdiskReq.upInfo->callback(pPGD->mPGPdiskReq.upInfo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -