2025-11-28 00:35:46 +09:00

275 lines
6.5 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <initguid.h>
#include <virtdisk.h>
#include "Storage.h"
//
// This sample demonstrates how to open a VHD or VHDX file in Raw IO mode and how to issue
// raw reads and writes to the virtual hard disk sectors.
//
//
// This sample uses a 1MB buffer for reads/writes but any size that is a multiple of the sector
// size for both VHDs is acceptable.
//
#define SAMPLE_BUFFER_SIZE (1024*1024)
DWORD
SampleRawIO(
_In_ LPCWSTR SourceVirtualDiskPath,
_In_ LPCWSTR DestinationVirtualDiskPath)
{
HANDLE sourceVhdHandle;
HANDLE destinationVhdHandle;
VIRTUAL_STORAGE_TYPE storageType;
OPEN_VIRTUAL_DISK_PARAMETERS openParameters;
ATTACH_VIRTUAL_DISK_PARAMETERS attachParameters;
ATTACH_VIRTUAL_DISK_FLAG attachFlags;
GET_VIRTUAL_DISK_INFO diskInfo;
DWORD opStatus;
OVERLAPPED overlapped;
LARGE_INTEGER virtualDiskSize;
LARGE_INTEGER offset;
ULONG diskInfoSize;
DWORD bytesRead;
DWORD bytesWritten;
PUCHAR buffer;
sourceVhdHandle = INVALID_HANDLE_VALUE;
destinationVhdHandle = INVALID_HANDLE_VALUE;
offset.QuadPart = 0;
buffer = (PUCHAR)malloc(SAMPLE_BUFFER_SIZE);
if (buffer == NULL)
{
opStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Specify UNKNOWN for both device and vendor so the system will use the
// file extension to determine the correct VHD format.
//
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
memset(&openParameters, 0, sizeof(openParameters));
openParameters.Version = OPEN_VIRTUAL_DISK_VERSION_2;
openParameters.Version2.GetInfoOnly = FALSE;
memset(&attachParameters, 0, sizeof(attachParameters));
attachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
memset(&diskInfo, 0, sizeof(diskInfo));
memset(&overlapped, 0, sizeof(overlapped));
//
// Open the source VHD in RAW IO mode to read directly from the virtual disk sectors.
//
//
// VIRTUAL_DISK_ACCESS_NONE is the only acceptable access mask for V2 handle opens.
//
opStatus = OpenVirtualDisk(
&storageType,
SourceVirtualDiskPath,
VIRTUAL_DISK_ACCESS_NONE,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&openParameters,
&sourceVhdHandle);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
//
// Deteremine the source virtual disk size.
//
diskInfo.Version = GET_VIRTUAL_DISK_INFO_SIZE;
diskInfoSize = sizeof(diskInfo);
opStatus = GetVirtualDiskInformation(
sourceVhdHandle,
&diskInfoSize,
&diskInfo,
NULL);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
virtualDiskSize.QuadPart = diskInfo.Size.VirtualSize;
//
// ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST is required for RawIO.
//
attachFlags = ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST |
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY;
opStatus = AttachVirtualDisk(
sourceVhdHandle,
NULL,
attachFlags,
0,
&attachParameters,
NULL);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
//
// Open the destination VHD in RAW IO mode to write directly to the virtual disk sectors.
//
//
// VIRTUAL_DISK_ACCESS_NONE is the only acceptable access mask for V2 handle opens.
//
opStatus = OpenVirtualDisk(
&storageType,
DestinationVirtualDiskPath,
VIRTUAL_DISK_ACCESS_NONE,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&openParameters,
&destinationVhdHandle);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
//
// ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST is required for RawIO.
//
attachFlags = ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST;
opStatus = AttachVirtualDisk(
destinationVhdHandle,
NULL,
attachFlags,
0,
&attachParameters,
NULL);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
while(offset.QuadPart < virtualDiskSize.QuadPart)
{
//
// Read next chunk of source file
//
overlapped.Offset = offset.LowPart;
overlapped.OffsetHigh = offset.HighPart;
if (!ReadFile(
sourceVhdHandle,
buffer,
SAMPLE_BUFFER_SIZE,
&bytesRead,
&overlapped))
{
if (GetLastError() == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(sourceVhdHandle, &overlapped, &bytesRead, TRUE))
{
opStatus = GetLastError();
}
}
if (opStatus != ERROR_SUCCESS)
{
break;
}
}
//
// Write next chunk to destination file
//
overlapped.Offset = offset.LowPart;
overlapped.OffsetHigh = offset.HighPart;
if (!WriteFile(
destinationVhdHandle,
buffer,
bytesRead,
&bytesWritten,
&overlapped))
{
if (GetLastError() == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(destinationVhdHandle, &overlapped, &bytesWritten, TRUE))
{
opStatus = GetLastError();
}
}
if (opStatus != ERROR_SUCCESS)
{
break;
}
if (bytesWritten != bytesRead)
{
opStatus = ERROR_HANDLE_EOF;
break;
}
}
offset.QuadPart += bytesWritten;
}
Cleanup:
if (opStatus == ERROR_SUCCESS)
{
wprintf(L"success, bytes transferred = %I64d\n", offset.QuadPart);
}
else
{
wprintf(L"error = %u\n", opStatus);
}
if (sourceVhdHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(sourceVhdHandle);
}
if (destinationVhdHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(destinationVhdHandle);
}
if (buffer != NULL)
{
free(buffer);
}
return opStatus;
}