cpgpdiskimp.cpp

来自「PGP8.0源码 请认真阅读您的文件包然后写出其具体功能」· C++ 代码 · 共 571 行

CPP
571
字号
/*____________________________________________________________________________
		Copyright (C) 2002 PGP Corporation
        All rights reserved.

        $Id: CPGPdiskImp.cpp,v 1.11 2002/09/26 01:32:11 wjb Exp $
____________________________________________________________________________*/

#include "pgpClassesConfig.h"

#include "CString.h"
#include "UDebug.h"
#include "UMath.h"

#include "CCipherContext.h"
#include "DriverAPI.h"
#include "pgpClientErrors.h"

#include "CDiskInactivity.h"
#include "CDriverSubsystems.h"
#include "CPGPdiskImp.h"

_USING_PGP

// Class CPGPdiskImp member functions

CPGPdiskImp::~CPGPdiskImp()
{
	if (IsMounted())
		Unmount(TRUE);
}

CPGPdiskImp::CPGPdiskImp() : mTimeoutActive(FALSE), mHasTimedOut(FALSE)
{
	Status() = mVolume.Status();

	if (Status().IsntError())
		Status() = mCipherContextMutex.Status();
}

void 
CPGPdiskImp::FlipContexts()
{
	mCipherContextMutex.Enter();
	mCipherContext.FlipKeyBytes();
	mCipherContextMutex.Leave();
}

CComboError 
CPGPdiskImp::ValidateContexts()
{
	CComboError	error;

	mCipherContextMutex.Enter();
	error = mCipherContext.Validate();
	mCipherContextMutex.Leave();

	return error;
}

CComboError 
CPGPdiskImp::SetInactivityTimeout(PGPUInt32 seconds)
{
	pgpAssert(IsMounted());

	CComboError	error;

	if (mTimeoutActive)
	{
		error = CDriverSubsystems::DiskInactivity().DestroyInactivityTimer(
			mTimeoutId);

		if (error.IsntError())
		{
			mTimeoutActive = FALSE;
			mHasTimedOut = FALSE;
		}
	}

	if (error.IsntError())
	{
		if (seconds > 0)
		{
			error = CDriverSubsystems::DiskInactivity().CreateInactivityTimer(
				seconds, TRUE, InactivityTimerCallback, 
				reinterpret_cast<ULONG>(this), mTimeoutId);

			if (error.IsntError())
				mTimeoutActive = TRUE;
		}
	}

	return error;
}

void 
CPGPdiskImp::ResetTimedOut()
{
	mHasTimedOut = FALSE;
}

