/*++ Copyright (c) 1998-2000 Microsoft Corporation Module Name: drdevol Abstract: This module contains a subclass of W32DrDev that uses overlapped IO implementations of read, write, and IOCTL handlers. Author: Tad Brockway 3/23/99 Revision History: --*/ #include #define TRC_FILE "DrDeviceOverlapped" #include "drdevol.h" #include "proc.h" #include "drdbg.h" #include "w32utl.h" #include "utl.h" #include "w32proc.h" #include "drfsfile.h" VOID W32DrDeviceOverlapped::CancelIOFunc( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params ) /*++ Routine Description: Start a Read IO operation. Arguments: params - Context for the IO request. Return Value: NA --*/ { PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL; ULONG replyPacketSize = 0; DC_BEGIN_FN("W32DrDeviceOverlapped::CancelIOFunc"); // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); // // Get the IO request. // pIoRequest = ¶ms->pIoRequestPacket->IoRequest; // // Allocate and send the reply buffer. VCMgr cleans up the // reply buffer for us. // replyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); replyPacketSize += (pIoRequest->Parameters.Read.Length - 1); pReplyPacket = DrUTL_AllocIOCompletePacket(params->pIoRequestPacket, replyPacketSize) ; if (pReplyPacket != NULL) { pReplyPacket->IoCompletion.IoStatus = STATUS_CANCELLED; ProcessObject()->GetVCMgr().ChannelWriteEx(pReplyPacket, replyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."), replyPacketSize)); } // // Clean up the IO request parameters. // if (params->overlapped.hEvent != NULL) { CloseHandle(params->overlapped.hEvent); params->overlapped.hEvent = NULL; } delete params->pIoRequestPacket; params->pIoRequestPacket = NULL; delete params; DC_END_FN(); } VOID W32DrDeviceOverlapped::_CancelIOFunc( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params ) { DC_BEGIN_FN("W32DrDeviceOverlapped::_CancelIOFunc"); // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); // Dispatch it. params->pObject->CancelIOFunc(params); DC_END_FN(); } VOID W32DrDeviceOverlapped::_CompleteIOFunc(PVOID clientData, DWORD status) /*++ Routine Description: Calls the instance-specific async IO completion function. Arguments: params - Context for the IO request. error - Status. Return Value: NA --*/ { W32DRDEV_OVERLAPPEDIO_PARAMS *params = (W32DRDEV_OVERLAPPEDIO_PARAMS *)clientData; DC_BEGIN_FN("W32DrDeviceOverlapped::_CompleteIOFunc"); ASSERT(params->magicNo == GOODMEMMAGICNUMBER); params->pObject->CompleteIOFunc(params, status); DC_END_FN(); } VOID W32DrDeviceOverlapped::MsgIrpCreate( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++ Routine Description: Handle a "Create" IO request from the server. Arguments: pIoRequestPacket - Server IO request packet. packetLen - Length of the packet Return Value: NA --*/ { ULONG ulRetCode = ERROR_SUCCESS; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; DWORD result; DWORD flags; TCHAR FileName[MAX_PATH]; TCHAR *pFileName; HANDLE FileHandle; ULONG FileId = 0; DrFile *FileObj; DWORD CreateDisposition; DWORD DesiredAccess; DWORD FileAttributes = -1; DWORD Information; BOOL IsDirectory = FALSE; DC_BEGIN_FN("W32DrDeviceOverlapped::MsgIrpCreate"); // // This version does not work without a file name. // ASSERT(_tcslen(_devicePath)); // // Get IO request pointer. // pIoRequest = &pIoRequestPacket->IoRequest; // // Get the file attributes, but make sure the overlapped bit is set. // flags = pIoRequest->Parameters.Create.FileAttributes | FILE_FLAG_OVERLAPPED; // // Disable the error box popup, e.g. There is no disk in Drive A // SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); // // Setup parameters to pass into the createfile // pFileName = ConstructFileName((PWCHAR)(pIoRequestPacket + 1), pIoRequest->Parameters.Create.PathLength); if (pFileName == NULL) { goto Cleanup; } DesiredAccess = ConstructDesiredAccess(pIoRequest->Parameters.Create.DesiredAccess); CreateDisposition = ConstructCreateDisposition(pIoRequest->Parameters.Create.Disposition); flags |= ConstructFileFlags(pIoRequest->Parameters.Create.CreateOptions); if (GetDeviceType() == RDPDR_DTYP_FILESYSTEM) { FileAttributes = GetFileAttributes(pFileName); IsDirectory = IsDirectoryFile(DesiredAccess, pIoRequest->Parameters.Create.CreateOptions, FileAttributes, &flags); } // // If we are requesting a directory and the file is not a directory // We return ERROR_DIRECTORY code back to the server // if (FileAttributes != -1 && !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && IsDirectory) { ulRetCode = ERROR_DIRECTORY; goto SendPkt; } // // Check if we are trying to create a directory // if (!((pIoRequest->Parameters.Create.CreateOptions & FILE_DIRECTORY_FILE) && CreateDisposition == CREATE_NEW)) { FileHandle = CreateFile(pFileName, DesiredAccess, pIoRequest->Parameters.Create.ShareAccess & ~(FILE_SHARE_DELETE), NULL, CreateDisposition, flags, NULL ); if (FileHandle != INVALID_HANDLE_VALUE || IsDirectory) { // // We either get a valid file handle or this is a directory // and we are trying to query directory information, so // we will just by pass the create file // FileId = _FileMgr->GetUniqueObjectID(); // // Create the file object // if (GetDeviceType() == RDPDR_DTYP_FILESYSTEM) { FileObj = new DrFSFile(this, FileId, FileHandle, IsDirectory, pFileName); } else { FileObj = new DrFile(this, FileId, FileHandle); } if (FileObj) { // // give subclass object a change to initialize. // if( ERROR_SUCCESS != InitializeDevice( FileObj ) ) { TRC_ERR((TB, _T("Failed to initialize device"))); delete FileObj; goto Cleanup; } if (_FileMgr->AddObject(FileObj) != ERROR_NOT_ENOUGH_MEMORY) { FileObj->AddRef(); } else { TRC_ERR((TB, _T("Failed to add File Object"))); delete FileObj; goto Cleanup; } } else { TRC_ERR((TB, _T("Failed to alloc File Object"))); goto Cleanup; } } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("CreateFile failed, %ld."), ulRetCode)); } } else { if (CreateDirectory(pFileName, NULL)) { // // Set the attributes on the directory // if (SetFileAttributes(pFileName, pIoRequest->Parameters.Create.FileAttributes)) { // // Create a new directory // FileId = _FileMgr->GetUniqueObjectID(); IsDirectory = TRUE; FileObj = new DrFSFile(this, FileId, INVALID_HANDLE_VALUE, IsDirectory, pFileName); if (FileObj) { if (_FileMgr->AddObject(FileObj) != ERROR_NOT_ENOUGH_MEMORY) { FileObj->AddRef(); } else { TRC_ERR((TB, _T("Failed to add File Object"))); delete FileObj; goto Cleanup; } } else { TRC_ERR((TB, _T("Failed to alloc File Object"))); goto Cleanup; } } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetFileAttribute for CreateDirectory failed, %ld."), ulRetCode)); } } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("CreateDirectory failed, %ld."), ulRetCode)); } } SendPkt: // // Setup return information. // if (CreateDisposition == CREATE_ALWAYS) Information = FILE_OVERWRITTEN; else if (CreateDisposition == OPEN_ALWAYS) Information = FILE_OPENED; // // Allocate reply buffer. // ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize); if (pReplyPacket) { // // Setup File Id for create IRP // pReplyPacket->IoCompletion.Parameters.Create.FileId = (UINT32) FileId; pReplyPacket->IoCompletion.Parameters.Create.Information = (UCHAR)Information; // // Send the result to the server. // result = TranslateWinError(ulRetCode); pReplyPacket->IoCompletion.IoStatus = result; ProcessObject()->GetVCMgr().ChannelWriteEx( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."), ulReplyPacketSize)); } Cleanup: // // Clean up the request packet and file name. // if (pFileName != NULL && pIoRequest->Parameters.Create.PathLength != 0) { delete pFileName; } delete pIoRequestPacket; DC_END_FN(); } VOID W32DrDeviceOverlapped::MsgIrpReadWrite( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++ Routine Description: Handles Read and Write IO requests. Arguments: pIoRequestPacket - Server IO request packet. packetLen - Length of the packet Return Value: NA --*/ { W32DRDEV_OVERLAPPEDIO_PARAMS *params; DWORD result; DC_BEGIN_FN("W32DrDeviceOverlapped::MsgIrpReadWrite"); TRC_NRM((TB, _T("Request to write %d bytes"), pIoRequestPacket->IoRequest.Parameters.Write.Length)); // // Allocate and dispatch an asynchronous IO request. // params = new W32DRDEV_OVERLAPPEDIO_PARAMS(this, pIoRequestPacket); if (params != NULL ) { TRC_NRM((TB, _T("Async IO operation"))); result = ProcessObject()->DispatchAsyncIORequest( (RDPAsyncFunc_StartIO) W32DrDeviceOverlapped::_StartIOFunc, (RDPAsyncFunc_IOComplete) W32DrDeviceOverlapped::_CompleteIOFunc, (RDPAsyncFunc_IOCancel) W32DrDeviceOverlapped::_CancelIOFunc, params ); } else { TRC_ERR((TB, _T("Memory alloc failed."))); result = ERROR_NOT_ENOUGH_MEMORY; } // // Clean up on error. // if (result != ERROR_SUCCESS) { if (params != NULL) { delete params; } delete pIoRequestPacket; // How can I return an error the server if I cannot allocate // the return buffer. This needs to be fixed. Otherwise, the server will // just hang on to an IO request that never completes. } DC_END_FN(); } HANDLE W32DrDeviceOverlapped::StartReadIO( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params, OUT DWORD *status ) /*++ Routine Description: Start an overlapped Read IO operation. Arguments: params - Context for the IO request. status - Return status for IO request in the form of a windows error code. Return Value: Returns a handle the pending IO object if the operation did not complete. Otherwise, NULL is returned. --*/ { PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL; PRDPDR_DEVICE_IOREQUEST pIoRequest; ULONG replyPacketSize = 0; DrFile *pFile; HANDLE FileHandle; DC_BEGIN_FN("W32DrDeviceOverlapped::StartReadIO"); // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); *status = ERROR_SUCCESS; // // Get the IO request. // pIoRequest = ¶ms->pIoRequestPacket->IoRequest; // // Get File object and File handle // pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE; // // Allocate reply buffer. // replyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); replyPacketSize += (pIoRequest->Parameters.Read.Length - 1); pReplyPacket = DrUTL_AllocIOCompletePacket(params->pIoRequestPacket, replyPacketSize) ; if (pReplyPacket == NULL) { *status = ERROR_NOT_ENOUGH_MEMORY; TRC_ERR((TB, _T("Failed to alloc %ld bytes."), replyPacketSize)); goto Cleanup; } // // Save the reply packet info to the context for this IO operation. // params->pIoReplyPacket = pReplyPacket; params->IoReplyPacketSize = replyPacketSize; // // Create an event for the overlapped IO. // memset(¶ms->overlapped, 0, sizeof(params->overlapped)); params->overlapped.hEvent = CreateEvent( NULL, // no attribute. TRUE, // manual reset. FALSE, // initially not signalled. NULL // no name. ); if (params->overlapped.hEvent == NULL) { TRC_ERR((TB, _T("Failed to create event"))); *status = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // Use ReadFile to execute the read. // // // Set the file pointer position if this is a seekable device // if (IsSeekableDevice()) { DWORD dwPtr; // // The offset is from FILE_BEGIN // dwPtr = SetFilePointer(FileHandle, pIoRequest->Parameters.Read.OffsetLow, &(pIoRequest->Parameters.Read.OffsetHigh), FILE_BEGIN); if (dwPtr == INVALID_SET_FILE_POINTER) { *status = GetLastError(); if (*status != NO_ERROR) { pReplyPacket->IoCompletion.Parameters.Read.Length = 0; TRC_ERR((TB, _T("Error SetFilePointer %x."), *status)); goto Cleanup; } } } if (!ReadFile( FileHandle, pReplyPacket->IoCompletion.Parameters.Read.Buffer, pIoRequest->Parameters.Read.Length, &(pReplyPacket->IoCompletion.Parameters.Read.Length), ¶ms->overlapped)) { // // If IO is pending. // *status = GetLastError(); if (*status == ERROR_IO_PENDING) { TRC_NRM((TB, _T("Pending read IO."))); } else { TRC_ERR((TB, _T("Error %x."), *status)); goto Cleanup; } } else { TRC_NRM((TB, _T("Read completed synchronously."))); *status = ERROR_SUCCESS; } Cleanup: // // If IO is pending, return the handle to the pending IO. // if (*status == ERROR_IO_PENDING) { DC_END_FN(); return params->overlapped.hEvent; } // // Otherwise, clean up the event handle and return NULL so that the // CompleteIOFunc can be called to send the results to the server. // else { CloseHandle(params->overlapped.hEvent); params->overlapped.hEvent = NULL; DC_END_FN(); return NULL; } } HANDLE W32DrDeviceOverlapped::StartWriteIO( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params, OUT DWORD *status ) /*++ Routine Description: Start an overlapped Write IO operation. Arguments: params - Context for the IO request. status - Return status for IO request in the form of a windows error code. Return Value: Returns a handle the pending IO object if the operation did not complete. Otherwise, NULL is returned. --*/ { PBYTE pDataBuffer; PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL; PRDPDR_DEVICE_IOREQUEST pIoRequest; ULONG replyPacketSize = 0; DrFile *pFile; HANDLE FileHandle; DC_BEGIN_FN("W32DrDeviceOverlapped::StartWriteIO"); *status = ERROR_SUCCESS; // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); // // Get the IO request. // pIoRequest = ¶ms->pIoRequestPacket->IoRequest; // // Get File object and File handle // pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE; // // Allocate reply buffer. // replyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); pReplyPacket = DrUTL_AllocIOCompletePacket(params->pIoRequestPacket, replyPacketSize) ; if (pReplyPacket == NULL) { *status = ERROR_NOT_ENOUGH_MEMORY; TRC_ERR((TB, _T("Failed to alloc %ld bytes."), replyPacketSize)); goto Cleanup; } // // Save the reply packet info to the context for this IO operation. // params->pIoReplyPacket = pReplyPacket; params->IoReplyPacketSize = replyPacketSize; // // Create an event for the overlapped IO. // memset(¶ms->overlapped, 0, sizeof(params->overlapped)); params->overlapped.hEvent = CreateEvent( NULL, // no attribute. TRUE, // manual reset. FALSE, // initially not signalled. NULL // no name. ); if (params->overlapped.hEvent == NULL) { TRC_ERR((TB, _T("Failed to create event"))); *status = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // Get the data buffer pointer. // pDataBuffer = (PBYTE)(pIoRequest + 1); // // Use WriteFile to execute the write operation. // ASSERT(FileHandle != INVALID_HANDLE_VALUE); // // Set the file pointer position if this is a seekable device // if (IsSeekableDevice()) { DWORD dwPtr; // // The offset is from FILE_BEGIN // dwPtr = SetFilePointer(FileHandle, pIoRequest->Parameters.Write.OffsetLow, &(pIoRequest->Parameters.Write.OffsetHigh), FILE_BEGIN); if (dwPtr == INVALID_SET_FILE_POINTER) { *status = GetLastError(); if (*status != NO_ERROR) { pReplyPacket->IoCompletion.Parameters.Write.Length = 0; TRC_ERR((TB, _T("Error SetFilePointer %x."), *status)); goto Cleanup; } } } if (!WriteFile( FileHandle, pDataBuffer, pIoRequest->Parameters.Write.Length, &(pReplyPacket->IoCompletion.Parameters.Write.Length), ¶ms->overlapped)) { // // If IO is pending. // *status = GetLastError(); if (*status == ERROR_IO_PENDING) { TRC_NRM((TB, _T("Pending IO."))); } else { TRC_NRM((TB, _T("Error %x."), *status)); goto Cleanup; } } else { TRC_NRM((TB, _T("Read completed synchronously."))); *status = ERROR_SUCCESS; } Cleanup: // // If IO is pending, return the handle to the pending IO. // if (*status == ERROR_IO_PENDING) { DC_END_FN(); return params->overlapped.hEvent; } // // Otherwise, clean up the event handle and return NULL so that the // CompleteIOFunc can be called to send the results to the server. // else { CloseHandle(params->overlapped.hEvent); params->overlapped.hEvent = NULL; DC_END_FN(); return NULL; } } HANDLE W32DrDeviceOverlapped::StartIOCTL( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params, OUT DWORD *status ) /*++ Routine Description: Start a generic overlapped IOCTL operation. Arguments: params - Context for the IO request. status - Return status for IO request in the form of a windows error code. Return Value: Returns a handle the pending IO object if the operation did not complete. Otherwise, NULL is returned. --*/ { PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL; PRDPDR_DEVICE_IOREQUEST pIoRequest; ULONG replyPacketSize = 0; DrFile *pFile; HANDLE FileHandle; PVOID pInputBuffer = NULL; PVOID pOutputBuffer = NULL; DC_BEGIN_FN("W32DrDeviceOverlapped::StartIOCTL"); *status = ERROR_SUCCESS; // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); // // Get the IO request. // pIoRequest = ¶ms->pIoRequestPacket->IoRequest; // // Get File object and File handle // pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE; // // Allocate reply buffer. // replyPacketSize = DR_IOCTL_REPLYBUFSIZE(pIoRequest); pReplyPacket = DrUTL_AllocIOCompletePacket(params->pIoRequestPacket, replyPacketSize) ; if (pReplyPacket == NULL) { *status = ERROR_NOT_ENOUGH_MEMORY; TRC_ERR((TB, _T("Failed to alloc %ld bytes."), replyPacketSize)); goto Cleanup; } if (pIoRequest->Parameters.DeviceIoControl.InputBufferLength) { pInputBuffer = pIoRequest + 1; } if (pIoRequest->Parameters.DeviceIoControl.OutputBufferLength) { pOutputBuffer = pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBuffer; } // // Save the reply packet info to the context for this IO operation. // params->pIoReplyPacket = pReplyPacket; params->IoReplyPacketSize = replyPacketSize; // // Create an event for the overlapped IO. // memset(¶ms->overlapped, 0, sizeof(params->overlapped)); params->overlapped.hEvent = CreateEvent( NULL, // no attribute. TRUE, // manual reset. FALSE, // initially not signalled. NULL // no name. ); if (params->overlapped.hEvent == NULL) { TRC_NRM((TB, _T("Failed to create event"))); *status = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // Use DeviceIoControl to execute the IO request. // if (FileHandle != INVALID_HANDLE_VALUE) { if (!DeviceIoControl(FileHandle, pIoRequest->Parameters.DeviceIoControl.IoControlCode, pInputBuffer, pIoRequest->Parameters.DeviceIoControl.InputBufferLength, pOutputBuffer, pIoRequest->Parameters.DeviceIoControl.OutputBufferLength, &(pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength), ¶ms->overlapped)) { // // If IO is pending. // *status = GetLastError(); if (*status == ERROR_IO_PENDING) { TRC_NRM((TB, _T("Pending IO."))); } else { TRC_NRM((TB, _T("Error %ld."), *status)); goto Cleanup; } } else { *status = ERROR_SUCCESS; } } else { TRC_NRM((TB, _T("IOCTL completed unsuccessfully."))); pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength = 0; *status = ERROR_INVALID_FUNCTION; } Cleanup: // // If IO is pending, return the handle to the pending IO. // if (*status == ERROR_IO_PENDING) { DC_END_FN(); return params->overlapped.hEvent; } // // Otherwise, return NULL so that the CompleteIOFunc can be called // to send the results to the server. // else { DC_END_FN(); if (params->overlapped.hEvent) { CloseHandle(params->overlapped.hEvent); params->overlapped.hEvent = NULL; } return NULL; } } VOID W32DrDeviceOverlapped::CompleteIOFunc( IN W32DRDEV_OVERLAPPEDIO_PARAMS *params, IN DWORD status ) /*++ Routine Description: Complete an async IO operation. Arguments: params - Context for the IO request. error - Status. Return Value: NA --*/ { ULONG replyPacketSize; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; PRDPDR_IOREQUEST_PACKET pIoRequestPacket; PRDPDR_DEVICE_IOREQUEST pIoRequest; DrFile *pFile; HANDLE FileHandle; DWORD Temp; DC_BEGIN_FN("W32DrDeviceOverlapped::CompleteIOFunc"); // // Simplify the params. // replyPacketSize = params->IoReplyPacketSize; pReplyPacket = params->pIoReplyPacket; pIoRequestPacket = params->pIoRequestPacket; pIoRequest = &pIoRequestPacket->IoRequest; if (pReplyPacket != NULL) { // // Get File object and File handle // pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE; // // If the operation had been pending, then we need to get // the overlapped results. // if (params->overlapped.hEvent != NULL) { LPDWORD bytesTransferred = NULL; ULONG irpMajor; irpMajor = pIoRequestPacket->IoRequest.MajorFunction; if (irpMajor == IRP_MJ_READ) { bytesTransferred = &pReplyPacket->IoCompletion.Parameters.Read.Length; } else if (irpMajor == IRP_MJ_WRITE) { bytesTransferred = &pReplyPacket->IoCompletion.Parameters.Write.Length; } else if (irpMajor == IRP_MJ_DEVICE_CONTROL) { bytesTransferred = &pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength; // IOCTL_SERIAL_WAIT_ON_MASK corresponds to WatiCommEvent(), for this call // *bytesTransferred returned from GetOverlappedResult() is undefined, // so we manually set OutputBufferLength to sizeof(DWORD) here if (params->pIoRequestPacket->IoRequest.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength = sizeof(DWORD); bytesTransferred = &Temp; } } else { ASSERT(FALSE); } if (!GetOverlappedResult( FileHandle, ¶ms->overlapped, bytesTransferred, TRUE // wait )) { status = GetLastError(); TRC_ERR((TB, _T("GetOverlappedResult %ld."), status)); } CloseHandle(params->overlapped.hEvent); params->overlapped.hEvent = NULL; } if (pIoRequestPacket->IoRequest.MajorFunction == IRP_MJ_READ) { // // Make sure the reply is the minimum size required // replyPacketSize = (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET, IoCompletion.Parameters.Read.Buffer) + pReplyPacket->IoCompletion.Parameters.Read.Length; TRC_NRM((TB, _T("Read %d bytes"), pReplyPacket->IoCompletion.Parameters.Read.Length)); } else if (pIoRequestPacket->IoRequest.MajorFunction == IRP_MJ_DEVICE_CONTROL) { // // Make sure the reply is the minimum size required // replyPacketSize = (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET, IoCompletion.Parameters.DeviceIoControl.OutputBuffer) + pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength; TRC_NRM((TB, _T("DeviceIoControl %d bytes"), pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength)); } // // Finish the response and send it. // TRC_NRM((TB, _T("replyPacketSize %ld."), replyPacketSize)); pReplyPacket->IoCompletion.IoStatus = TranslateWinError(status); ProcessObject()->GetVCMgr().ChannelWriteEx(pReplyPacket, replyPacketSize); } else { // // We previously failed allocating reply packet, try again // DefaultIORequestMsgHandle(pIoRequestPacket, ERROR_NOT_ENOUGH_MEMORY); params->pIoRequestPacket = NULL; } // // ChannelWrite releases the reply packet for us. // params->pIoReplyPacket = NULL; params->IoReplyPacketSize = 0; // // Clean up the rest of the request packet and IO parms. // if (params->pIoRequestPacket != NULL) { delete params->pIoRequestPacket; params->pIoRequestPacket = NULL; } DC_END_FN(); delete params; } VOID W32DrDeviceOverlapped::DispatchIOCTLDirectlyToDriver( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket ) /*++ Routine Description: Dispatch an IOCTL directly to the device driver. This will likely not work for platforms that don't match the server platform. Arguments: pIoRequestPacket - Request packet received from server. Return Value: The size (in bytes) of a device announce packet for this device. --*/ { W32DRDEV_OVERLAPPEDIO_PARAMS *params; DWORD result; DC_BEGIN_FN("W32DrDeviceOverlapped::DispatchIOCTLDirectlyToDriver"); // // Allocate and dispatch an asynchronous IO request. // params = new W32DRDEV_OVERLAPPEDIO_PARAMS(this, pIoRequestPacket); if (params != NULL ) { result = ProcessObject()->DispatchAsyncIORequest( (RDPAsyncFunc_StartIO) W32DrDeviceOverlapped::_StartIOFunc, (RDPAsyncFunc_IOComplete) W32DrDeviceOverlapped::_CompleteIOFunc, (RDPAsyncFunc_IOCancel) W32DrDeviceOverlapped::_CancelIOFunc, params ); } else { TRC_ERR((TB, _T("Memory alloc failed."))); result = ERROR_NOT_ENOUGH_MEMORY; } // // Clean up on error. // if (result != ERROR_SUCCESS) { if (params != NULL) { delete params; } delete pIoRequestPacket; // How can I return an error the server if I cannot allocate // the return buffer. This needs to be fixed. Otherwise, the server will // just hang on to an IO request that never completes. } DC_END_FN(); } HANDLE W32DrDeviceOverlapped::_StartIOFunc( IN PVOID clientData, OUT DWORD *status ) /*++ Routine Description: Dispatch an IO operation start to the right instance of this class. Arguments: clientData - Context for the IO request. status - Return status for IO request in the form of a windows error code. Return Value: NA --*/ { PRDPDR_DEVICE_IOREQUEST pIoRequest; W32DRDEV_OVERLAPPEDIO_PARAMS *params = (W32DRDEV_OVERLAPPEDIO_PARAMS *)clientData; DC_BEGIN_FN("W32DrDeviceOverlapped::_StartIOFunc"); // Assert the integrity of the IO context ASSERT(params->magicNo == GOODMEMMAGICNUMBER); // // Get the IO request. // pIoRequest = ¶ms->pIoRequestPacket->IoRequest; // // Dispatch it. // DC_END_FN(); switch(pIoRequest->MajorFunction) { ASSERT(params->pObject != NULL); case IRP_MJ_READ: return params->pObject->StartReadIO(params, status); case IRP_MJ_WRITE: return params->pObject->StartWriteIO(params, status); case IRP_MJ_DEVICE_CONTROL: return params->pObject->StartIOCTL(params, status); default: ASSERT(FALSE); return NULL; } }