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.
600 lines
13 KiB
600 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
w32drdev
|
|
|
|
Abstract:
|
|
|
|
This module defines the parent for the Win32 client-side RDP
|
|
device redirection "device" class hierarchy, W32DrDevice.
|
|
|
|
Author:
|
|
|
|
Tad Brockway 3/23/99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precom.h>
|
|
|
|
#define TRC_FILE "W32DrDevice"
|
|
|
|
#include "w32drdev.h"
|
|
#include "proc.h"
|
|
#include "drdbg.h"
|
|
#include "w32utl.h"
|
|
#include "utl.h"
|
|
#include "w32proc.h"
|
|
|
|
#ifdef OS_WINCE
|
|
#include "filemgr.h"
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// W32DrDevice Members
|
|
//
|
|
//
|
|
|
|
W32DrDevice::W32DrDevice(
|
|
IN ProcObj *processObject,
|
|
IN ULONG deviceID,
|
|
IN const TCHAR *devicePath
|
|
) : DrDevice(processObject, deviceID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for the W32DrDevice class.
|
|
|
|
Arguments:
|
|
|
|
processObject - Associated Process Object
|
|
deviceID - Unique device identifier.
|
|
devicePath - Path to device that can be used by
|
|
CreateFile to open device.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrDevice::W32DrDevice");
|
|
|
|
//
|
|
// Record device path.
|
|
//
|
|
ASSERT(STRLEN(devicePath) < MAX_PATH);
|
|
STRNCPY(_devicePath, devicePath, MAX_PATH);
|
|
_devicePath[MAX_PATH-1] = '\0';
|
|
|
|
//
|
|
// Initialize the handle to the string resource module.
|
|
//
|
|
_hRdpDrModuleHandle = NULL;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
W32DrDevice::~W32DrDevice()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for the W32DrDevice class.
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrDevice::~W32DrDevice");
|
|
|
|
//
|
|
// Close the string resource module.
|
|
//
|
|
if (_hRdpDrModuleHandle != NULL) {
|
|
FreeLibrary( _hRdpDrModuleHandle );
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
TCHAR*
|
|
W32DrDevice::ConstructFileName(
|
|
PWCHAR Path,
|
|
ULONG PathBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Setup the file name
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR *pFileName;
|
|
HRESULT hr;
|
|
UINT cchFileName;
|
|
|
|
//
|
|
// Get the File Name
|
|
//
|
|
if (PathBytes) {
|
|
ULONG PathLen, DeviceLen;
|
|
|
|
//
|
|
// Open a File
|
|
//
|
|
|
|
//
|
|
// Path is assumed string null terminated
|
|
//
|
|
PathLen = PathBytes / sizeof(WCHAR) - 1;
|
|
Path[PathLen] = L'\0';
|
|
|
|
#ifndef OS_WINCE
|
|
DeviceLen = _tcslen(_devicePath);
|
|
#else
|
|
DeviceLen = 0;
|
|
#endif
|
|
|
|
//
|
|
// Append device path and file path together
|
|
// Assuming we need the \\?\ format, string
|
|
// is null terminated
|
|
//
|
|
|
|
#ifndef OS_WINCE
|
|
cchFileName = (DeviceLen + PathLen + 5);
|
|
pFileName = new TCHAR[cchFileName];
|
|
#else
|
|
cchFileName = PathLen + 1
|
|
pFileName = new TCHAR[cchFileName];
|
|
#endif
|
|
|
|
if (pFileName) {
|
|
#ifndef OS_WINCE
|
|
if (DeviceLen + PathLen < MAX_PATH) {
|
|
//
|
|
// Buffer is allocated large enough for the string
|
|
//
|
|
StringCchCopy(pFileName, cchFileName, _devicePath);
|
|
}
|
|
else {
|
|
//
|
|
// Buffer is allocated large enough for the string
|
|
//
|
|
StringCchPrintf(pFileName, cchFileName,
|
|
TEXT("\\\\?\\%s"),
|
|
_devicePath);
|
|
|
|
DeviceLen += 4;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
RDPConvertToAnsi(Path, pFileName + DeviceLen, PathLen + 1);
|
|
#else
|
|
memcpy(pFileName + DeviceLen, Path, PathLen * sizeof(WCHAR));
|
|
pFileName[DeviceLen + PathLen] = _T('\0');
|
|
#endif
|
|
}
|
|
else {
|
|
//
|
|
// Open the device itself
|
|
//
|
|
pFileName = _devicePath;
|
|
}
|
|
|
|
Cleanup:
|
|
return pFileName;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDevice::ConstructCreateDisposition(
|
|
DWORD Disposition
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct client create disposition
|
|
|
|
--*/
|
|
{
|
|
DWORD CreateDisposition;
|
|
|
|
//
|
|
// Setup CreateDisposition
|
|
//
|
|
switch (Disposition) {
|
|
case FILE_CREATE :
|
|
CreateDisposition = CREATE_NEW;
|
|
break;
|
|
case FILE_OVERWRITE_IF :
|
|
CreateDisposition = CREATE_ALWAYS;
|
|
break;
|
|
case FILE_OPEN :
|
|
CreateDisposition = OPEN_EXISTING;
|
|
break;
|
|
case FILE_OPEN_IF :
|
|
CreateDisposition = OPEN_ALWAYS;
|
|
break;
|
|
|
|
default :
|
|
CreateDisposition = 0;
|
|
}
|
|
|
|
return CreateDisposition;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDevice::ConstructDesiredAccess(
|
|
DWORD AccessMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct client desired access from server's access mask
|
|
|
|
--*/
|
|
{
|
|
DWORD DesiredAccess;
|
|
|
|
//
|
|
// Setup DesiredAccess
|
|
//
|
|
DesiredAccess = 0;
|
|
|
|
//
|
|
// If the user requested WRITE_DATA, return write.
|
|
//
|
|
|
|
if (AccessMask & FILE_WRITE_DATA) {
|
|
DesiredAccess |= GENERIC_WRITE;
|
|
}
|
|
|
|
//
|
|
// If the user requested READ_DATA, return read.
|
|
//
|
|
if (AccessMask & FILE_READ_DATA) {
|
|
DesiredAccess |= GENERIC_READ;
|
|
}
|
|
|
|
//
|
|
// If the user requested FILE_EXECUTE, return execute.
|
|
//
|
|
if (AccessMask & FILE_EXECUTE) {
|
|
DesiredAccess |= GENERIC_READ;
|
|
}
|
|
|
|
return DesiredAccess;
|
|
}
|
|
|
|
DWORD
|
|
W32DrDevice::ConstructFileFlags(
|
|
DWORD CreateOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct file flags
|
|
|
|
--*/
|
|
{
|
|
DWORD CreateFlags;
|
|
|
|
|
|
CreateFlags = 0;
|
|
CreateFlags |= (CreateOptions & FILE_WRITE_THROUGH ? FILE_FLAG_WRITE_THROUGH : 0);
|
|
CreateFlags |= (CreateOptions & FILE_RANDOM_ACCESS ? FILE_FLAG_RANDOM_ACCESS : 0 );
|
|
//CreateFlags |= (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT ? 0 : FILE_FLAG_OVERLAPPED);
|
|
#ifndef OS_WINCE
|
|
CreateFlags |= (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING ? FILE_FLAG_NO_BUFFERING : 0);
|
|
CreateFlags |= (CreateOptions & FILE_SEQUENTIAL_ONLY ? FILE_FLAG_SEQUENTIAL_SCAN : 0);
|
|
CreateFlags |= (CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT ? FILE_FLAG_BACKUP_SEMANTICS : 0);
|
|
CreateFlags |= (CreateOptions & FILE_DELETE_ON_CLOSE ? FILE_FLAG_DELETE_ON_CLOSE : 0);
|
|
CreateFlags |= (CreateOptions & FILE_OPEN_REPARSE_POINT ? FILE_FLAG_OPEN_REPARSE_POINT : 0);
|
|
CreateFlags |= (CreateOptions & FILE_OPEN_NO_RECALL ? FILE_FLAG_OPEN_NO_RECALL : 0);
|
|
#endif
|
|
|
|
return CreateFlags;
|
|
}
|
|
|
|
BOOL
|
|
W32DrDevice::IsDirectoryFile(
|
|
DWORD DesiredAccess, DWORD CreateOptions, DWORD FileAttributes,
|
|
PDWORD FileFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the pFileName corresponds to a directory
|
|
|
|
--*/
|
|
{
|
|
BOOL IsDirectory = FALSE;
|
|
|
|
//
|
|
// Set up the directory check
|
|
//
|
|
if (!(CreateOptions & FILE_DIRECTORY_FILE)) {
|
|
//
|
|
// File doesn't have the directory flag on
|
|
// or nondirecotry flag on, so it's not sure
|
|
// if the file is a directory request or not
|
|
//
|
|
if (!(CreateOptions & FILE_NON_DIRECTORY_FILE)) {
|
|
if (FileAttributes != -1) {
|
|
//
|
|
// From file attributes, we know this is an directory file
|
|
// and we are requesting query access only. So, we add the
|
|
// BACKUP_SEMANTICS for the file and set the directory flag
|
|
// to be true. We always set the backup_semantics flag
|
|
//
|
|
#ifndef OS_WINCE
|
|
*FileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
|
|
#endif
|
|
|
|
if ((FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && DesiredAccess == 0) {
|
|
IsDirectory = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Non directory file flag is on, so we are doing file create/open request
|
|
//
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// File has the directory flag on, but we still want to do create file
|
|
// on the directory
|
|
//
|
|
// Set the BACKUP_SEMANTICS, add it to the file flags
|
|
// and remember this is a directory
|
|
//
|
|
if (FileAttributes != -1) {
|
|
#ifndef OS_WINCE
|
|
*FileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
|
|
#endif
|
|
IsDirectory = TRUE;
|
|
}
|
|
}
|
|
|
|
return IsDirectory;
|
|
}
|
|
|
|
|
|
VOID
|
|
W32DrDevice::MsgIrpFlushBuffers(
|
|
IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
IN UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Cleanup" IO request from the server.
|
|
|
|
Arguments:
|
|
|
|
pIoRequestPacket - Server IO request packet.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
BOOL result;
|
|
DWORD returnValue;
|
|
DrFile* pFile;
|
|
HANDLE FileHandle;
|
|
|
|
DC_BEGIN_FN("W32DrDevice::MsgIrpFlushBuffers");
|
|
|
|
//
|
|
// Get IO request pointer.
|
|
//
|
|
pIoRequest = &pIoRequestPacket->IoRequest;
|
|
|
|
//
|
|
// Get File Object
|
|
//
|
|
pFile = _FileMgr->GetObject(pIoRequest->FileId);
|
|
|
|
if (pFile)
|
|
FileHandle = pFile->GetFileHandle();
|
|
else
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// Flush the device handle.
|
|
//
|
|
ASSERT(FileHandle != INVALID_HANDLE_VALUE);
|
|
#ifndef OS_WINCE
|
|
result = FlushFileBuffers(FileHandle);
|
|
#else
|
|
result = CEFlushFileBuffers(FileHandle);
|
|
#endif
|
|
if (!result) {
|
|
TRC_ERR((TB, _T("Flush returned %ld."), GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Send the result to the server.
|
|
//
|
|
returnValue = result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
DefaultIORequestMsgHandle(pIoRequestPacket, returnValue);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
W32DrDevice::MsgIrpClose(
|
|
IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
IN UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Close" IO request from the server.
|
|
|
|
Arguments:
|
|
|
|
pIoRequestPacket - Server IO request packet.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
DWORD returnValue = STATUS_SUCCESS;
|
|
DrFile* pFile;
|
|
|
|
DC_BEGIN_FN("W32DrDevice::MsgIrpClose");
|
|
|
|
//
|
|
// Get IO request pointer.
|
|
//
|
|
pIoRequest = &pIoRequestPacket->IoRequest;
|
|
|
|
if (_FileMgr == NULL) {
|
|
returnValue = STATUS_UNSUCCESSFUL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Remove the File Object
|
|
//
|
|
pFile = _FileMgr->RemoveObject(pIoRequest->FileId);
|
|
|
|
if ( pFile != NULL) {
|
|
if (!pFile->Close()) {
|
|
TRC_ERR((TB, _T("Close returned %ld."), GetLastError()));
|
|
returnValue = STATUS_UNSUCCESSFUL;
|
|
}
|
|
pFile->Release();
|
|
}
|
|
else {
|
|
returnValue = STATUS_UNSUCCESSFUL;
|
|
}
|
|
Cleanup:
|
|
//
|
|
// Send the result to the server.
|
|
//
|
|
DefaultIORequestMsgHandle(pIoRequestPacket, returnValue);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
ULONG
|
|
W32DrDevice::ReadResources(
|
|
ULONG ulMessageID,
|
|
LPTSTR *ppStringBuffer,
|
|
PVOID pArguments,
|
|
BOOL bFromSystemModule
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read a string from the resources file.
|
|
|
|
Arguments:
|
|
|
|
lMessageID - Message ID.
|
|
ppStringBuffer - Buffer pointer where the alloted buffer pointer
|
|
is returned.
|
|
pArguments - Pointer array.
|
|
bFromSystemModule - When set TRUE return the message from the system
|
|
module otherwise from the rdpdr.dll message module.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS on success. Otherwise, a Windows error code is
|
|
returned.
|
|
|
|
--*/
|
|
{
|
|
ULONG ulError;
|
|
HINSTANCE hModuleHandle;
|
|
ULONG ulModuleFlag;
|
|
ULONG ulLen;
|
|
|
|
DC_BEGIN_FN("W32DrDevice::ReadResources");
|
|
|
|
if( !bFromSystemModule ) {
|
|
|
|
if (_hRdpDrModuleHandle == NULL ) {
|
|
_hRdpDrModuleHandle = LoadLibrary(RDPDR_MODULE_NAME);
|
|
|
|
if( _hRdpDrModuleHandle == NULL ) {
|
|
ulError = GetLastError();
|
|
TRC_ERR((TB, _T("LoadLibrary failed for %s: %ld."),
|
|
RDPDR_MODULE_NAME, ulError));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
hModuleHandle = _hRdpDrModuleHandle;
|
|
ulModuleFlag = FORMAT_MESSAGE_FROM_HMODULE;
|
|
}
|
|
else {
|
|
hModuleHandle = NULL;
|
|
ulModuleFlag = FORMAT_MESSAGE_FROM_SYSTEM;
|
|
}
|
|
|
|
ulLen =
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
ulModuleFlag |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
hModuleHandle,
|
|
ulMessageID,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPTSTR)ppStringBuffer,
|
|
0,
|
|
(va_list *)pArguments );
|
|
|
|
if( ulLen == 0 ) {
|
|
ulError = GetLastError();
|
|
TRC_ERR((TB, _T("FormatMessage() %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(*ppStringBuffer != NULL);
|
|
ulError = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
DC_END_FN();
|
|
return ulError;
|
|
}
|
|
|
|
|
|
|