CComboError 
CPGPdiskImp::Mount(
	const char	*path, 
	const char	*root, 
	const char	*deviceName, 
	PGPdiskEncryptionAlgorithm	algorithm, 
	const void	*exportedContext, 
	PGPUInt32	sizeContext, 
	PGPUInt64	firstDataBlock, 
	PGPUInt64	numDataBlocks, 
	const void	*ioHandlerFunc, 
	void		*refPtr, 
	PGPUInt32	procId, 
	PGPBoolean	readOnly)
{
	pgpAssertStrValid(path);
	pgpAssertStrValid(root);
	pgpAssertStrValid(deviceName);
	pgpAssertAddrValid(exportedContext, VoidAlign);
	pgpAssert(sizeContext > 0);
	pgpAssertAddrValid(ioHandlerFunc, VoidAlign);

	CComboError	error;

	mIsReadOnly		= readOnly;
	mFirstDataBlock	= firstDataBlock;
	mNumDataBlocks	= numDataBlocks;

	// Open the PGPdisk file.
	PGPUInt16	flags	= CFile::kNoBufferingFlag;

	if (IsReadOnly())
		flags |= CFile::kReadOnlyFlag;

	error = mFile.Open(path, flags);

	if (error.IsntError())
	{
		// Read in blocksize of host drive.
		error = CalcBlockSizeOfHost(path, mHostBlockSize);

		if (error.IsntError())
		{
			// Create buffer of appropriate size, aligned properly.
			mBufferObject = new CArray<PGPByte>(BlocksPerOp * 
				mHostBlockSize + PFLConstants::kPlatformPageSize);

			if (IsNull(mBufferObject))
				error.pgpErr = kPGPError_OutOfMemory;

			if (error.IsntError())
				error = mBufferObject->Status();

			if (error.IsntError())
			{
				// Use only page-aligned portion of buffer.
				PGPUInt32	baseAddress	= reinterpret_cast<PGPUInt32>(
					mBufferObject->Get());

				mBuffer = reinterpret_cast<PGPByte *>(
					UMath::RoundUpToMultiple<PGPUInt32>(baseAddress, 
					PFLConstants::kPlatformPageSize));

				// Initliaze the cipher context.
				error = mCipherContext.Init(algorithm);

				if (error.IsntError())
				{
					// Import the cipher context data.
					mCipherContext.Import(exportedContext, sizeContext);

					// Create the PGPdisk I/O thread.
					if (IsNull(mIoThread = new CThread))
						error.pgpErr = kPGPError_OutOfMemory;

					if (error.IsntError())
					{
						// Start the PGPdisk I/O thread.
						error = mIoThread->StartThread(MaxQueuedIoReqs);

						// Call down to base classe for pre-mount tasks.
						if (error.IsntError())
							error = PerformPremountTasks();

						if (error.IsntError())
						{
							// Create the PGPdisk volume.
							error = mVolume.Mount(deviceName, root, 
								mNumDataBlocks, kPGPdiskBlockSize, 
								ioHandlerFunc, refPtr, IsReadOnly());

							if (error.IsError())
								mIoThread->KillThread();
						}

						if (error.IsError())
						{
							delete mIoThread;
							mIoThread = NULL;
						}
					}

					if (error.IsError())
						mCipherContext.Cleanup();
				}

				if (error.IsError())
				{
					delete mBufferObject;

					mBufferObject = NULL;
					mBuffer = NULL;
				}
			}
		}

		if (error.IsError())
			mFile.Close();
	}

	return error;
}

CComboError 
CPGPdiskImp::Unmount(PGPBoolean isForced)
{
	CComboError	error;

	pgpAssert(IsMounted());

	// Fail if the PGPdisk has open files.
	if (mVolume.HasOpenFiles())
		error.pgpErr = kPGPClientError_FilesOpenOnDisk; // NETABUG has open files?

	if (isForced)
		error = CComboError();

	// Destroy any active inactivity timeouts.
	if (error.IsntError())
		error = SetInactivityTimeout(0);

	// Destroy the PGPdisk volume.
	if (error.IsntError())
		error = mVolume.Unmount(isForced);

	if (error.IsntError())
	{
		// Kill the IO thread.
		mIoThread->KillThread();

		delete mIoThread;
		mIoThread = NULL;

		// Destroy the cipher context.
		mCipherContext.Cleanup();
		
		// Delete the data buffer.
		delete mBufferObject;

		mBufferObject = NULL;
		mBuffer = NULL;

		// Close the PGPdisk file.
		mFile.Close();
	}

	return error;
}

