📄 pgpdisk.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
// PGPdisk.cpp
//
// Implementation of class PGPdisk.
//////////////////////////////////////////////////////////////////////////////
// $Id: PGPdisk.cpp,v 1.9 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 "PGPdiskHighLevelUtils.h"
#include "PGPdiskLowLevelUtils.h"
#include "UtilityFunctions.h"
#include "Globals.h"
#include "PGPdisk.h"
#include "PlacementNew.h"
////////////////////////////////////////
// Class PGPdisk public member functions
////////////////////////////////////////
// The PGPdisk default constructor.
PGPdisk::PGPdisk() : VolFile(), mSmContextA(sizeof(CipherContext)),
mSmContextB(sizeof(CipherContext))
{
mContextA = NULL;
mContextB = NULL;
mDataBuf = NULL;
mPGPdiskReq.isInUse = FALSE;
mInitErr = VolFile::mInitErr;
if (mInitErr.IsntError())
{
mInitErr = mSmContextA.mInitErr;
}
if (mInitErr.IsntError())
{
mInitErr = mSmContextB.mInitErr;
}
// Get our data buffer.
if (mInitErr.IsntError())
{
mInitErr = GetByteBuffer(kPGDBlocksPerOp*kDefaultBlockSize,
&mDataBuf);
}
if (mInitErr.IsntError())
{
// Use placement new.
mContextA = new (mSmContextA.GetPtr()) CipherContext;
mContextB = new (mSmContextB.GetPtr()) CipherContext;
}
}
// The PGPdisk destructor cleans up.
PGPdisk::~PGPdisk()
{
if (Mounted())
Unmount(TRUE);
if (IsntNull(mContextB))
{
mContextB->~CipherContext();
mContextB = NULL;
}
if (IsntNull(mContextA))
{
mContextA->~CipherContext();
mContextA = NULL;
}
if (IsntNull(mDataBuf))
{
FreeByteBuffer(mDataBuf);
mDataBuf = NULL;
}
}
// BestGuessComparePaths uses a number of methods to determine if the
// specified file is the same as the current mounted PGPdisk.
PGPBoolean
PGPdisk::BestGuessComparePaths(LPCSTR path)
{
File testFile;
DualErr derr;
PGPBoolean failedTest = FALSE;
PGPUInt32 i, numPGPdiskPathElems, numTestFilePathElems;
PGPUInt64 PGPdiskLength, testFileLength;
pgpAssert(Mounted());
// First try the easy case.
if (ComparePaths(path))
return TRUE;
// See if the number of path elements in each path is the same.
numPGPdiskPathElems = 0;
for (i=0; i<strlen(GetPath()); i++)
{
if ((GetPath()[i] == '\\') || (GetPath()[i] == '/'))
numPGPdiskPathElems++;
}
numTestFilePathElems = 0;
for (i=0; i<strlen(path); i++)
{
if ((path[i] == '\\') || (path[i] == '/'))
numTestFilePathElems++;
}
if (numPGPdiskPathElems != numTestFilePathElems)
failedTest = TRUE;
// Make sure the files are the same size.
if (!failedTest)
{
derr = GetLength(&PGPdiskLength);
}
if (derr.IsntError() && !failedTest)
{
derr = testFile.Open(path, kOF_MustExist | kOF_ReadOnly);
}
if (derr.IsntError() && !failedTest)
{
derr = testFile.GetLength(&testFileLength);
}
if (!failedTest && testFile.Opened())
{
testFile.Close();
}
if (derr.IsntError() && !failedTest)
{
if (PGPdiskLength != testFileLength)
failedTest = TRUE;
}
// Check if the test file is in use (which must be the case with any
// mounted PGPdisk.
if (derr.IsntError() && !failedTest)
{
if (!Driver->IsFileInUse(path))
failedTest = TRUE;
}
// Finally return false if there was an error.
if (derr.IsError())
{
failedTest = TRUE;
}
return !failedTest;
}
// GetUniqueSessionId returns the unique session ID for the PGPdisk.
PGPUInt64
PGPdisk::GetUniqueSessionId()
{
pgpAssert(Mounted());
return mUniqueSessionId;
}
// FlipContexts flips the key bits on each context.
void
PGPdisk::FlipContexts()
{
pgpAssertAddrValid(mContextA, CipherContext);
pgpAssertAddrValid(mContextB, CipherContext);
pgpAssert(Mounted());
mContextA->FlipContext();
mContextB->FlipContext();
}
// ValidateContexts makes sure the cipher procs aren't damaged.
DualErr
PGPdisk::ValidateContexts()
{
DualErr derr;
pgpAssertAddrValid(mContextA, CipherContext);
pgpAssertAddrValid(mContextB, CipherContext);
pgpAssert(Mounted());
derr = mContextA->ValidateContext();
if (derr.IsntError())
{
derr = mContextB->ValidateContext();
}
return derr;
}
// Mount reads in the PGPdisk-specific header and asks VolFile to continue
// with the mount, passing along header and disk size information.
DualErr
PGPdisk::Mount(
LPCSTR path,
CipherContext *context,
PDCB pDcb,
PGPUInt8 drive,
PGPBoolean mountReadOnly)
{
DualErr derr;
File diskFile;
PGPBoolean readHeader = FALSE;
PGPdiskFileHeader *fileHeader;
pgpAssertStrValid(path);
pgpAssertAddrValid(context, CipherContext);
// Mark the PGPdisk as mounted.
if (!mountReadOnly)
SetPGPdiskMountedFlag(path, TRUE);
// Read the session ID.
mUniqueSessionId = GetPGPdiskUniqueSessionId(path);
// Read in the header.
derr = ReadPGPdiskFileMainHeader(path, &fileHeader);
readHeader = derr.IsntError();
// Initialize the contexts and flip context B.
if (derr.IsntError())
{
pgpAssertAddrValid(mContextA, CipherContext);
pgpAssertAddrValid(mContextB, CipherContext);
(* mContextA) = (* mContextB) = (* context);
mContextB->FlipContext();
}
// Finish the mount by calling down.
if (derr.IsntError())
{
derr = VolFile::Mount(path, fileHeader->numHeaderBlocks,
fileHeader->numDataBlocks, pDcb, drive, mountReadOnly);
}
if (derr.IsError())
{
if (!mountReadOnly)
SetPGPdiskMountedFlag(path, FALSE);
}
if (readHeader)
FreePGPdiskFileHeader((PGPdiskFileHeaderInfo *) fileHeader);
return derr;
}
// Unmount unmounts a mounted PGPdisk.
DualErr
PGPdisk::Unmount(PGPBoolean isThisEmergency)
{
DualErr derr;
LPSTR pathCopy;
PGPBoolean dupedPath, wasReadOnly;
pgpAssert(Mounted());
dupedPath = FALSE;
wasReadOnly = IsReadOnly();
// Copy path.
derr = DupeString(GetPath(), &pathCopy);
dupedPath = derr.IsntError();
// Unmount the PGPdisk volume.
if (derr.IsntError())
{
derr = VolFile::Unmount(isThisEmergency);
}
if (derr.IsntError())
{
// Mark as not mounted.
if (!wasReadOnly)
SetPGPdiskMountedFlag(pathCopy, FALSE);
// Unflip the contexts and destroy them.
(mContextA->IsFlipped() ? mContextA->FlipContext() :
mContextB->FlipContext());
mContextA->DestroyContext();
mContextB->DestroyContext();
}
if (dupedPath)
delete[] pathCopy;
return derr;
}
// ReadAsync performs a read request on the mounted PGPdisk asynchronously.
void
PGPdisk::ReadAsync(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
PGPBoolean doneWithRequest;
pgpAssertAddrValid(upInfo, GenericCallbackInfo);
pgpAssertAddrValid(upInfo->callback, PGPUInt8);
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(Mounted());
pgpAssert(!mPGPdiskReq.isInUse);
mPGPdiskReq.isInUse = TRUE;
// Prepare the request for execution.
mPGPdiskReq.op = kPGDOP_Read;
mPGPdiskReq.upInfo = upInfo;
mPGPdiskReq.downInfo.callback = PGPdiskCallback;
mPGPdiskReq.downInfo.refData[0] = (PGPUInt32) this;
// We start out by initializing the request so that all possible
// pieces of the request are marked as completed.
mPGPdiskReq.read.readHeader = TRUE;
mPGPdiskReq.read.readMiddle = TRUE;
mPGPdiskReq.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%kDefaultBlockSize > 0)
{
PGPUInt32 bytesInHeader;
// The request has a header - that is, it doesn't begin on a
// block boundary.
bytesInHeader = min(nBytes, kDefaultBlockSize -
(PGPUInt32) (pos%kDefaultBlockSize));
mPGPdiskReq.read.readHeader = FALSE;
mPGPdiskReq.read.bufHeader = buf;
mPGPdiskReq.read.posHeader = pos;
mPGPdiskReq.read.nBytesHeader = bytesInHeader;
buf += bytesInHeader;
pos += bytesInHeader;
nBytes -= bytesInHeader;
}
if (nBytes >= kDefaultBlockSize)
{
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%kDefaultBlockSize;
mPGPdiskReq.read.readMiddle = FALSE;
mPGPdiskReq.read.bufMiddle = buf;
mPGPdiskReq.read.posMiddle = pos;
mPGPdiskReq.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.
mPGPdiskReq.read.readTail = FALSE;
mPGPdiskReq.read.bufTail = buf;
mPGPdiskReq.read.posTail = pos;
mPGPdiskReq.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();
}
}
// WriteAsync performs a write request on the mounted PGPdisk asynchronously.
void
PGPdisk::WriteAsync(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBytes,
GenericCallbackInfo *upInfo)
{
PGPBoolean doneWithRequest;
pgpAssertAddrValid(upInfo, GenericCallbackInfo);
pgpAssertAddrValid(upInfo->callback, PGPUInt8);
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(Mounted());
pgpAssert(!mPGPdiskReq.isInUse);
mPGPdiskReq.isInUse = TRUE;
// Prepare the request for execution.
mPGPdiskReq.op = kPGDOP_Write;
mPGPdiskReq.upInfo = upInfo;
mPGPdiskReq.downInfo.callback = PGPdiskCallback;
mPGPdiskReq.downInfo.refData[0] = (PGPUInt32) this;
// We start out by initializing the request so that all possible
// pieces of the request are marked as completed.
mPGPdiskReq.write.readHeader = TRUE;
mPGPdiskReq.write.wroteHeader = TRUE;
mPGPdiskReq.write.wroteMiddle = TRUE;
mPGPdiskReq.write.readTail = TRUE;
mPGPdiskReq.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%kDefaultBlockSize > 0)
{
PGPUInt32 bytesInHeader;
// The request has a header - that is, it doesn't begin on a
// block boundary.
bytesInHeader = min(nBytes, kDefaultBlockSize -
(PGPUInt32) (pos%kDefaultBlockSize));
mPGPdiskReq.write.readHeader = FALSE;
mPGPdiskReq.write.wroteHeader = FALSE;
mPGPdiskReq.write.bufHeader = buf;
mPGPdiskReq.write.posHeader = pos;
mPGPdiskReq.write.nBytesHeader = bytesInHeader;
buf += bytesInHeader;
pos += bytesInHeader;
nBytes -= bytesInHeader;
}
if (nBytes >= kDefaultBlockSize)
{
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%kDefaultBlockSize;
mPGPdiskReq.write.wroteMiddle = FALSE;
mPGPdiskReq.write.bufMiddle = buf;
mPGPdiskReq.write.posMiddle = pos;
mPGPdiskReq.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.
mPGPdiskReq.write.readTail = FALSE;
mPGPdiskReq.write.wroteTail = FALSE;
mPGPdiskReq.write.bufTail = buf;
mPGPdiskReq.write.posTail = pos;
mPGPdiskReq.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();
}
}
// ReadSync performs a read request on the mounted PGPdisk synchronously.
DualErr
PGPdisk::ReadSync(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
PGPUInt32 blocksChunk, blocksToRead, 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 read in 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(mDataBuf + headOffset, buf, headSize);
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
// Read in the middle, in 'kPGDBlocksPerOp' chunks.
if (derr.IsntError())
{
blocksToRead = nBytes/kDefaultBlockSize;
while (derr.IsntError() && (blocksToRead > 0)) // is there a middle?
{
// Determine exactly how many blocks to read this iteration.
//
// blockPGPdisk = block on the PGPdisk where this read begins
// blocksChunk = the most blocks we can read in this iteration
blockPGPdisk = pos/kDefaultBlockSize;
blocksChunk = min(blocksToRead, kPGDBlocksPerOp);
derr = VolFile::Read(mDataBuf, blockPGPdisk*kDefaultBlockSize,
blocksChunk*kDefaultBlockSize);
if (derr.IsntError())
{
SmartCipherBlocks(blockPGPdisk, blocksChunk, mDataBuf,
buf + bufPos, kCipherOp_Decrypt);
bufPos += blocksChunk * kDefaultBlockSize;
nBytes -= blocksChunk * kDefaultBlockSize;
pos += blocksChunk * kDefaultBlockSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -