You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1261 lines
34 KiB
1261 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
drdevasc
|
|
|
|
Abstract:
|
|
|
|
This module contains an (async) subclass of W32DrDev that uses a
|
|
thread pool for implementations of read, write, and IOCTL handlers.
|
|
|
|
Author:
|
|
|
|
Tad Brockway 3/23/99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precom.h>
|
|
|
|
#define TRC_FILE "DrDeviceAsync"
|
|
|
|
#include "drdevasc.h"
|
|
#include "proc.h"
|
|
#include "drdbg.h"
|
|
#include "w32utl.h"
|
|
#include "utl.h"
|
|
#include "w32proc.h"
|
|
#include "drfsfile.h"
|
|
|
|
#ifdef OS_WINCE
|
|
#include "filemgr.h"
|
|
#include "wceinc.h"
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// W32DrDeviceAsync Members
|
|
//
|
|
|
|
W32DrDeviceAsync::W32DrDeviceAsync(
|
|
ProcObj *processObject, ULONG deviceID,
|
|
const TCHAR *devicePath
|
|
) :
|
|
W32DrDevice(processObject, deviceID, devicePath)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
processObject - Related process object.
|
|
deviceID - Associated device ID
|
|
devicePath - Associated device path for device.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Get a pointer to the thread pool object.
|
|
//
|
|
_threadPool = &(((W32ProcObj *)processObject)->GetThreadPool());
|
|
}
|
|
|
|
HANDLE
|
|
W32DrDeviceAsync::StartIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params,
|
|
OUT DWORD *status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start a generic asynchronous 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 to an object that will be signalled when the read
|
|
completes, if it is not completed in this function. Otherwise, NULL
|
|
is returned.
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL;
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
ULONG replyPacketSize = 0;
|
|
ULONG irpMajor;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::StartAsyncIO");
|
|
|
|
*status = ERROR_SUCCESS;
|
|
|
|
// Assert the integrity of the IO context
|
|
ASSERT(params->magicNo == GOODMEMMAGICNUMBER);
|
|
|
|
//
|
|
// Get the IO request and the IPR major.
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
|
|
irpMajor = pIoRequest->MajorFunction;
|
|
|
|
//
|
|
// Allocate reply buffer.
|
|
//
|
|
if (irpMajor == IRP_MJ_DEVICE_CONTROL) {
|
|
replyPacketSize = DR_IOCTL_REPLYBUFSIZE(pIoRequest);
|
|
}
|
|
else {
|
|
replyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET);
|
|
if (irpMajor == IRP_MJ_READ) {
|
|
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;
|
|
|
|
//
|
|
// Hand the request off to the thread pool.
|
|
//
|
|
params->completionEvent = CreateEvent(
|
|
NULL, // no attribute.
|
|
TRUE, // manual reset.
|
|
FALSE, // initially not signalled.
|
|
NULL // no name.
|
|
);
|
|
if (params->completionEvent == NULL) {
|
|
*status = GetLastError();
|
|
TRC_ERR((TB, _T("Error in CreateEvent: %08X."), *status));
|
|
}
|
|
else {
|
|
|
|
switch (irpMajor)
|
|
{
|
|
case IRP_MJ_WRITE:
|
|
params->thrPoolReq = _threadPool->SubmitRequest(
|
|
_AsyncWriteIOFunc,
|
|
params, params->completionEvent
|
|
); break;
|
|
case IRP_MJ_READ:
|
|
params->thrPoolReq = _threadPool->SubmitRequest(
|
|
_AsyncReadIOFunc,
|
|
params, params->completionEvent
|
|
); break;
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
params->thrPoolReq = _threadPool->SubmitRequest(
|
|
_AsyncIOCTLFunc,
|
|
params, params->completionEvent
|
|
); break;
|
|
}
|
|
|
|
if (params->thrPoolReq == INVALID_THREADPOOLREQUEST) {
|
|
*status = ERROR_SERVICE_NO_THREAD;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// If IO is pending, return the handle to the pending IO.
|
|
//
|
|
if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
|
|
*status = ERROR_IO_PENDING;
|
|
DC_END_FN();
|
|
return params->completionEvent;
|
|
}
|
|
//
|
|
// Otherwise, clean up the event handle and return NULL so that the
|
|
// CompleteIOFunc can be called to send the results to the server.
|
|
//
|
|
else {
|
|
|
|
if (params->completionEvent != NULL) {
|
|
CloseHandle(params->completionEvent);
|
|
params->completionEvent = NULL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
HANDLE
|
|
W32DrDeviceAsync::_StartIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params,
|
|
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
|
|
|
|
--*/
|
|
{
|
|
return params->pObject->StartIOFunc(params, status);
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::CompleteIOFunc(
|
|
IN W32DRDEV_ASYNCIO_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;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::CompleteAsyncIOFunc");
|
|
|
|
//
|
|
// Simplify the params.
|
|
//
|
|
replyPacketSize = params->IoReplyPacketSize;
|
|
pReplyPacket = params->pIoReplyPacket;
|
|
pIoRequestPacket = params->pIoRequestPacket;
|
|
|
|
//
|
|
// If the operation had been pending, then we need to get the async
|
|
// results.
|
|
//
|
|
if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
|
|
status = _threadPool->GetRequestCompletionStatus(params->thrPoolReq);
|
|
}
|
|
|
|
if (pReplyPacket != 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. The VC manager releases the reply
|
|
// packet on failure and on success.
|
|
//
|
|
TRC_NRM((TB, _T("replyPacketSize %ld."), replyPacketSize));
|
|
pReplyPacket->IoCompletion.IoStatus = TranslateWinError(status);
|
|
ProcessObject()->GetVCMgr().ChannelWriteEx(
|
|
pReplyPacket,
|
|
replyPacketSize
|
|
);
|
|
}
|
|
else {
|
|
DefaultIORequestMsgHandle(pIoRequestPacket, TranslateWinError(status));
|
|
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->thrPoolReq != INVALID_THREADPOOLREQUEST) {
|
|
_threadPool->CloseRequest(params->thrPoolReq);
|
|
params->thrPoolReq = INVALID_THREADPOOLREQUEST;
|
|
}
|
|
if (params->completionEvent != NULL) {
|
|
CloseHandle(params->completionEvent);
|
|
params->completionEvent = NULL;
|
|
}
|
|
|
|
if (params->pIoRequestPacket != NULL) {
|
|
delete params->pIoRequestPacket;
|
|
params->pIoRequestPacket = NULL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
delete params;
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::_CompleteIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params,
|
|
IN DWORD status
|
|
)
|
|
{
|
|
params->pObject->CompleteIOFunc(params, status);
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::AsyncIOCTLFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchrous IOCTL Function
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
Always returns 0.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
PRDPDR_IOCOMPLETION_PACKET pReplyPacket;
|
|
DrFile* pFile;
|
|
HANDLE FileHandle;
|
|
PVOID pInputBuffer = NULL;
|
|
PVOID pOutputBuffer = NULL;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::AsyncIOCTLFunc");
|
|
|
|
//
|
|
// Use DeviceIoControl to execute the IO request.
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
pReplyPacket = params->pIoReplyPacket;
|
|
|
|
if (pIoRequest->Parameters.DeviceIoControl.InputBufferLength) {
|
|
pInputBuffer = pIoRequest + 1;
|
|
}
|
|
|
|
if (pIoRequest->Parameters.DeviceIoControl.OutputBufferLength) {
|
|
pOutputBuffer = pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBuffer;
|
|
}
|
|
|
|
//
|
|
// Get File Object
|
|
//
|
|
pFile = _FileMgr->GetObject(pIoRequest->FileId);
|
|
|
|
if (pFile)
|
|
FileHandle = pFile->GetFileHandle();
|
|
else
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
if (FileHandle != INVALID_HANDLE_VALUE) {
|
|
#ifndef OS_WINCE
|
|
if (!DeviceIoControl(FileHandle,
|
|
#else
|
|
if (!CEDeviceIoControl(FileHandle,
|
|
#endif
|
|
pIoRequest->Parameters.DeviceIoControl.IoControlCode,
|
|
pInputBuffer,
|
|
pIoRequest->Parameters.DeviceIoControl.InputBufferLength,
|
|
pOutputBuffer,
|
|
pIoRequest->Parameters.DeviceIoControl.OutputBufferLength,
|
|
&(pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength),
|
|
NULL)) {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("IOCTL Error %ld."), status));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("IOCTL completed successfully.")));
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("IOCTL completed unsuccessfully.")));
|
|
pReplyPacket->IoCompletion.Parameters.DeviceIoControl.OutputBufferLength = 0;
|
|
status = ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::_AsyncIOCTLFunc(
|
|
IN PVOID params,
|
|
IN HANDLE cancelEvent
|
|
)
|
|
{
|
|
return ((W32DRDEV_ASYNCIO_PARAMS *)params)->pObject->AsyncIOCTLFunc(
|
|
(W32DRDEV_ASYNCIO_PARAMS *)params);
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::AsyncReadIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchrous IO Read Function
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
Always returns 0.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
DrFile* pFile;
|
|
HANDLE FileHandle;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::AsyncReadIOFunc");
|
|
|
|
//
|
|
// Get File Object
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
|
|
pFile = _FileMgr->GetObject(pIoRequest->FileId);
|
|
if (pFile)
|
|
FileHandle = pFile->GetFileHandle();
|
|
else
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// Use ReadFile to execute the read.
|
|
//
|
|
|
|
//
|
|
// Set the file pointer position if this is a seekable device
|
|
//
|
|
if (IsSeekableDevice()) {
|
|
DWORD dwPtr;
|
|
|
|
//
|
|
// The offset we get is from FILE_BEGIN
|
|
//
|
|
#ifndef OS_WINCE
|
|
dwPtr = SetFilePointer(FileHandle,
|
|
#else
|
|
dwPtr = CESetFilePointer(FileHandle,
|
|
#endif
|
|
pIoRequest->Parameters.Read.OffsetLow,
|
|
&(pIoRequest->Parameters.Read.OffsetHigh),
|
|
FILE_BEGIN);
|
|
|
|
if (dwPtr == INVALID_SET_FILE_POINTER) {
|
|
status = GetLastError();
|
|
|
|
if (status != NO_ERROR) {
|
|
params->pIoReplyPacket->IoCompletion.Parameters.Read.Length = 0;
|
|
TRC_ERR((TB, _T("Error SetFilePointer %ld."), status));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
if (!ReadFile(
|
|
#else
|
|
if (!CEReadFile(
|
|
#endif
|
|
FileHandle,
|
|
params->pIoReplyPacket->IoCompletion.Parameters.Read.Buffer,
|
|
params->pIoRequestPacket->IoRequest.Parameters.Read.Length,
|
|
&(params->pIoReplyPacket->IoCompletion.Parameters.Read.Length),
|
|
NULL)) {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("Error %ld."), status));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Read completed synchronously.")));
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::_AsyncReadIOFunc(
|
|
IN PVOID params,
|
|
IN HANDLE cancelEvent
|
|
)
|
|
{
|
|
return ((W32DRDEV_ASYNCIO_PARAMS *)params)->pObject->AsyncReadIOFunc(
|
|
(W32DRDEV_ASYNCIO_PARAMS *)params);
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::AsyncWriteIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchrous IO Write Function
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
Always returns 0.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrDeviceAsync::AsyncWriteIOFunc");
|
|
|
|
PBYTE pDataBuffer;
|
|
DWORD status;
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
DrFile* pFile;
|
|
HANDLE FileHandle;
|
|
|
|
//
|
|
// Get the data buffer pointer.
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
pDataBuffer = (PBYTE)(pIoRequest + 1);
|
|
|
|
//
|
|
// Get File Object
|
|
//
|
|
pFile = _FileMgr->GetObject(pIoRequest->FileId);
|
|
if (pFile)
|
|
FileHandle = pFile->GetFileHandle();
|
|
else
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// 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 we get is from FILE_BEGIN
|
|
//
|
|
#ifndef OS_WINCE
|
|
dwPtr = SetFilePointer(FileHandle,
|
|
#else
|
|
dwPtr = CESetFilePointer(FileHandle,
|
|
#endif
|
|
pIoRequest->Parameters.Write.OffsetLow,
|
|
&(pIoRequest->Parameters.Write.OffsetHigh),
|
|
FILE_BEGIN);
|
|
|
|
if (dwPtr == INVALID_SET_FILE_POINTER) {
|
|
status = GetLastError();
|
|
|
|
if (status != NO_ERROR) {
|
|
params->pIoReplyPacket->IoCompletion.Parameters.Write.Length = 0;
|
|
TRC_ERR((TB, _T("Error SetFilePointer %ld."), status));
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
if (!WriteFile(
|
|
#else
|
|
if (!CEWriteFile(
|
|
#endif
|
|
FileHandle,
|
|
pDataBuffer,
|
|
pIoRequest->Parameters.Write.Length,
|
|
&(params->pIoReplyPacket->IoCompletion.Parameters.Write.Length),
|
|
NULL)) {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("Error %ld."), status));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Read completed synchronously.")));
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::_AsyncWriteIOFunc(
|
|
IN PVOID params,
|
|
IN HANDLE cancelEvent
|
|
)
|
|
{
|
|
|
|
return ((W32DRDEV_ASYNCIO_PARAMS *)params)->pObject->AsyncWriteIOFunc(
|
|
(W32DRDEV_ASYNCIO_PARAMS *)params);
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::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_ASYNCIO_PARAMS *params;
|
|
DWORD result;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::DispatchIOCTLDirectlyToDriver");
|
|
|
|
//
|
|
// Allocate and dispatch an asynchronous IO request.
|
|
//
|
|
params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket);
|
|
if (params != NULL ) {
|
|
result = ProcessObject()->DispatchAsyncIORequest(
|
|
(RDPAsyncFunc_StartIO)
|
|
W32DrDeviceAsync::_StartIOFunc,
|
|
(RDPAsyncFunc_IOComplete)
|
|
W32DrDeviceAsync::_CompleteIOFunc,
|
|
(RDPAsyncFunc_IOCancel)
|
|
W32DrDeviceAsync::_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();
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::MsgIrpCreate(
|
|
IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
IN UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Create" IO request from the server by saving the results
|
|
of CreateFile against our device path in our file handle.
|
|
|
|
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 *pFileName = NULL;
|
|
HANDLE FileHandle;
|
|
ULONG Information = 0;
|
|
ULONG FileId = 0;
|
|
DrFile *FileObj;
|
|
DWORD CreateDisposition;
|
|
DWORD DesiredAccess;
|
|
DWORD FileAttributes = -1;
|
|
BOOL IsDirectory = FALSE;
|
|
BOOL fSetFileIsADirectoryFlag = FALSE;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::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 not set.
|
|
//
|
|
flags = pIoRequest->Parameters.Create.FileAttributes & ~(FILE_FLAG_OVERLAPPED);
|
|
|
|
//
|
|
// Disable the error box popup, e.g. There is no disk in Drive A
|
|
//
|
|
#ifndef OS_WINCE
|
|
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
#endif
|
|
//
|
|
// Make sure the packet length is right
|
|
//
|
|
if (packetLen < sizeof(RDPDR_IOREQUEST_PACKET) + pIoRequest->Parameters.Create.PathLength) {
|
|
// Call VirtualChannelClose
|
|
ProcessObject()->GetVCMgr().ChannelClose();
|
|
TRC_ASSERT(FALSE, (TB, _T("Packet Length Error")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// 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)) {
|
|
|
|
#ifndef OS_WINCE
|
|
FileHandle = CreateFile(pFileName, DesiredAccess,
|
|
#else
|
|
FileHandle = CECreateFile(pFileName, DesiredAccess,
|
|
#endif
|
|
pIoRequest->Parameters.Create.ShareAccess & ~(FILE_SHARE_DELETE),
|
|
NULL,
|
|
CreateDisposition,
|
|
flags,
|
|
NULL
|
|
);
|
|
|
|
TRC_ALT((TB, _T("CreateFile returned 0x%08x : pFileName=%s, DesiredAccess=0x%x, ShareMode=0x%x, CreateDisposition=0x%x, flags=0x%x, LastErr=0x%x."),
|
|
FileHandle, pFileName, DesiredAccess, pIoRequest->Parameters.Create.ShareAccess & ~(FILE_SHARE_DELETE), CreateDisposition, flags, ulRetCode));
|
|
|
|
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();
|
|
if (ulRetCode == ERROR_ACCESS_DENIED) {
|
|
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
fSetFileIsADirectoryFlag = TRUE;
|
|
}
|
|
}
|
|
#ifndef OS_WINCE
|
|
TRC_ERR((TB, _T("CreateFile failed, %ld."), ulRetCode));
|
|
#else
|
|
TRC_NRM((TB, _T("CreateFile failed, pFileName=%s, DesiredAccess=0x%x, ShareMode=0x%x, CreateDisposition=0x%x, flags=0x%x, LastErr=0x%x."),
|
|
pFileName, DesiredAccess, pIoRequest->Parameters.Create.ShareAccess & ~(FILE_SHARE_DELETE), CreateDisposition, flags, ulRetCode));
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
#ifdef OS_WINCE
|
|
DWORD dwAttrib = 0xffffffff;
|
|
if ( (pIoRequest->Parameters.Create.CreateOptions & FILE_DIRECTORY_FILE) && ( ((CreateDisposition == CREATE_NEW) && (CreateDirectory(pFileName, NULL))) ||
|
|
( (CreateDisposition == OPEN_EXISTING) && ((dwAttrib = GetFileAttributes(pFileName)) != 0xffffffff) &&
|
|
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ) ) ){
|
|
#else
|
|
if (CreateDirectory(pFileName, NULL)) {
|
|
#endif
|
|
|
|
//
|
|
// Set the attributes on the directory
|
|
//
|
|
#ifndef OS_WINCE
|
|
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
|
|
//
|
|
// Create a new directory, for CE, you can't change the directory attributes
|
|
//
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
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.
|
|
//
|
|
|
|
if (fSetFileIsADirectoryFlag) {
|
|
result = STATUS_FILE_IS_A_DIRECTORY;
|
|
} else {
|
|
result = TranslateWinError(ulRetCode);
|
|
}
|
|
|
|
pReplyPacket->IoCompletion.IoStatus = result;
|
|
ProcessObject()->GetVCMgr().ChannelWrite(
|
|
(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 W32DrDeviceAsync::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_ASYNCIO_PARAMS *params;
|
|
DWORD result;
|
|
|
|
DC_BEGIN_FN("W32DrDeviceAsync::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_ASYNCIO_PARAMS(this, pIoRequestPacket);
|
|
if (params != NULL ) {
|
|
|
|
TRC_NRM((TB, _T("Async IO operation")));
|
|
|
|
result = ProcessObject()->DispatchAsyncIORequest(
|
|
(RDPAsyncFunc_StartIO)W32DrDeviceAsync::_StartIOFunc,
|
|
(RDPAsyncFunc_IOComplete)W32DrDeviceAsync::_CompleteIOFunc,
|
|
(RDPAsyncFunc_IOCancel)W32DrDeviceAsync::_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();
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::CancelIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancel an 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("W32DrDeviceAsync::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("CancelIOFunc failed to alloc %ld bytes."), replyPacketSize));
|
|
}
|
|
|
|
//
|
|
// Clean up the IO request parameters.
|
|
//
|
|
#if DBG
|
|
memset(params->pIoRequestPacket, DRBADMEM, sizeof(RDPDR_IOREQUEST_PACKET));
|
|
#endif
|
|
delete params->pIoRequestPacket;
|
|
params->pIoRequestPacket = NULL;
|
|
delete params;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
W32DrDeviceAsync::_CancelIOFunc(
|
|
IN PVOID clientData
|
|
)
|
|
{
|
|
W32DRDEV_ASYNCIO_PARAMS *params = (W32DRDEV_ASYNCIO_PARAMS *)clientData;
|
|
|
|
// Dispatch it.
|
|
params->pObject->CancelIOFunc(params);
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::AsyncMsgIrpCloseFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchronous Close IRP router.
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrDeviceAsync::AsyncMsgIrpCloseFunc");
|
|
|
|
//
|
|
// This function is a temporary placeholder for this release. (.NET).
|
|
// We may decide to route all close functionality through this parent
|
|
// class in a future release. For now, it should never be called. It
|
|
// is up to the child class to override this function if async closes
|
|
// are being dispatched at their level. - TadB
|
|
//
|
|
ASSERT(FALSE);
|
|
|
|
DC_END_FN();
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
DWORD
|
|
W32DrDeviceAsync::_AsyncMsgIrpCloseFunc(
|
|
IN PVOID params,
|
|
IN HANDLE cancelEvent
|
|
)
|
|
{
|
|
W32DRDEV_ASYNCIO_PARAMS *p = (W32DRDEV_ASYNCIO_PARAMS *)params;
|
|
return p->pObject->AsyncMsgIrpCloseFunc(p);
|
|
}
|
|
|
|
DWORD
|
|
W32DrDeviceAsync::AsyncMsgIrpCreateFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchronous Create IRP router.
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrDeviceAsync::AsyncMsgIrpCreateFunc");
|
|
|
|
//
|
|
// This function is a temporary placeholder for this release. (.NET).
|
|
// We may decide to route all create functionality through this parent
|
|
// class in a future release. For now, it should never be called. It
|
|
// is up to the child class to overide this function if async closes
|
|
// are being dispatched at their level. - TadB
|
|
//
|
|
ASSERT(FALSE);
|
|
|
|
DC_END_FN();
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
DWORD
|
|
W32DrDeviceAsync::_AsyncMsgIrpCreateFunc(
|
|
IN PVOID params,
|
|
IN HANDLE cancelEvent
|
|
)
|
|
{
|
|
W32DRDEV_ASYNCIO_PARAMS *p = (W32DRDEV_ASYNCIO_PARAMS *)params;
|
|
return p->pObject->AsyncMsgIrpCreateFunc(p);
|
|
}
|