CComboError 
CPGPdiskImp::Read(void *buf, PGPUInt64 posInBlocks, PGPUInt32 nBlocks) const
{
	pgpAssertAddrValid(buf, PGPByte);
	pgpAssert(IsMounted());

	CComboError	error;

	UDebug::DebugOut("PGPdisk: Reading PGPdisk %s at pos %u nBlocks "
		"%u\n", Root(), static_cast<PGPUInt32>(posInBlocks), nBlocks);

//  Moved around actual decrypt calls because of fsecure hang -wjb
//	mCipherContextMutex.Enter();

	// We must handle the case where the PGPdisk block size is less than the
	// block size of the underlying volume by breaking up the request.

	PGPUInt64	posInBytes	= posInBlocks * kPGPdiskBlockSize;
	PGPUInt32	nBytes		= nBlocks * kPGPdiskBlockSize;
	PGPUInt32	bufPos		= 0;

	if (posInBytes % mHostBlockSize > 0)	// is there a head?
	{
		// Now read in the head.
		//
		// blockPGPdisk = block on PGPdisk containing the head
		// headOffset = byte offset into block where head starts
		// headSize = size of the head, in bytes

		PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
			kPGPdiskBlockSize) / mHostBlockSize;
		PGPUInt32	headOffset		= static_cast<PGPUInt32>(posInBytes % 
			mHostBlockSize);
		PGPUInt32	headSize		= pgpMin(nBytes, mHostBlockSize - 
			headOffset);

		error = mFile.Read(mBuffer, blockPGPdisk * mHostBlockSize, 
			mHostBlockSize);

		if (error.IsntError())
		{
			// Decrypt the blocks.
			mCipherContextMutex.Enter();

			error = mCipherContext.DecryptCFB(
				posInBytes / kPGPdiskBlockSize, 
				headSize / kPGPdiskBlockSize, mBuffer + headOffset, buf);

			mCipherContextMutex.Leave();
		}

		if (error.IsntError())
		{
			bufPos		= headSize;
			posInBytes	+= headSize;
			nBytes		-= headSize;
		}
	}

	// Read the middle in chunks.
	if (error.IsntError())
	{
		PGPUInt32	blocksToRead	= nBytes / mHostBlockSize;

		while (error.IsntError() && (blocksToRead > 0))	// is 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

			PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
				kPGPdiskBlockSize) / mHostBlockSize;
			PGPUInt32	blocksChunk		= pgpMin(blocksToRead, BlocksPerOp);

			error = mFile.Read(mBuffer, blockPGPdisk * mHostBlockSize, 
				blocksChunk * mHostBlockSize);

			if (error.IsntError())
			{
				// Decrypt the blocks.
				mCipherContextMutex.Enter();

				error = mCipherContext.DecryptCFB(
					posInBytes / kPGPdiskBlockSize, 
					(blocksChunk * mHostBlockSize) / kPGPdiskBlockSize, 
					mBuffer, static_cast<PGPByte *>(buf) + bufPos);

				mCipherContextMutex.Leave();
			}

			if (error.IsntError())
			{
				bufPos			+= blocksChunk * mHostBlockSize;
				nBytes			-= blocksChunk * mHostBlockSize;
				posInBytes		+= blocksChunk * mHostBlockSize;
				blocksToRead	-= blocksChunk;
			}
		}
	}
	
	// Read in the tail.
	if (error.IsntError())
	{
		if (nBytes > 0)				// 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.

			PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
				kPGPdiskBlockSize) / mHostBlockSize;

			error = mFile.Read(mBuffer, blockPGPdisk * mHostBlockSize, 
				mHostBlockSize);

			if (error.IsntError())
			{
				// Decrypt the blocks.
				mCipherContextMutex.Enter();

				error = mCipherContext.DecryptCFB(
					posInBytes / kPGPdiskBlockSize, 
					nBytes / kPGPdiskBlockSize, mBuffer, 
					static_cast<PGPByte *>(buf) + bufPos);

				mCipherContextMutex.Leave();
			}
		}
	}

//  Moved around actual decrypt calls because of fsecure hang -wjb
//	mCipherContextMutex.Leave();

	return error;
}

