📄 cvolumeimpdrvnt.cpp
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: CVolumeImpDrvNT.cpp,v 1.10 2002/09/26 01:32:11 wjb Exp $
____________________________________________________________________________*/
#include "pgpClassesConfig.h"
#if (_WIN32_WINNT >= 0x0500)
#include <mountmgr.h>
#endif // _WIN32_WINNT >= 0x5000
#include "CDevice.h"
#include "CEvent.h"
#include "CUnicodeString.h"
#include "FsctlCodes.h"
#include "pgpDiskBase.h"
#include "DriverAPI.h"
#include "CDeviceCache.h"
#include "CDriverSubsystemsDrvNT.h"
#include "CVolumeImpDrvNT.h"
#include "DriverMain.h"
_USING_PGP
_UNNAMED_BEGIN
// Constants
const WCHAR *kMountPointDeviceName = L"MountPointManager";
const PGPUInt32 IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
// Types
struct REPARSE_GUID_DATA_BUFFER
{
PGPUInt32 ReparseTag;
PGPUInt16 ReparseDataLength;
PGPUInt16 Reserved;
GUID ReparseGuid;
struct
{
PGPByte DataBuffer[1];
} GenericReparseBuffer;
};
_UNNAMED_END
// Class CVolumeImpDrvNT member functions
#if (_WIN32_WINNT >= 0x0500)
CVolumeImpDrvNT::CVolumeImpDrvNT() : mPDevice(NULL), mVHFileObject(NULL),
mVolumeHandle(NULL), mDirFileObject(NULL), mDirHandle(NULL)
{
Status() = mAsciiDeviceName.Status();
if (Status().IsntError())
Status() = mVHDevice.Status();
if (Status().IsntError())
Status() = mMountMgr.Status();
if (Status().IsntError())
Status() = mDirDevice.Status();
}
#else // !(_WIN32_WINNT < 0x0500)
CVolumeImpDrvNT::CVolumeImpDrvNT() : mPDevice(NULL), mVHFileObject(NULL),
mVolumeHandle(NULL)
{
Status() = mAsciiDeviceName.Status();
if (Status().IsntError())
Status() = mVHDevice.Status();
}
#endif // (_WIN32_WINNT < 0x0500)
CVolumeImpDrvNT::~CVolumeImpDrvNT()
{
if (IsMounted())
{
if (IsAttachedToVolume())
DetachVolume();
else
Unmount(TRUE);
}
}
PGPBoolean
CVolumeImpDrvNT::HasOpenFiles()
{
pgpAssert(IsMounted());
CComboError error;
if (IsLockedForIO() || IsLockedForFormat())
return TRUE;
// If lock fails, then the volume has open files.
error = LockForIO(); // NETABUG has open files?
if (error.IsntError())
UnlockVolume();
return error.IsError();
}
CComboError
CVolumeImpDrvNT::AttachVolume(const char *root, const char *deviceName)
{
pgpAssert(!IsMounted());
CComboError error;
error = mRoot.Assign(root);
if (error.IsntError())
{
if (IsntNull(deviceName))
error = mAsciiDeviceName.Assign(deviceName);
}
if (error.IsntError())
error = FillInBlockInfo();
if (error.IsntError())
{
mIsAttachedToVolume = TRUE;
mVolState = kVolStateMounted;
mLockState = kLockStateNone;
}
return error;
}
void
CVolumeImpDrvNT::DetachVolume()
{
pgpAssert(IsMounted());
pgpAssert(IsAttachedToVolume());
if (IsLockedForIO() || IsLockedForFormat())
UnlockVolume();
mIsAttachedToVolume = FALSE;
mVolState = kVolStateUnmounted;
mLockState = kLockStateNone;
}
CComboError
CVolumeImpDrvNT::Mount(
const char *deviceName,
const char *root,
PGPUInt64 totalBlocks,
PGPUInt32 blockSize,
const void *ioHandlerFunc,
void *refPtr,
PGPBoolean readOnly)
{
pgpAssert(IsUnmounted());
pgpAssertStrValid(deviceName);
pgpAssertStrValid(root);
pgpAssertAddrValid(ioHandlerFunc, VoidAlign);
CComboError error;
// Prepare strings.
CUnicodeString fullDevName;
CUnicodeString fullLinkName;
error = MakeDeviceStrings(deviceName, root, fullDevName, fullLinkName);
if (error.IsntError())
error = mAsciiDeviceName.Assign(deviceName);
if (error.IsntError())
error = mRoot.Assign(root);
if (error.IsntError())
{
mVolState = kVolStateMounted;
mLockState = kLockStateNone;
mIsAttachedToVolume = FALSE;
mTotalBlocks = totalBlocks;
mBlockSize = blockSize;
// Is device for this device name in cache?
if (CDriverSubsystemsDrvNT::DeviceCache().DoesEntryExist(deviceName))
{
// It's in cache, get it.
error = CDriverSubsystemsDrvNT::DeviceCache().GetEntryDevice(
deviceName, mPDevice);
if (readOnly)
mPDevice->Get()->Characteristics |= FILE_READ_ONLY_DEVICE;
else
mPDevice->Get()->Characteristics &= ~FILE_READ_ONLY_DEVICE;
mPDevice->UpdateRefPtr(refPtr);
}
else
{
// Not in cache, create new entry.
error = CDriverSubsystemsDrvNT::DeviceCache().CreateEntry(
deviceName);
mPDevice = new CDevice;
if (IsNull(mPDevice))
error.err = kPGPError_OutOfMemory;
if (error.IsntError())
{
error = mPDevice->Status();
if (error.IsntError())
{
PGPUInt32 attribs = 0;
if (CVolume::kUseRemovableFlag)
attribs |= FILE_REMOVABLE_MEDIA;
if (readOnly)
attribs |= FILE_READ_ONLY_DEVICE;
error = mPDevice->Create(
DriverMain::GetDriverObjectInitParam(), fullDevName,
FILE_DEVICE_DISK, attribs, FALSE,
static_cast<IrpDispatchFunc>(ioHandlerFunc), refPtr);
}
if (error.IsntError())
{
error = CDriverSubsystemsDrvNT::DeviceCache().
SetEntryDevice(deviceName, mPDevice);
if (error.IsError())
mPDevice->Delete();
}
if (error.IsError())
{
delete mPDevice;
mPDevice = NULL;
}
}
}
}
#if (_WIN32_WINNT >= 0x0500)
// Win2k, announce arrival and create mount point.
if (error.IsntError())
error = OpenMountMgr();
if (error.IsntError())
{
error = AnnounceWin2kArrival(fullDevName);
if (error.IsntError())
{
CUnicodeString curLink;
CUnicodeString volId;
error = GetVolumeStrings(deviceName, volId, curLink);
if (error.IsntError())
{
if (!curLink.IsEmpty() && (fullLinkName != curLink))
error = DeleteMountPoint(volId, fullDevName, curLink);
}
if (error.IsntError())
{
if (fullLinkName != curLink)
{
error = CreateMountPoint(volId, fullDevName,
fullLinkName);
}
}
}
CloseMountMgr();
}
#else // !(_WIN32_WINNT >= 0x0500)
// NT4, create symbolic link.
if (error.IsntError())
error = mPDevice->Link(fullLinkName);
#endif // (_WIN32_WINNT >= 0x0500)
if (error.IsError())
{
if (IsntNull(mPDevice))
{
mPDevice->UpdateRefPtr(NULL);
mPDevice = NULL; // no need to delete, it's cached
}
mAsciiDeviceName.Empty();
mRoot.Empty();
mVolState = kVolStateUnmounted;
mLockState = kLockStateNone;
}
return error;
}
CComboError
CVolumeImpDrvNT::Unmount(PGPBoolean isForced)
{
pgpAssert(IsMounted());
pgpAssert(!IsAttachedToVolume());
CComboError error;
// Prepare strings.
CUnicodeString fullDevName;
CUnicodeString fullLinkName;
error = MakeDeviceStrings(DeviceName(), Root(), fullDevName,
fullLinkName);
// Dismount the volume.
if (error.IsntError() && !IsLockedForFormat() && !IsLockedForIO())
{
error = LockForIO();
if (error.IsError() && isForced)
error = OpenVolumeHandle(); // NETABUG forced unmount failure/crash?
}
// Dismount the volume.
if (error.IsntError())
{
error = mVHDevice.SendFsctlRequest(IRP_MN_USER_FS_REQUEST,
FSCTL_DISMOUNT_VOLUME);
if (isForced)
error = CComboError();
}
#if (_WIN32_WINNT >= 0x0500)
// Win2k, delete the mount point.
if (error.IsntError())
error = OpenMountMgr();
if (error.IsntError())
{
CUnicodeString curLink;
CUnicodeString volId;
error = GetVolumeStrings(DeviceName(), volId, curLink);
if (error.IsntError())
error = DeleteMountPoint(volId, fullDevName, fullLinkName);
if (error.IsntError())
{
// Make sure cached link name is empty.
CUnicodeString empty;
error = empty.Status();
CDriverSubsystemsDrvNT::DeviceCache().SetEntryCurLink(
DeviceName(), empty);
}
if (isForced)
error = CComboError();
CloseMountMgr();
}
#else // !(_WIN32_WINNT >= 0x0500)
// NT4, delete the symbolic link.
if (error.IsntError())
error = mPDevice->Unlink();
#endif // (_WIN32_WINNT >= 0x0500)
if (IsLockedForIO() || IsLockedForFormat())
UnlockVolume();
if (IsVolumeHandleOpened())
CloseVolumeHandle();
if (error.IsntError())
{
mPDevice->UpdateRefPtr(NULL);
mPDevice = NULL; // no need to delete, it's cached
mAsciiDeviceName.Empty();
mRoot.Empty();
mVolState = kVolStateUnmounted;
mLockState = kLockStateNone;
}
return error;
}
CComboError
CVolumeImpDrvNT::LockForIO()
{
pgpAssert(IsMounted());
pgpAssert(!IsLockedForIO() && !IsLockedForFormat());
CComboError error;
error = OpenVolumeHandle(); // NETABUG has open files?
if (error.IsntError())
{
error = mVHDevice.SendFsctlRequest(IRP_MN_USER_FS_REQUEST,
FSCTL_LOCK_VOLUME);
}
if (error.IsntError())
mLockState = kLockStateIO;
if (error.IsError())
{
if (IsVolumeHandleOpened())
CloseVolumeHandle();
}
return error;
}
CComboError
CVolumeImpDrvNT::LockForFormat()
{
pgpAssert(IsMounted());
pgpAssert(!IsLockedForIO() && !IsLockedForFormat());
CComboError error;
error = OpenVolumeHandle();
if (error.IsntError())
{
error = mVHDevice.SendFsctlRequest(IRP_MN_USER_FS_REQUEST,
FSCTL_LOCK_VOLUME);
}
if (error.IsntError())
mLockState = kLockStateFormat;
if (error.IsError())
{
if (IsVolumeHandleOpened())
CloseVolumeHandle();
}
return error;
}
CComboError
CVolumeImpDrvNT::UnlockVolume()
{
pgpAssert(IsMounted());
pgpAssert(IsVolumeHandleOpened());
pgpAssert(IsLockedForIO() || IsLockedForFormat());
CComboError error;
if (IsLockedForFormat())
{
error = mVHDevice.SendFsctlRequest(IRP_MN_USER_FS_REQUEST,
FSCTL_DISMOUNT_VOLUME);
}
if (error.IsntError())
{
error = mVHDevice.SendFsctlRequest(IRP_MN_USER_FS_REQUEST,
FSCTL_UNLOCK_VOLUME);
}
if (error.IsntError())
{
mLockState = kLockStateNone;
CloseVolumeHandle();
}
return error;
}
CComboError
CVolumeImpDrvNT::Read(void *buf, PGPUInt64 pos, PGPUInt32 nBlocks) const
{
pgpAssert(IsMounted());
pgpAssert(IsVolumeHandleOpened());
pgpAssert(IsLockedForIO() || IsLockedForFormat());
pgpAssertAddrValid(buf, VoidAlign);
CComboError error;
IO_STATUS_BLOCK ioStatus;
LARGE_INTEGER bigPos;
bigPos.QuadPart = pos * BlockSize();
error.err = ZwReadFile(mVolumeHandle, NULL, NULL, NULL, &ioStatus, buf,
nBlocks * BlockSize(), &bigPos, NULL);
if (error.HaveNonPGPError())
error.pgpErr = kPGPError_VolumeOpFailed;
return error;
}
CComboError
CVolumeImpDrvNT::Write(const void *buf, PGPUInt64 pos, PGPUInt32 nBlocks)
{
pgpAssert(IsMounted());
pgpAssert(IsVolumeHandleOpened());
pgpAssert(IsLockedForIO() || IsLockedForFormat());
pgpAssertAddrValid(buf, VoidAlign);
CComboError error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -