即使OpenVirtualDisk成功,QueryChangesVirtualDisk仍返回ERROR_INVALID_HANDLE6

如何解决即使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;
}

程序输出:

enter image description here

wmi资源管理器输出的屏幕截图。

enter image description here

解决方法

这在某种程度上是可行的..问题是我传递给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返回

enter image description here

最后,对于使用实时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,&params,&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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-