📄 cpgpdiskimpdrvnt.cpp
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: CPGPdiskImpDrvNT.cpp,v 1.11 2002/09/26 01:32:11 wjb Exp $
____________________________________________________________________________*/
#include "pgpClassesConfig.h"
#include <devioctl.h>
#if (_WIN32_WINNT >= 0x0500)
#include <mountdev.h>
#endif // _WIN32_WINNT >= 0x5000
#include "CString.h"
#include "UDebug.h"
#include "CDevice.h"
#include "CUnicodeString.h"
#include "DriverAPI.h"
#include "CDeviceCache.h"
#include "CDriverSubsystemsDrvNT.h"
#include "CPGPdiskImpDrvNT.h"
#include "UConstantNamesDrvNT.h"
#include "UMessageLog.h"
_USING_PGP
_UNNAMED_BEGIN
// Constants
enum {kStandardBlockSize = 512};
_UNNAMED_END
// Class CPGPdiskImpDrvNT member functions
CComboError
CPGPdiskImpDrvNT::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 isReadOnly)
{
CComboError error;
// Initialize security tokens.
error = mTokenForMountUnmount.AssignProcessId(procId);
if (error.IsntError())
{
error = mTokenForIo.AssignProcessId(procId);
if (error.IsntError())
{
// Assume security token of the user's original process ID.
mTokenForMountUnmount.ImpersonateToken();
error = CPGPdiskImp::Mount(path, root, deviceName, algorithm,
exportedContext, sizeContext, firstDataBlock, numDataBlocks,
ioHandlerFunc, refPtr, procId, isReadOnly);
mTokenForMountUnmount.RevertToSelf();
if (error.IsError())
mTokenForIo.UnassignProcessId();
}
if (error.IsError())
mTokenForMountUnmount.UnassignProcessId();
}
return error;
}
CComboError
CPGPdiskImpDrvNT::Unmount(PGPBoolean isForced)
{
CComboError error;
// Assume security token of the user's original process ID.
mTokenForMountUnmount.ImpersonateToken(); // NETABUG security
error = CPGPdiskImp::Unmount(isForced);
mTokenForMountUnmount.RevertToSelf(); // NETABUG security
// Uninitialize the previously initialize security tokens.
if (error.IsntError())
{
mTokenForMountUnmount.UnassignProcessId();
mTokenForIo.UnassignProcessId();
}
return error;
}
CComboError
CPGPdiskImpDrvNT::CalcBlockSizeOfHost(
const char *path,
PGPUInt32& hostBlockSize) const
{
pgpAssertStrValid(path);
CComboError error;
// Determine block size.
CString hostRoot;
CVolume host;
error = hostRoot.Status();
if (error.IsntError())
hostRoot.Format("%c:\\", path[0]);
if (error.IsntError())
{
error = host.AttachVolume(hostRoot);
if (error.IsntError())
{
hostBlockSize = host.BlockSize();
host.DetachVolume();
}
// Network path if error.
if (error.IsError())
{
error = CComboError();
hostBlockSize = kStandardBlockSize;
}
}
return error;
}
void
CPGPdiskImpDrvNT::CalcNTFakeDriveLayout(
DRIVE_LAYOUT_INFORMATION *pDLI) const
{
pgpAssertAddrValid(pDLI, DRIVE_LAYOUT_INFORMATION);
pDLI->PartitionCount = 1;
pDLI->Signature = 0;
CalcNTFakePartitionInfo(&pDLI->PartitionEntry[0]);
}
void
CPGPdiskImpDrvNT::CalcNTFakeGeometry(DISK_GEOMETRY *pGeom) const
{
pgpAssertAddrValid(pGeom, DISK_GEOMETRY);
pGeom->Cylinders.QuadPart = TotalBlocks();
pGeom->MediaType = (CVolume::kUseRemovableFlag ?
RemovableMedia : FixedMedia);
pGeom->TracksPerCylinder = 1;
pGeom->SectorsPerTrack = 1;
pGeom->BytesPerSector = kPGPdiskBlockSize;
}
void
CPGPdiskImpDrvNT::CalcNTFakePartitionInfo(
PARTITION_INFORMATION *pPI) const
{
pgpAssertAddrValid(pPI, PARTITION_INFORMATION);
pPI->StartingOffset.QuadPart = kPGPdiskBlockSize;
pPI->PartitionLength.QuadPart = TotalBlocks() * kPGPdiskBlockSize;
pPI->HiddenSectors = 0;
pPI->PartitionNumber = 1;
pPI->PartitionType = PARTITION_ENTRY_UNUSED; // like I know
pPI->BootIndicator = FALSE;
pPI->RecognizedPartition = TRUE;
pPI->RewritePartition = FALSE;
}
NTSTATUS
CPGPdiskImpDrvNT::ProcessIrpMjRead(CIrp& irp)
{
pgpAssert(irp.MajorFunction() == IRP_MJ_READ);
CComboError error;
void *buf;
// Extract parameters. Note that 0 IS a valid length!
PGPUInt64 posInBlocks = irp.ReadPos() / kPGPdiskBlockSize;
PGPUInt32 nBlocks = static_cast<PGPUInt32>(
irp.ReadLength() / kPGPdiskBlockSize);
if (nBlocks > 0)
{
// Extract the buffer.
#if (_WIN32_WINNT >= 0x0500)
buf = MmGetSystemAddressForMdlSafe(irp.MdlAddress(),
NormalPagePriority);
if (IsNull(buf))
error.pgpErr = kPGPError_MemoryOpFailed;
#else // _WIN32_WINNT < 0x5000
buf = MmGetSystemAddressForMdl(irp.MdlAddress());
pgpAssertAddrValid(buf, VoidAlign);
#endif // _WIN32_WINNT >= 0x5000
}
if (error.IsntError())
error = Read(buf, posInBlocks, nBlocks);
if (error.IsntError())
{
irp.Information() = irp.ReadLength();
return STATUS_SUCCESS;
}
else
{
irp.Information() = 0;
return STATUS_DEVICE_DATA_ERROR;
}
}
NTSTATUS
CPGPdiskImpDrvNT::ProcessIrpMjWrite(CIrp& irp)
{
pgpAssert(irp.MajorFunction() == IRP_MJ_WRITE);
CComboError error;
void *buf;
if (IsReadOnly())
return STATUS_MEDIA_WRITE_PROTECTED;
// Extract parameters. Note that 0 IS a valid length!
PGPUInt64 posInBlocks = irp.WritePos() / kPGPdiskBlockSize;
PGPUInt32 nBlocks = static_cast<PGPUInt32>(
irp.WriteLength() / kPGPdiskBlockSize);
if (nBlocks > 0)
{
// Extract the buffer.
#if (_WIN32_WINNT >= 0x0500)
buf = MmGetSystemAddressForMdlSafe(irp.MdlAddress(),
NormalPagePriority);
if (IsNull(buf))
error.pgpErr = kPGPError_MemoryOpFailed;
#else // _WIN32_WINNT < 0x5000
buf = MmGetSystemAddressForMdl(irp.MdlAddress());
pgpAssertAddrValid(buf, VoidAlign);
#endif // _WIN32_WINNT >= 0x5000
}
if (error.IsntError())
error = Write(buf, posInBlocks, nBlocks);
if (error.IsntError())
{
irp.Information() = irp.WriteLength();
return STATUS_SUCCESS;
}
else
{
irp.Information() = 0;
return STATUS_DEVICE_DATA_ERROR;
}
}
void
CPGPdiskImpDrvNT::ProcessIrpCallbackAux(
CIrp& irp,
PGPBoolean& wasIrpCompleted)
{
CComboError error;
PGPUInt8 majorFunc = irp.MajorFunction();
PGPUInt32 irpAddress = reinterpret_cast<PGPUInt32>(
static_cast<PIRP>(irp));
UDebug::DebugOut("PGPdisk: Processing an %s address %X.",
UConstantNamesDrvNT::NameIrpMajorFunction(majorFunc), irpAddress);
// Assume appropriate security context for file access.
if (!mTokenForIo.IsTokenSet())
mTokenForIo.ImpersonateToken();
// Process the IRP according to function.
switch (majorFunc)
{
case IRP_MJ_READ:
error.err = ProcessIrpMjRead(irp);
break;
case IRP_MJ_WRITE:
error.err = ProcessIrpMjWrite(irp);
break;
default:
pgpAssert(FALSE);
irp.Information() = 0;
error.err = STATUS_NOT_IMPLEMENTED;
break;
}
if (error.HaveNonPGPError())
irp.Complete(error.err, IO_DISK_INCREMENT);
else
irp.Complete(error.err);
wasIrpCompleted = TRUE;
UDebug::DebugOut("PGPdisk: Completed an %s address %X status %X.",
UConstantNamesDrvNT::NameIrpMajorFunction(majorFunc),
irpAddress, static_cast<PGPUInt32>(error.err));
}
void
_cdecl
CPGPdiskImpDrvNT::ProcessIrpCallback(void *refPtr)
{
CIrp irp(static_cast<PIRP>(refPtr));
PGPBoolean wasIrpCompleted = FALSE;
__try
{
CPGPdiskImpDrvNT *pImp = static_cast<CPGPdiskImpDrvNT *>(
irp.DriverContext1());
pgpAssertAddrValid(pImp, CPGPdiskImpDrvNT);
pImp->ProcessIrpCallbackAux(irp, wasIrpCompleted);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
UDebug::DebugOut("PGPdisk: Exception in CPGPdiskImpDrvNT::"
"ProcessIrpCallback.");
UMessageLog::Output("Exception caught");
// We don't exit with uncompleted IRPs.
if (!wasIrpCompleted)
{
irp.Information() = 0;
irp.Complete(STATUS_DEVICE_DATA_ERROR);
wasIrpCompleted = TRUE;
}
}
}
CComboError
CPGPdiskImpDrvNT::QueueIrpToIoThread(CIrp& irp)
{
CComboError error;
irp.DriverContext1() = static_cast<PVOID>(this);
error = mIoThread->PerformAsyncCallback(ProcessIrpCallback, irp.Get());
return error;
}
// Added by wjb for Windows XP.
// These are selected snippets from the XP DDK
#ifndef IOCTL_DISK_GET_LENGTH_INFO
#define FTTYPE ((ULONG)'f')
#define IOCTL_VOLUME_BASE ((ULONG) 'V')
#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FT_BALANCED_READ_MODE CTL_CODE(FTTYPE, 6, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_VOLUME_GET_GPT_ATTRIBUTES CTL_CODE(IOCTL_VOLUME_BASE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VOLUME_ONLINE CTL_CODE(IOCTL_VOLUME_BASE, 2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_MOUNTDEV_QUERY_STABLE_GUID CTL_CODE(MOUNTDEVCONTROLTYPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif // IOCTL_DISK_GET_LENGTH_INFO
#ifndef GET_LENGTH_INFORMATION
//
// The structure GET_LENGTH_INFORMATION is used with the ioctl
// IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the
// disk, partition, or volume.
//
typedef struct _GET_LENGTH_INFORMATION {
LARGE_INTEGER Length;
} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
//
// There are currently two ways a disk can be partitioned. With a traditional
// AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT
// partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable
// partition style. There are a very limited number of things you can
// do with a RAW partititon.
//
typedef enum _PARTITION_STYLE {
PARTITION_STYLE_MBR,
PARTITION_STYLE_GPT,
PARTITION_STYLE_RAW
} PARTITION_STYLE;
//
// The following structure defines information in an MBR partition that is not
// common to both GPT and MBR partitions.
//
typedef struct _PARTITION_INFORMATION_MBR {
UCHAR PartitionType;
BOOLEAN BootIndicator;
BOOLEAN RecognizedPartition;
ULONG HiddenSectors;
} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
//
// The following structure defines information in a GPT partition that is
// not common to both GPT and MBR partitions.
//
typedef struct _PARTITION_INFORMATION_GPT {
GUID PartitionType; // Partition type. See table 16-3.
GUID PartitionId; // Unique GUID for this partition.
_int64 Attributes; // See table 16-4.
WCHAR Name [36]; // Partition Name in Unicode.
} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
//
// The PARTITION_INFORMATION_EX structure is used with the
// IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
// IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls.
//
typedef struct _PARTITION_INFORMATION_EX {
PARTITION_STYLE PartitionStyle;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER PartitionLength;
ULONG PartitionNumber;
BOOLEAN RewritePartition;
union {
PARTITION_INFORMATION_MBR Mbr;
PARTITION_INFORMATION_GPT Gpt;
};
} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
//
// IOCTL_STORAGE_GET_HOTPLUG_INFO
//
typedef struct _STORAGE_HOTPLUG_INFO {
ULONG Size; // version
BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd
BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media?
BOOLEAN DeviceHotplug; // ie. 1394, USB, etc.
BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used
} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO;
//
// Output structure for IOCTL_VOLUME_GET_GPT_ATTRIBUTES.
//
typedef struct _VOLUME_GET_GPT_ATTRIBUTES_INFORMATION {
ULONGLONG GptAttributes;
} VOLUME_GET_GPT_ATTRIBUTES_INFORMATION, *PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION;
//
// Output structure for IOCTL_MOUNTDEV_QUERY_STABLE_GUID.
//
typedef struct _MOUNTDEV_STABLE_GUID {
GUID StableGuid;
} MOUNTDEV_STABLE_GUID, *PMOUNTDEV_STABLE_GUID;
#endif // GET_LENGTH_INFORMATION
// End wjb
NTSTATUS
CPGPdiskImpDrvNT::ProcessExtIrpMjDeviceControl(CIrp& irp)
{
pgpAssert(irp.MajorFunction() == IRP_MJ_DEVICE_CONTROL);
CComboError error;
UDebug::DebugOut("PGPdisk: Seen an %s IRP.",
UConstantNamesDrvNT::NameIoctlCode(irp.IoctlCode()));
irp.Information() = 0;
// Perform the IOCTL.
switch (irp.IoctlCode())
{
case IOCTL_DISK_IS_WRITABLE:
// check if disk is read-only
if (IsReadOnly())
error.err = STATUS_MEDIA_WRITE_PROTECTED;
else
error.err = STATUS_SUCCESS;
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -