[channels,rdpdr] fix IRP handling

* clean up IRP creation
* Properly handle each IRP, call irp->Complete or irp->Discard only once
  for each IRP
* For each channel split IRP handling, one function prepares the data
  and a single evaluate function later calls irp->Complete or irp->Discard
This commit is contained in:
Armin Novak
2026-02-17 14:11:46 +01:00
parent 66d84e7f45
commit 5f10ae9599
7 changed files with 134 additions and 128 deletions

View File

@@ -23,6 +23,7 @@
#include <freerdp/config.h>
#include <freerdp/utils/helpers.h>
#include <freerdp/utils/rdpdr_utils.h>
#include <errno.h>
#include <stdio.h>
@@ -155,12 +156,11 @@ static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
*/
static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
{
UINT32 FileId = 0;
DRIVE_FILE* file = NULL;
BYTE Information = 0;
const WCHAR* path = NULL;
if (!drive || !irp || !irp->devman)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->devman)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 6 * 4 + 8))
@@ -177,10 +177,11 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
return ERROR_INVALID_DATA;
path = Stream_ConstPointer(irp->input);
FileId = irp->devman->id_sequence++;
file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess,
CreateDisposition, CreateOptions, FileAttributes, SharedAccess);
const WCHAR* path = Stream_ConstPointer(irp->input);
UINT32 FileId = irp->devman->id_sequence++;
DRIVE_FILE* file =
drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess,
CreateDisposition, CreateOptions, FileAttributes, SharedAccess);
if (!file)
{
@@ -233,8 +234,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
Stream_Write_UINT32(irp->output, FileId);
Stream_Write_UINT8(irp->output, Information);
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -244,14 +244,13 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
*/
static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
{
void* key = NULL;
DRIVE_FILE* file = NULL;
if (!drive || !irp || !irp->output)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->output)
return ERROR_INVALID_PARAMETER;
file = drive_get_file_by_id(drive, irp->FileId);
key = (void*)(size_t)irp->FileId;
DRIVE_FILE* file = drive_get_file_by_id(drive, irp->FileId);
void* key = (void*)(size_t)irp->FileId;
if (!file)
irp->IoStatus = STATUS_UNSUCCESSFUL;
@@ -267,8 +266,7 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
Stream_Zero(irp->output, 5); /* Padding(5) */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -282,7 +280,9 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
UINT32 Length = 0;
UINT64 Offset = 0;
if (!drive || !irp || !irp->output)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->output)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
@@ -326,8 +326,7 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
}
}
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -341,7 +340,9 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
UINT32 Length = 0;
UINT64 Offset = 0;
if (!drive || !irp || !irp->input || !irp->output)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->input || !irp->output)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
@@ -374,8 +375,7 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
Stream_Write_UINT32(irp->output, Length);
Stream_Write_UINT8(irp->output, 0); /* Padding */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -388,8 +388,8 @@ static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
DRIVE_FILE* file = NULL;
UINT32 FsInformationClass = 0;
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
return ERROR_INVALID_DATA;
@@ -406,8 +406,7 @@ static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
irp->IoStatus = drive_map_windows_err(GetLastError());
}
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -421,7 +420,9 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
UINT32 FsInformationClass = 0;
UINT32 Length = 0;
if (!drive || !irp || !irp->input || !irp->output)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->input || !irp->output)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
@@ -443,8 +444,7 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
Stream_Write_UINT32(irp->output, Length);
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -455,17 +455,16 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
{
UINT32 FsInformationClass = 0;
wStream* output = NULL;
DWORD lpSectorsPerCluster = 0;
DWORD lpBytesPerSector = 0;
DWORD lpNumberOfFreeClusters = 0;
DWORD lpTotalNumberOfClusters = 0;
WIN32_FILE_ATTRIBUTE_DATA wfad = { 0 };
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
output = irp->output;
wStream* output = irp->output;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
return ERROR_INVALID_DATA;
@@ -590,8 +589,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP*
break;
}
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/* http://msdn.microsoft.com/en-us/library/cc241518.aspx */
@@ -601,9 +599,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP*
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
static UINT drive_process_irp_silent_ignore(WINPR_ATTR_UNUSED DRIVE_DEVICE* drive, IRP* irp)
{
if (!drive || !irp || !irp->output)
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!irp->output)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
@@ -613,8 +613,7 @@ static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
WLog_VRB(TAG, "Silently ignore FSInformationClass %s [0x%08" PRIx32 "]",
FSInformationClass2Tag(FsInformationClass), FsInformationClass);
Stream_Write_UINT32(irp->output, 0); /* Length */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -630,8 +629,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
UINT32 PathLength = 0;
UINT32 FsInformationClass = 0;
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
return ERROR_INVALID_DATA;
@@ -657,8 +656,7 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
irp->IoStatus = drive_map_windows_err(GetLastError());
}
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -668,8 +666,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
*/
static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
{
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
switch (irp->MinorFunction)
{
@@ -677,13 +675,14 @@ static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
return drive_process_irp_query_directory(drive, irp);
case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
return irp->Discard(irp);
irp->IoStatus = STATUS_NOT_SUPPORTED;
Stream_Write_UINT32(irp->output, 0); /* Length */
break;
default:
irp->IoStatus = STATUS_NOT_SUPPORTED;
Stream_Write_UINT32(irp->output, 0); /* Length */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
break;
}
return CHANNEL_RC_OK;
@@ -694,14 +693,28 @@ static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
static UINT drive_process_irp_device_control(WINPR_ATTR_UNUSED DRIVE_DEVICE* drive, IRP* irp)
{
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
static UINT drive_evaluate(UINT error, IRP* irp)
{
WINPR_ASSERT(irp);
if (error == CHANNEL_RC_OK)
{
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
}
WLog_ERR(TAG, "IRP %s failed with %" PRIu32, rdpdr_irp_string(irp->MajorFunction), error);
WINPR_ASSERT(irp->Discard);
irp->Discard(irp);
return error;
}
/**
@@ -711,10 +724,9 @@ static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
*/
static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
{
UINT error = 0;
if (!drive || !irp)
return ERROR_INVALID_PARAMETER;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(drive);
WINPR_ASSERT(irp);
irp->IoStatus = STATUS_SUCCESS;
@@ -762,12 +774,10 @@ static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
default:
irp->IoStatus = STATUS_NOT_SUPPORTED;
WINPR_ASSERT(irp->Complete);
error = irp->Complete(irp);
break;
}
return error;
return drive_evaluate(error, irp);
}
static BOOL drive_poll_run(DRIVE_DEVICE* drive, IRP* irp)

View File

@@ -119,8 +119,7 @@ static UINT parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
Stream_Write_UINT32(irp->output, parallel->id);
Stream_Write_UINT8(irp->output, 0);
free(path);
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -136,8 +135,7 @@ static UINT parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
(void)close(parallel->file);
Stream_Zero(irp->output, 5); /* Padding(5) */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -198,8 +196,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
}
free(buffer);
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -247,8 +244,7 @@ static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
Stream_Write_UINT32(irp->output, Length);
Stream_Write_UINT8(irp->output, 0); /* Padding */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -263,8 +259,7 @@ static UINT parallel_process_irp_device_control(WINPR_ATTR_UNUSED PARALLEL_DEVIC
WINPR_ASSERT(irp);
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -272,6 +267,22 @@ static UINT parallel_process_irp_device_control(WINPR_ATTR_UNUSED PARALLEL_DEVIC
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT parallel_eval(UINT error, IRP* irp)
{
WINPR_ASSERT(irp);
if (error == CHANNEL_RC_OK)
{
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
}
WLog_ERR(TAG, "IRP %s failed with %" PRIu32, rdpdr_irp_string(irp->MajorFunction), error);
WINPR_ASSERT(irp->Discard);
irp->Discard(irp);
return error;
}
static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
{
UINT error = ERROR_INTERNAL_ERROR;
@@ -303,11 +314,12 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
default:
irp->IoStatus = STATUS_NOT_SUPPORTED;
WINPR_ASSERT(irp->Complete);
error = irp->Complete(irp);
error = CHANNEL_RC_OK;
break;
}
error = parallel_eval(error, irp);
DWORD level = WLOG_TRACE;
if (error)
level = WLOG_WARN;
@@ -379,6 +391,7 @@ static UINT parallel_irp_request(DEVICE* device, IRP* irp)
if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*)irp, NULL))
{
WLog_Print(parallel->log, WLOG_ERROR, "MessageQueue_Post failed!");
irp->Discard(irp);
return ERROR_INTERNAL_ERROR;
}

