static NTSTATUS EvhdRegisterIo(ParserInstance *parser, BOOLEAN flag1, BOOLEAN flag2, PGUID pSnapshotId) { NTSTATUS status = STATUS_SUCCESS; if (!parser->bIoRegistered) { REGISTER_IO_REQUEST request = { 0 }; REGISTER_IO_RESPONSE response = { 0 }; SCSI_ADDRESS scsiAddressResponse = { 0 }; request.dwVersion = 1; request.dwFlags = flag1 ? 9 : 8; if (flag2) request.wFlags |= 0x1; request.SnapshotId = *pSnapshotId; request.pfnCompleteScsiRequest = &EvhdCompleteScsiRequest; request.pfnSendMediaNotification = &EvhdSendMediaNotification; request.pfnSendNotification = &EvhdSendNotification; request.pVstorInterface = parser->pVstorInterface; request.wMountFlags = parser->wMountFlags; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_REGISTER_IO, &request, sizeof(REGISTER_IO_REQUEST), &response, sizeof(REGISTER_IO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "IOCTL_STORAGE_REGISTER_IO failed with error 0x%0X\n", status); return status; } parser->bIoRegistered = TRUE; parser->dwDiskSaveSize = response.dwDiskSaveSize; parser->dwInnerBufferSize = sizeof(PARSER_STATE) + response.dwExtensionBufferSize; parser->Io = response.Io; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_SCSI_GET_ADDRESS, NULL, 0, &scsiAddressResponse, sizeof(SCSI_ADDRESS)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "IOCTL_SCSI_GET_ADDRESS failed with error 0x%0X\n", status); return status; } parser->ScsiLun = scsiAddressResponse.Lun; parser->ScsiPathId = scsiAddressResponse.PathId; parser->ScsiTargetId = scsiAddressResponse.TargetId; } return status; }
static NTSTATUS EvhdInitialize(HANDLE hFileHandle, PFILE_OBJECT pFileObject, ParserInstance *parser) { NTSTATUS status = STATUS_SUCCESS; parser->pVhdmpFileObject = pFileObject; parser->FileHandle = hFileHandle; /* Initialize Direct IO */ parser->pDirectIoIrp = IoAllocateIrp(IoGetRelatedDeviceObject(parser->pVhdmpFileObject)->StackSize, FALSE); if (!parser->pDirectIoIrp) { LOG_PARSER(LL_FATAL, "IoAllocateIrp failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } /* Initialize QoS */ parser->pQoSStatusIrp = IoAllocateIrp(IoGetRelatedDeviceObject(parser->pVhdmpFileObject)->StackSize, FALSE); if (!parser->pQoSStatusIrp) { LOG_PARSER(LL_FATAL, "IoAllocateIrp failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } parser->pQoSStatusBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, QoSBufferSize, EvhdQoSPoolTag); if (!parser->pQoSStatusBuffer) { LOG_PARSER(LL_FATAL, "ExAllocatePoolWithTag failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } /* Initialize CTL */ ExInitializeRundownProtection(&parser->RecoveryRundownProtection); parser->pRecoveryStatusIrp = IoAllocateIrp(IoGetRelatedDeviceObject(parser->pVhdmpFileObject)->StackSize, FALSE); if (!parser->pRecoveryStatusIrp) { LOG_PARSER(LL_FATAL, "IoAllocateIrp failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } parser->FileHandle = hFileHandle; parser->pVhdmpFileObject = pFileObject; return status; }
NTSTATUS EVhdMountDisk(ParserInstance *parser, UCHAR flags, PGUID pUnkGuid, __out PARSER_MOUNT_INFO *mountInfo) { NTSTATUS status = STATUS_SUCCESS; status = EvhdRegisterIo(parser, flags & 1, (flags >> 1) & 1, pUnkGuid); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "EvhdRegisterIo failed with error 0x%0x\n", status); EvhdUnregisterIo(parser); return status; } parser->bMounted = TRUE; mountInfo->dwInnerBufferSize = parser->dwInnerBufferSize; mountInfo->bUnk = FALSE; mountInfo->bFastPause = parser->bFastPause; mountInfo->bFastClose = parser->bFastClose; return status; }
NTSTATUS EVhdQueryInformationDisk(ParserInstance *parser, EDiskInfoType type, INT unused1, INT unused2, PVOID pBuffer, INT *pBufferSize) { NTSTATUS status = STATUS_SUCCESS; DISK_INFO_REQUEST Request = { EDiskInfoType_Geometry }; DISK_INFO_RESPONSE Response = { 0 }; UNREFERENCED_PARAMETER(unused1); UNREFERENCED_PARAMETER(unused2); if (EDiskInfo_Format == type) { ASSERT(0x38 == sizeof(DISK_INFO_FORMAT)); if (*pBufferSize < sizeof(DISK_INFO_FORMAT)) return status = STATUS_BUFFER_TOO_SMALL; DISK_INFO_FORMAT *pRes = pBuffer; memset(pBuffer, 0, sizeof(DISK_INFO_FORMAT)); Request.RequestCode = EDiskInfoType_Type; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve disk type. 0x%0X\n", status); return status; } pRes->DiskType = Response.vals[0].dwLow; Request.RequestCode = EDiskInfoType_ParserInfo; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve parser info. 0x%0X\n", status); return status; } pRes->DiskFormat = Response.vals[0].dwLow; Request.RequestCode = EDiskInfoType_Geometry; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve size info. 0x%0X\n", status); return status; } pRes->dwBlockSize = Response.vals[2].dwLow; pRes->qwDiskSize = Response.vals[1].qword; Request.RequestCode = EDiskInfoType_LinkageId; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve linkage identifier. 0x%0X\n", status); return status; } pRes->LinkageId = Response.guid; Request.RequestCode = EDiskInfoType_InUseFlag; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve in use flag. 0x%0X\n", status); return status; } pRes->bIsInUse = (BOOLEAN)Response.vals[0].dwLow; Request.RequestCode = EDiskInfoType_IsFullyAllocated; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve fully allocated flag. 0x%0X\n", status); return status; } pRes->bIsFullyAllocated = (BOOLEAN)Response.vals[0].dwLow; Request.RequestCode = EDiskInfoType_PhysicalDisk; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve unk9 flag. 0x%0X\n", status); return status; } pRes->IsRemote = (BOOLEAN)Response.vals[0].dwLow; Request.RequestCode = EDiskInfoType_Page83Data; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve disk identifier. 0x%0X\n", status); return status; } pRes->DiskIdentifier = Response.guid; *pBufferSize = sizeof(DISK_INFO_FORMAT); } else if (EDiskInfo_Fragmentation == type) { status = STATUS_INVALID_DEVICE_REQUEST; } else if (EDiskInfo_ParentNameList == type) { #pragma pack(push, 1) typedef struct { ULONG64 f_0; UCHAR f_8; BOOLEAN bHaveParent; UCHAR _align[2]; INT size; UCHAR data[1]; } ParentNameResponse; typedef struct { UCHAR f_0; BOOLEAN bHaveParent; UCHAR _align[2]; ULONG size; UCHAR data[1]; } ResultBuffer; #pragma pack(pop) if (*pBufferSize < 8) return status = STATUS_BUFFER_TOO_SMALL; ResultBuffer *pRes = (ResultBuffer *)pBuffer; memset(pRes, 0, 8); INT ResponseBufferSize = *pBufferSize + 0x18; ParentNameResponse *ResponseBuffer = (ParentNameResponse *)ExAllocatePoolWithTag(PagedPool, ResponseBufferSize, EvhdPoolTag); if (!ResponseBuffer) return STATUS_INSUFFICIENT_RESOURCES; Request.RequestCode = EDiskInfoType_ParentNameList; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(Request), ResponseBuffer, ResponseBufferSize); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve type info. 0x%0X\n", status); ExFreePoolWithTag(ResponseBuffer, EvhdPoolTag); return status; } pRes->f_0 = ResponseBuffer->f_8; pRes->bHaveParent = ResponseBuffer->bHaveParent; pRes->size = ResponseBuffer->size; if (ResponseBuffer->bHaveParent) { memmove(pRes->data, ResponseBuffer->data, pRes->size); ExFreePoolWithTag(ResponseBuffer, EvhdPoolTag); *pBufferSize = 8 + pRes->size; } else *pBufferSize = 8; } else if (EDiskInfo_PreloadDiskMetadata == type) { if (*pBufferSize < sizeof(BOOLEAN)) return status = STATUS_BUFFER_TOO_SMALL; BOOLEAN *pRes = (BOOLEAN *)pBuffer; BOOLEAN Response = FALSE; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_PRELOAD_DISK_METADATA_V2, NULL, 0, &Response, sizeof(BOOLEAN)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve type info. 0x%0X\n", status); return status; } *pRes = Response; *pBufferSize = sizeof(BOOLEAN); } else if (EDiskInfo_Geometry == type) { ASSERT(0x10 == sizeof(DISK_INFO_GEOMETRY)); if (*pBufferSize < sizeof(DISK_INFO_GEOMETRY)) return status = STATUS_BUFFER_TOO_SMALL; DISK_INFO_GEOMETRY *pRes = pBuffer; Request.RequestCode = EDiskInfoType_Geometry; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve size info. 0x%0X\n", status); return status; } pRes->dwSectorSize = Response.vals[2].dwHigh; pRes->qwDiskSize = Response.vals[0].qword; Request.RequestCode = EDiskInfoType_NumSectors; status = SynchronouseCall(parser->pVhdmpFileObject, IOCTL_STORAGE_VHD_GET_INFORMATION, &Request, sizeof(DISK_INFO_REQUEST), &Response, sizeof(DISK_INFO_RESPONSE)); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to retrieve number of sectors. 0x%0X\n", status); return status; } pRes->dwNumSectors = Response.vals[0].dwLow; *pBufferSize = sizeof(DISK_INFO_GEOMETRY); } else { LOG_PARSER(LL_FATAL, "Unknown Disk info type %X\n", type); status = STATUS_INVALID_DEVICE_REQUEST; } return status; }
NTSTATUS EVhdOpenDisk(PCUNICODE_STRING diskPath, ULONG32 OpenFlags, GUID *pVmId, PVOID vstorInterface, __out ParserInstance **ppOutParser) { NTSTATUS status = STATUS_SUCCESS; PFILE_OBJECT pFileObject = NULL; HANDLE FileHandle = NULL; ParserInstance *parser = NULL; RESILIENCY_INFO_EA vmInfo = { 0 }; if (pVmId) { vmInfo.NextEntryOffset = 0; vmInfo.EaValueLength = sizeof(GUID); vmInfo.EaNameLength = sizeof(vmInfo.EaName) - 1; strncpy(vmInfo.EaName, OPEN_FILE_RESILIENCY_INFO_EA_NAME, sizeof(vmInfo.EaName)); vmInfo.EaValue = *pVmId; } status = OpenVhdmpDevice(&FileHandle, OpenFlags, &pFileObject, diskPath, pVmId ? &vmInfo : NULL); if (!NT_SUCCESS(status)) { LOG_PARSER(LL_FATAL, "Failed to open vhdmp device for virtual disk file %S\n", diskPath->Buffer); goto failure_cleanup; } parser = (ParserInstance *)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(ParserInstance), EvhdPoolTag); if (!parser) { LOG_PARSER(LL_FATAL, "Failed to allocate memory for ParserInstance\n"); status = STATUS_NO_MEMORY; goto failure_cleanup; } memset(parser, 0, sizeof(ParserInstance)); status = EvhdInitialize(FileHandle, pFileObject, parser); if (!NT_SUCCESS(status)) goto failure_cleanup; parser->wMountFlags = OpenFlags & 0x40 ? 4 : OpenFlags & 1; // 4 - ignore SCSI_SYNCHRONIZE_CACHE opcodes, 1 - read only mount EvhdQueryBoolParameter(L"FastPause", TRUE, &parser->bFastPause); EvhdQueryBoolParameter(L"FastClose", TRUE, &parser->bFastClose); parser->pVstorInterface = vstorInterface; *ppOutParser = parser; goto cleanup; failure_cleanup: if (FileHandle) { ZwClose(FileHandle); parser->FileHandle = NULL; } if (parser) { EVhdCloseDisk(parser); } cleanup: return status; }
char remote488_device::recv_update(uint8_t& data) { char c; unsigned i; // Do not iterate too much.. for (i = 0; i < 8 && m_stream->input(&c , 1); i++) { int prev_state = m_rx_state; switch (m_rx_state) { case REM_RX_WAIT_CH: if (is_msg_type(c)) { m_rx_ch = c; m_rx_state = REM_RX_WAIT_COLON; } else if (!is_space(c)) { m_rx_state = REM_RX_WAIT_WS; } break; case REM_RX_WAIT_COLON: if (c == ':') { m_rx_state = REM_RX_WAIT_1ST_HEX; } else { m_rx_state = REM_RX_WAIT_WS; } break; case REM_RX_WAIT_1ST_HEX: if (a2hex(c , m_rx_data)) { m_rx_state = REM_RX_WAIT_2ND_HEX; } else { m_rx_state = REM_RX_WAIT_WS; } break; case REM_RX_WAIT_2ND_HEX: { uint8_t tmp; if (a2hex(c , tmp)) { m_rx_data = (m_rx_data << 4) | tmp; m_rx_state = REM_RX_WAIT_SEP; } else { m_rx_state = REM_RX_WAIT_WS; } } break; case REM_RX_WAIT_SEP: if (is_terminator(c) || is_space(c)) { m_rx_state = REM_RX_WAIT_CH; LOG_PARSER("PARSE %02x %d->%d\n" , c , prev_state , m_rx_state); data = m_rx_data; return m_rx_ch; } else { m_rx_state = REM_RX_WAIT_WS; } break; case REM_RX_WAIT_WS: if (is_terminator(c) || is_space(c)) { m_rx_state = REM_RX_WAIT_CH; } break; default: m_rx_state = REM_RX_WAIT_CH; break; } LOG_PARSER("PARSE %02x %d->%d\n" , c , prev_state , m_rx_state); } return 0; }