CComboError 
CPGPdiskImp::Write(const void *buf, PGPUInt64 posInBlocks, PGPUInt32 nBlocks)
{
	pgpAssertAddrValid(buf, PGPByte);
	pgpAssert(IsMounted());

	CComboError	error;

	UDebug::DebugOut("PGPdisk: Writing PGPdisk %s at pos %u nBlocks "
		"%u\n", Root(), static_cast<PGPUInt32>(posInBlocks), nBlocks);

//  Moved around actual decrypt calls because of fsecure hang -wjb
//	mCipherContextMutex.Enter();

	// We must handle the case where the PGPdisk block size is less than the
	// block size of the underlying volume by breaking up the request.

	PGPUInt64	posInBytes	= posInBlocks * kPGPdiskBlockSize;
	PGPUInt32	nBytes		= nBlocks * kPGPdiskBlockSize;
	PGPUInt32	bufPos		= 0;

	if (posInBytes % mHostBlockSize > 0)	// is there a head?
	{
		// Now write out the head.
		//
		// blockPGPdisk = block on PGPdisk containing the head
		// headOffset = byte offset into block where head starts
		// headSize = size of the head, in bytes

		PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
			kPGPdiskBlockSize) / mHostBlockSize;
		PGPUInt32	headOffset		= static_cast<PGPUInt32>(posInBytes % 
			mHostBlockSize);
		PGPUInt32	headSize		= pgpMin(nBytes, mHostBlockSize - 
			headOffset);

		// Must read in existing head first.
		error = mFile.Read(mBuffer, blockPGPdisk * mHostBlockSize, 
			mHostBlockSize);

		if (error.IsntError())
		{
			// Encrypt the blocks.
			mCipherContextMutex.Enter();

			error = mCipherContext.DecryptCFB(
				posInBytes / kPGPdiskBlockSize, 
				headSize / kPGPdiskBlockSize, buf, mBuffer + headOffset);

			mCipherContextMutex.Leave();
		}

		if (error.IsntError())
		{
			// Write out the modified header.
			error = mFile.Write(mBuffer, blockPGPdisk * mHostBlockSize, 
				mHostBlockSize);
		}

		if (error.IsntError())
		{
			bufPos		= headSize;
			posInBytes	+= headSize;
			nBytes		-= headSize;
		}
	}

	// Write the middle in chunks.
	if (error.IsntError())
	{
		PGPUInt32	blocksToWrite	= nBytes / mHostBlockSize;

		while (error.IsntError() && (blocksToWrite > 0))	// is 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 read in this iteration

			PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
				kPGPdiskBlockSize) / mHostBlockSize;
			PGPUInt32	blocksChunk		= pgpMin(blocksToWrite, BlocksPerOp);

			// Encrypt the blocks.
			mCipherContextMutex.Enter();

			error = mCipherContext.EncryptCFB(
				posInBytes / kPGPdiskBlockSize, 
				(blocksChunk * mHostBlockSize) / kPGPdiskBlockSize, 
				static_cast<const PGPByte *>(buf) + bufPos, mBuffer);

			mCipherContextMutex.Leave();

			if (error.IsntError())
			{
				// Write out the blocks.
				error = mFile.Write(mBuffer, blockPGPdisk * mHostBlockSize, 
					blocksChunk * mHostBlockSize);
			}

			if (error.IsntError())
			{
				bufPos			+= blocksChunk * mHostBlockSize;
				nBytes			-= blocksChunk * mHostBlockSize;
				posInBytes		+= blocksChunk * mHostBlockSize;
				blocksToWrite	-= blocksChunk;
			}
		}
	}
	
	// Write out the tail.
	if (error.IsntError())
	{
		if (nBytes > 0)		// 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.

			PGPUInt64	blockPGPdisk	= (posInBytes + mFirstDataBlock * 
				kPGPdiskBlockSize) / mHostBlockSize;

			// Must read in existing tail first.
			error = mFile.Read(mBuffer, blockPGPdisk * mHostBlockSize, 
				mHostBlockSize);

			if (error.IsntError())
			{
				// Encrypt the blocks.
				mCipherContextMutex.Enter();

				error = mCipherContext.DecryptCFB(
					posInBytes / kPGPdiskBlockSize, 
					nBytes / kPGPdiskBlockSize, 
					static_cast<const PGPByte *>(buf) + bufPos, mBuffer);

				mCipherContextMutex.Leave();
			}

			if (error.IsntError())
			{
				// Write out the modified tail.
				error = mFile.Write(mBuffer, blockPGPdisk * mHostBlockSize, 
					mHostBlockSize);
			}
		}
	}

//  Moved around actual decrypt calls because of fsecure hang -wjb
//	mCipherContextMutex.Leave();

	return error;
}

void 
CPGPdiskImp::InactivityTimerCallback(ULONG userVal)
{
	CPGPdiskImp	*pImp	= reinterpret_cast<CPGPdiskImp *>(userVal);
	pgpAssertAddrValid(pImp, CPGPdiskImp);

	pImp->mHasTimedOut = TRUE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?