View File

@@ -45,7 +45,7 @@
#include "../printer.h"
#include <freerdp/client/printer.h>
#include <freerdp/utils/rdpdr_utils.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("printer.client")
@@ -504,8 +504,7 @@ static UINT printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
}
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -536,8 +535,7 @@ static UINT printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
}
Stream_Zero(irp->output, 4); /* Padding(4) */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -589,9 +587,7 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
Stream_Write_UINT32(irp->output, Length);
Stream_Write_UINT8(irp->output, 0); /* Padding */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
/**
@@ -606,11 +602,23 @@ static UINT printer_process_irp_device_control(WINPR_ATTR_UNUSED PRINTER_DEVICE*
WINPR_ASSERT(irp);
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
return CHANNEL_RC_OK;
}
static UINT printer_evaluate(UINT error, IRP* irp)
{
WINPR_ASSERT(irp);
if (error == CHANNEL_RC_OK)
{
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
}
WLog_ERR(TAG, "IRP %s failed with %" PRIu32, rdpdr_irp_string(irp->MajorFunction), error);
WINPR_ASSERT(irp->Discard);
irp->Discard(irp);
return error;
}
/**
* Function description
*
@@ -618,7 +626,7 @@ static UINT printer_process_irp_device_control(WINPR_ATTR_UNUSED PRINTER_DEVICE*
*/
static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
{
UINT error = 0;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(printer_dev);
WINPR_ASSERT(irp);
@@ -626,49 +634,27 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
switch (irp->MajorFunction)
{
case IRP_MJ_CREATE:
if ((error = printer_process_irp_create(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_create failed with error %" PRIu32 "!", error);
return error;
}
error = printer_process_irp_create(printer_dev, irp);
break;
case IRP_MJ_CLOSE:
if ((error = printer_process_irp_close(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_close failed with error %" PRIu32 "!", error);
return error;
}
error = printer_process_irp_close(printer_dev, irp);
break;
case IRP_MJ_WRITE:
if ((error = printer_process_irp_write(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_write failed with error %" PRIu32 "!", error);
return error;
}
error = printer_process_irp_write(printer_dev, irp);
break;
case IRP_MJ_DEVICE_CONTROL:
if ((error = printer_process_irp_device_control(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_device_control failed with error %" PRIu32 "!",
error);
return error;
}
error = printer_process_irp_device_control(printer_dev, irp);
break;
default:
irp->IoStatus = STATUS_NOT_SUPPORTED;
WINPR_ASSERT(irp->Complete);
return irp->Complete(irp);
break;
}
return CHANNEL_RC_OK;
return printer_evaluate(error, irp);
}
static DWORD WINAPI printer_thread_func(LPVOID arg)

View File

@@ -61,23 +61,19 @@ static UINT irp_free(IRP* irp)
*/
static UINT irp_complete(IRP* irp)
{
size_t pos = 0;
rdpdrPlugin* rdpdr = NULL;
UINT error = 0;
WINPR_ASSERT(irp);
WINPR_ASSERT(irp->output);
WINPR_ASSERT(irp->devman);
rdpdr = (rdpdrPlugin*)irp->devman->plugin;
rdpdrPlugin* rdpdr = (rdpdrPlugin*)irp->devman->plugin;
WINPR_ASSERT(rdpdr);
pos = Stream_GetPosition(irp->output);
const size_t pos = Stream_GetPosition(irp->output);
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4);
Stream_Write_INT32(irp->output, irp->IoStatus); /* IoStatus (4 bytes) */
Stream_SetPosition(irp->output, pos);
error = rdpdr_send(rdpdr, irp->output);
const UINT error = rdpdr_send(rdpdr, irp->output);
irp->output = NULL;
irp_free(irp);
@@ -112,7 +108,7 @@ IRP* irp_new(DEVMAN* devman, wStreamPool* pool, wStream* s, wLog* log, UINT* err
return NULL;
}
irp = (IRP*)winpr_aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
irp = (IRP*)winpr_aligned_calloc(1, sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
if (!irp)
{
@@ -122,8 +118,6 @@ IRP* irp_new(DEVMAN* devman, wStreamPool* pool, wStream* s, wLog* log, UINT* err
return NULL;
}
ZeroMemory(irp, sizeof(IRP));
Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */
Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Read_UINT32(s, irp->MajorFunction); /* MajorFunction (4 bytes) */

View File

@@ -1557,13 +1557,14 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
if (irp->device->IRPRequest)
error = irp->device->IRPRequest(irp->device, irp);
else
error = irp->Discard(irp);
if (error != CHANNEL_RC_OK)
{
WLog_Print(rdpdr->log, WLOG_ERROR, "device->IRPRequest failed with error %" PRIu32 "",
error);
}
irp->Discard(irp);
return error;
}

View File

@@ -772,9 +772,6 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp)
WINPR_ASSERT(irp != NULL);
WINPR_ASSERT(serial);
if (irp == NULL)
return CHANNEL_RC_OK;
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
* allows the server to send multiple simultaneous read or
* write requests.
@@ -783,6 +780,7 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp)
if (!MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*)irp, NULL))
{
WLog_Print(serial->log, WLOG_ERROR, "MessageQueue_Post failed!");
irp->Discard(irp);
return ERROR_INTERNAL_ERROR;
}

View File

@@ -596,11 +596,15 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
if (!smartcard)
{
irp->Discard(irp);
return ERROR_INVALID_PARAMETER;
}
if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL))
{
WLog_ERR(TAG, "MessageQueue_Post failed!");
irp->Discard(irp);
return ERROR_INTERNAL_ERROR;
}