如何解决即使OpenVirtualDisk成功,QueryChangesVirtualDisk仍返回ERROR_INVALID_HANDLE6
我正在试用VirtualDisk API, 到目前为止,我已经能够打开VHDX文件,使用GetVirtualDiskInformation获取一些属性。 但是我无法获得RCT信息和ChangedAreas。
第一次成功调用GetVirtualDiskInformation。 由于缓冲区不足ERROR_INSUFFICIENT_BUFFER(122),对GetVirtualDiskInformation的第二次调用失败。 调用QueryChangesVirtualDisk失败,并显示ERROR_INVALID_HANDLE(6)。 硬编码在代码中的RCT ID是正确的,我能够使用WMI Explorer获得ChangedAreas。 附上相同的屏幕截图。
如果它是无效的句柄,那么GetVirtualDiskInformation也应该抛出相同的错误?
#include "pch.h"
#include <iostream>
#include <string>
#include <cstdlib>
#define WINVER _WIN32_WINNT_WIN10
#include <windows.h>
#include <winioctl.h>
#include <virtdisk.h>
#include <initguid.h>
#pragma comment(lib,"virtdisk.lib")
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT,0xec984aec,0xa0f9,0x47e9,0x90,0x1f,0x71,0x41,0x5a,0x66,0x34,0x5b);
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN,0x00000000,0x0000,0x00,0x00);
int main()
{
HANDLE vhdHandle;
_VIRTUAL_STORAGE_TYPE storageType;
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
wchar_t path[] = L"C:\\Hyper-V\\Virtual Hard Disks\\Lacazette\\Windows2016.vhdx";
VIRTUAL_DISK_ACCESS_MASK mask = VIRTUAL_DISK_ACCESS_GET_INFO;
PGET_VIRTUAL_DISK_INFO diskInfo;
ULONG diskInfoSize = sizeof(GET_VIRTUAL_DISK_INFO);
std::wcout << "size of diskinfo structure " << diskInfoSize << std::endl;
diskInfo = (PGET_VIRTUAL_DISK_INFO)malloc(diskInfoSize);
if (diskInfo == NULL)
{
std::cout << "Failed to malloc disk info,ret=" << std::endl;
return 0;
}
std::wcout << "Opening Virtual disk " << path << std::endl;
DWORD res = OpenVirtualDisk(&storageType,path,VIRTUAL_DISK_ACCESS_GET_INFO,OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,NULL,&vhdHandle);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to open disk,ret=" << res << std::endl;
return 0;
}
diskInfo->Version = GET_VIRTUAL_DISK_INFO_SIZE;
res = GetVirtualDiskInformation(vhdHandle,&diskInfoSize,diskInfo,NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_SIZE,ret=" << res << std::endl;
}
long physicalSize = diskInfo->Size.PhysicalSize;
long virtualSize = diskInfo->Size.VirtualSize;
long sectorSize = diskInfo->Size.SectorSize;
long blockSize = diskInfo->Size.BlockSize;
std::wcout << "physicalSize :" << physicalSize << std::endl;
std::wcout << "virtualSize :" << virtualSize << std::endl;
std::wcout << "sectorSize :" << sectorSize << std::endl;
std::wcout << "blockSize :" << blockSize << std::endl;
diskInfo->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
res = GetVirtualDiskInformation(vhdHandle,NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE,ret=" << res << std::endl;
}
std::cout << "\nrct id:" << diskInfo->ChangeTrackingState.MostRecentId << std::endl;
std::cout << "\nQuerying for changed disk areas...\n" << std::endl;
wchar_t rctId[] = L"rctX:c2eb01d9:ccb1:405d:acb6:f0e76d055906:00000001";
ULONG64 byteOffset = 0L;
ULONG64 byteLength = 19327352832;
QUERY_CHANGES_VIRTUAL_DISK_RANGE* changedAreas = NULL;
ULONG rangeCount = 0L;
ULONG64 processedLength = 0L;
res = QueryChangesVirtualDisk(&vhdHandle,rctId,byteOffset,byteLength,QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,changedAreas,&rangeCount,&processedLength);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to get chanegd areas,ret=" << res << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
std::cout << "closing handle!" <<std::endl;
}
return 0;
}
std::cout << "Total changed areas:" << rangeCount << std::endl;
std::cout << "Total processed length:" << processedLength << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
}
return 0;
}
程序输出:
wmi资源管理器输出的屏幕截图。
解决方法
这在某种程度上是可行的..问题是我传递给QueryChangesVirtualDisk API的rctid格式。应如以下示例所示。我将其包含在大括号{}中,这是不正确的。以下代码成功返回了RCT更改的块
另一个观察结果是,似乎我们从GetVirtualDiskInformation获得的脱机vhdx的ChangeTrackingState.MostRecentId大于我们在VM启动时最初创建的内容。例如,我使用rctid创建了一个参考点:rctX: 4abdf273:7e45:4748:85af:78ec4af82ebf:00000000现在,当vhdx脱机时,如果我查询ChangeTrackingState.MostRecentId,它将为我提供以下信息:rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000001导致QueryChangesVirtualDisk无效, rctid错误。以下功能希望用户从外部传递正确的rctid。显然,Get-VmReferencePoints仍仅列出较早的00000参考点。此(00001)似乎仅由GetVirtualDiskInformation API返回
最后,对于使用实时VM拒绝访问的另一个问题,似乎我们必须将OpenVirtualDisk中的VIRTUAL_DISK_ACCESS_MASK设置为0,以及OPEN_VIRTUAL_DISK_PARAMETERS的版本3,如下所示。这样,我们就可以从实时检查点的VM的基础磁盘查询RCT CBT。从https://github.com/cloudbase/rct-service/issues/1
得到澄清#include <windows.h>
#include <virtdisk.h>
#include <iostream>
bool QueryRCTData(const std::wstring& file,const std::wstring& rctid)
{
DWORD fRet;
HANDLE hVHD;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN,{0xEC984AEC,0xA0F9,0x47e9,{ 0x90,0x1F,0x71,0x41,0x5A,0x66,0x34,0x5B }}
};
OPEN_VIRTUAL_DISK_PARAMETERS params = { 0 };
params.Version = OPEN_VIRTUAL_DISK_VERSION_3;
DWORD fRet = OpenVirtualDisk(
&vst,file.c_str(),(VIRTUAL_DISK_ACCESS_MASK) 0,//VIRTUAL_DISK_ACCESS_ALL,//VIRTUAL_DISK_ACCESS_GET_INFO,OPEN_VIRTUAL_DISK_FLAG_NONE,¶ms,&hvhd);
if (fRet != ERROR_SUCCESS)
{
std::cout << "OpenVirtualDisk failed " << fRet << "\n";
return false;
}
//query rctid
WCHAR vdinfo[2048];
ZeroMemory(vdinfo,sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
ULONG vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,&vdinfoSize,(PGET_VIRTUAL_DISK_INFO)vdinfo,NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE failed " << fRet << "\n";
return false;
}
std::wcout << "RCT ID : " << std::wstring(((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId) << "\n";
//query disk length
ZeroMemory(vdinfo,sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_SIZE;
vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_SIZE failed " << fRet << "\n";
return false;
}
std::cout << "Disk length : " << ((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize << "\n";
ULONG RangeCount = 1024;
ULONG64 ProcessedLength = 0;
QUERY_CHANGES_VIRTUAL_DISK_RANGE Ranges[1024] = { 0 };
fRet = QueryChangesVirtualDisk(
hVHD,rctid.c_str(),//((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId,((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize,QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,Ranges,&RangeCount,&ProcessedLength);
if (fRet != ERROR_SUCCESS)
{
std::cout << "QueryChangesVirtualDisk failed " << fRet << "\n";
return false;
}
std::cout << "RangeCount : " << RangeCount << "\n";
std::cout << "ProcessedLength : " << ProcessedLength << "\n";
for (int i = 0; i < RangeCount; i++)
{
std::cout << "Range offset : " << Ranges[i].ByteOffset << "\n";
std::cout << "Range length : " << Ranges[i].ByteLength << "\n";
}
CloseHandle(hVHD);
return true;
}
int main(void)
{
QueryRCTData(L"D:\\BACKUP\\INCR\\Virtual Hard Disks\\2019.vhdx",L"rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000000");
return 0;
}
#pragma comment(lib,"virtdisk.lib")
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。