|
|
/*++
Copyright (c) 1998-2000 Microsoft Corporation
Module Name:
w32drive
Abstract:
This module defines a child of the client-side RDP device redirection, the "w32drive" W32Drive to provide file system redirection on 32bit windows
Author:
Joy Chik 11/1/99
Revision History:
--*/
#include <precom.h>
#define TRC_FILE "w32drive"
#include "drdev.h"
#include "w32drdev.h"
#include "w32drive.h"
#include "proc.h"
#include "drconfig.h"
#include "w32utl.h"
#include "utl.h"
#include "drfsfile.h"
#ifdef OS_WINCE
#include "wceinc.h"
#include "axresrc.h"
#include <lss.h>
#include <ceconfig.h>
#include "filemgr.h"
#endif
///////////////////////////////////////////////////////////////
//
// W32Drive Methods
//
//
W32Drive::W32Drive( ProcObj *processObject, ULONG deviceID, const TCHAR *deviceName, const TCHAR *devicePath) : W32DrDeviceAsync(processObject, deviceID, devicePath) /*++
Routine Description:
Constructor
Arguments:
processObject - Associated process object. deviceName - Name of the drive. id - Device ID for the drive. devicePath - Path that can be opened by CreateFile for drive.
Return Value:
NA
--*/ { unsigned len;
DC_BEGIN_FN("W32Drive::W32Drive"); SetDeviceProperty(); _fFailedInConstructor = FALSE; //
// Record the drive name.
//
TRC_ASSERT((deviceName != NULL), (TB, _T("deviceName is NULL"))); len = (STRLEN(deviceName) + 1); _driveName = new TCHAR[len]; if (_driveName != NULL) { StringCchCopy(_driveName, len, deviceName); }
//
// Check and record our status,
//
if (_driveName == NULL) { TRC_ERR((TB, _T("Memory allocation failed."))); SetValid(FALSE); _fFailedInConstructor = TRUE; } }
W32Drive::~W32Drive() /*++
Routine Description:
Destructor
Arguments:
NA Return Value:
NA
--*/ { if (_driveName != NULL) { delete _driveName; } }
DWORD W32Drive::Enumerate( IN ProcObj *procObj, IN DrDeviceMgr *deviceMgr ) { //
// We enumerate all 26 drive letters
//
return W32Drive::EnumerateDrives(procObj, deviceMgr, 0x3FFFFFF); }
DWORD W32Drive::EnumerateDrives( IN ProcObj *procObj, IN DrDeviceMgr *deviceMgr, IN UINT unitMask ) /*++
Routine Description:
Enumerate devices of this type by adding appropriate device instances to the device manager.
Arguments:
procObj - Corresponding process object. deviceMgr - Device manager to add devices to.
Return Value:
ERROR_SUCCESS on success. Otherwise, an error code is returned.
--*/ { TCHAR szBuff[LOGICAL_DRIVE_LEN * MAX_LOGICAL_DRIVES + 1]; LPTSTR lpszDrive = &szBuff[0]; TCHAR szDrive[3]; W32Drive *deviceObj; RDPDR_VERSION serverVer; DC_BEGIN_FN("W32Drive::Enumerate");
TRC_DBG((TB, _T("Enumerating drives")));
serverVer = procObj->serverVersion();
if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectDrives) { TRC_DBG((TB,_T("Drive redirection disabled, bailing out"))); return ERROR_SUCCESS; }
//
// If the server doesn't support drive redirection,
// then don't bother enumerate the drives, simply
// return success
//
if (COMPARE_VERSION(serverVer.Minor, serverVer.Major, 4, 1) < 0) { TRC_NRM((TB, _T("Skipping drive enumeration"))); return ERROR_SUCCESS; }
szDrive[2] = TEXT('\0');
#ifndef OS_WINCE
DWORD dwEnum;
//
// Enumerate all drive letters and find the valid drives
//
dwEnum = 0; while (unitMask) { if (unitMask & 0x1) { //
// For each drive find whether it is a local sharable drive
//
lpszDrive = &(szBuff[LOGICAL_DRIVE_LEN * dwEnum]); lpszDrive[0] = TEXT('A') + (TCHAR)dwEnum; lpszDrive[1] = TEXT(':'); lpszDrive[2] = TEXT('\\'); lpszDrive[3] = TEXT('\0'); switch (GetDriveType(lpszDrive)) { case DRIVE_REMOVABLE: // The disk can be removed from the drive.
case DRIVE_FIXED: // The disk cannot be removed from the drive.
case DRIVE_CDROM: // The drive is a CD-ROM drive.
case DRIVE_RAMDISK: // The drive is a RAM disk.
case DRIVE_REMOTE: // The drive is a remote (network) drive.
TRC_NRM((TB, _T("Redirecting drive %s"), lpszDrive)); // Copy <driveletter>: into drive device path
szDrive[0] = lpszDrive[0]; szDrive[1] = lpszDrive[1]; deviceObj = new W32Drive(procObj, deviceMgr->GetUniqueObjectID(), &szDrive[0], &szDrive[0]); //
// Add to the device manager if we got a valid object.
//
if (deviceObj != NULL) { if (deviceObj->IfFailedInConstructor() != TRUE) { deviceObj->Initialize(); if (!(deviceObj->IsValid() && (deviceMgr->AddObject(deviceObj) == STATUS_SUCCESS))) { delete deviceObj; } } else { TRC_ERR((TB, _T("Failed in new W32Drive"))); delete deviceObj; } } else { TRC_ERR((TB, _T("Failed to allocate drive device."))); } break; case DRIVE_UNKNOWN: // The drive type cannot be determined.
case DRIVE_NO_ROOT_DIR: // The root path is invalid. For example, no volume is mounted at the path.
default: TRC_NRM((TB, _T("Skipping drive %s"), lpszDrive)); break; } }
unitMask = unitMask >> 0x1; dwEnum++; } #else
//
// JOYC: Need to look into CE way of enumerate drives
// For now, we just use C drive e.g. \\tsclient\c on the server side
//
//CE doesnt have drive letters. So DevicePath='\\', DeviceName="Files". And this string should NOT be localized
deviceObj = new W32Drive(procObj, deviceMgr->GetUniqueObjectID(), CEROOTDIRNAME, CEROOTDIR); //
// Add to the device manager if we got a valid object.
//
if (deviceObj != NULL) { deviceObj->Initialize(); if (!(deviceObj->IsValid() && (deviceMgr->AddObject(deviceObj) == STATUS_SUCCESS))) { delete deviceObj; } } else { TRC_ERR((TB, _T("Failed to allocate drive device."))); }
#endif
DC_END_FN();
return ERROR_SUCCESS; }
DWORD W32Drive::RemoveDrives( IN ProcObj *procObj, IN DrDeviceMgr *deviceMgr, IN UINT unitMask ) /*++
Routine Description:
Enumerate devices of this type by removing appropriate device instances from the device manager.
Arguments:
procObj - Corresponding process object. deviceMgr - Device manager to add devices to.
Return Value:
ERROR_SUCCESS on success. Otherwise, an error code is returned.
--*/ {
DWORD driveIndex = 0; RDPDR_VERSION serverVer; TCHAR szDrive[3];
DC_BEGIN_FN("W32Drive::RemoveDrives");
serverVer = procObj->serverVersion();
if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectDrives) { TRC_DBG((TB,_T("Drive redirection disabled, bailing out"))); return ERROR_SUCCESS; }
//
// If the server doesn't support drive removal,
// then don't bother enumerate the drives, simply
// return
//
if (!(procObj->GetServerCap().GeneralCap.extendedPDU & RDPDR_DEVICE_REMOVE_PDUS)) { TRC_NRM((TB, _T("Skipping drive enumeration"))); return ERROR_SUCCESS; }
szDrive[1] = TEXT(':'); szDrive[2] = TEXT('\0');
while (unitMask) { if (unitMask & 0x1) { DrDevice *deviceObj; //
// Find if a device exists
//
szDrive[0] = TEXT('A') + (TCHAR)driveIndex; deviceObj = (DrDevice*)deviceMgr->GetObject(szDrive, RDPDR_DTYP_FILESYSTEM);
if ( deviceObj != NULL ) { deviceObj->_deviceChange = DEVICEREMOVE;
// Need to remove this device
TRC_NRM((TB, _T("Deleting drive %s"), szDrive)); } }
unitMask = unitMask >> 0x1; driveIndex++; }
DC_END_FN(); return ERROR_SUCCESS; }
ULONG W32Drive::GetDevAnnounceDataSize() /*++
Routine Description:
Return the size (in bytes) of a device announce packet for this device.
Arguments:
NA
Return Value:
The size (in bytes) of a device announce packet for this device.
--*/ { ULONG size = 0;
DC_BEGIN_FN("W32Drive::GetDevAnnounceDataSize");
TRC_ASSERT((IsValid()), (TB, _T("Invalid w32drive object"))); if (!IsValid()) { return 0; }
size = 0;
//
// Add the base announce size.
//
size += sizeof(RDPDR_DEVICE_ANNOUNCE);
DC_END_FN();
return size; }
VOID W32Drive::GetDevAnnounceData( IN PRDPDR_DEVICE_ANNOUNCE pDeviceAnnounce ) /*++
Routine Description:
Add a device announce packet for this device to the input buffer.
Arguments:
pDeviceAnnounce - Device Announce Buf for this Device
Return Value:
NA
--*/ { DC_BEGIN_FN("W32Drive::GetDevAnnounceData");
TRC_ASSERT((IsValid()), (TB, _T("Invalid w32drive object"))); if (!IsValid()) { DC_END_FN(); return; }
pDeviceAnnounce->DeviceId = GetID(); pDeviceAnnounce->DeviceType = GetDeviceType(); pDeviceAnnounce->DeviceDataLength = 0;
//
// Record the device name in ANSI.
//
#ifdef UNICODE
RDPConvertToAnsi(_driveName, (LPSTR)pDeviceAnnounce->PreferredDosName, sizeof(pDeviceAnnounce->PreferredDosName) ); #else
STRNCPY((char *)pDeviceAnnounce->PreferredDosName, _driveName, PREFERRED_DOS_NAME_SIZE); pDeviceAnnounce->PreferredDosName[PREFERRED_DOS_NAME_SIZE - 1] = '\0'; #endif
DC_END_FN(); }
HANDLE W32Drive::StartFSFunc( IN W32DRDEV_ASYNCIO_PARAMS *params, OUT DWORD *status ) /*++
Routine Description:
Start a generic asynchronous File System 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_DEVICE_IOREQUEST pIoRequest; DrFile* pFile; ULONG irpMajor; DC_BEGIN_FN("W32Drive::StartFSFunc");
*status = ERROR_SUCCESS;
// Assert the integrity of the IO context
TRC_ASSERT((params->magicNo == GOODMEMMAGICNUMBER), (TB, _T("bad params->magicNo: %x"), params->magicNo));
//
// Get the IO request and the IPR major.
//
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
irpMajor = pIoRequest->MajorFunction;
//
// 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_DIRECTORY_CONTROL: params->thrPoolReq = _threadPool->SubmitRequest( _AsyncDirCtrlFunc, 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 { //
// Get File Object
//
pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) { pFile->Release(); }
if (params->completionEvent != NULL) { CloseHandle(params->completionEvent); params->completionEvent = NULL; }
DC_END_FN(); return NULL; } }
HANDLE W32Drive::_StartFSFunc( IN W32DRDEV_ASYNCIO_PARAMS *params, OUT DWORD *status ) { return ((W32Drive*)params->pObject)->StartFSFunc(params, status); }
VOID W32Drive::MsgIrpQueryDirectory( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Queries the directory information for this drive device.
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; ULONG BufferLength = 0; BYTE Buffer[RDP_FILE_DIRECTORY_INFO_MAXLENGTH + (MAX_PATH + 1) * sizeof(WCHAR)]; TCHAR *pFileName; DrFile *pFile; HANDLE FileHandle; WIN32_FIND_DATA FileData; unsigned DriveLen, PathLen; BOOL rc; HRESULT hr;
DC_BEGIN_FN("W32Drive::MsgIrpQueryDirectory");
ASSERT(_tcslen(_devicePath));
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
PathLen = DriveLen = 0; pFileName = NULL; memset(Buffer, 0, sizeof(Buffer));
//
// Map file Id to get the file object
//
pFile = _FileMgr->GetObject(pIoRequest->FileId);
//
// Query file or directory information
//
if (pFile) { if (!pIoRequest->Parameters.QueryDir.InitialQuery) { ASSERT(((DrFSFile *)pFile)->GetSearchHandle() != INVALID_TS_FILEHANDLE); rc = FindNextFile(((DrFSFile *)pFile)->GetSearchHandle(), &FileData); } else { TCHAR FileName[MAX_PATH];
//
// Setup the File Name
//
//
// Path is assumed string null terminated
//
if (packetLen < sizeof(RDPDR_IOREQUEST_PACKET) + pIoRequest->Parameters.QueryDir.PathLength) { // call VirtualChannelClose
ProcessObject()->GetVCMgr().ChannelClose(); TRC_ASSERT(FALSE, (TB, _T("Packet Length Error"))); goto Cleanup; } PathLen = pIoRequest->Parameters.QueryDir.PathLength / sizeof(WCHAR) - 1;
if (PathLen) { WCHAR *Path;
//
// Open a File
//
Path = (WCHAR *)(pIoRequestPacket + 1); Path[PathLen] = L'\0';
#ifndef OS_WINCE
DriveLen = _tcslen(_devicePath); #else
DriveLen = 0; #endif
//
// Append device path and file path together
//
#ifndef OS_WINCE
if (DriveLen + PathLen < MAX_PATH) { pFileName = &FileName[0]; //Length is pre-checked
hr = StringCchCopy(pFileName, MAX_PATH, _devicePath); TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str copy failed for pre-checked len: 0x%x"),hr)); } else { UINT cchLen = DriveLen + PathLen + 5; pFileName = new TCHAR[cchLen];
if (pFileName) {
//
// The file name needs to be in the \\?\ format.
//
// Note: we'll not get UNC path name
hr = StringCchPrintf(pFileName, cchLen, TEXT("\\\\?\\%s"), _devicePath); TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str copy failed for pre-checked len: 0x%x"),hr)); DriveLen += 4;
} else { TRC_ERR((TB, _T("Failed to alloc File Name"))); goto Cleanup; } } #else
pFileName = &FileName[0]; #endif
#ifndef UNICODE
RDPConvertToAnsi(Path, pFileName + DriveLen, PathLen + 1); #else
memcpy(pFileName + DriveLen, Path, PathLen * sizeof(WCHAR)); pFileName[DriveLen + PathLen] = _T('\0'); #endif
} else { //
// Open the root drive
//
hr = StringCchPrintf(FileName, SIZE_TCHARS(FileName), _T("%s\\"), _devicePath); TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str printf failed for pre-checked len: 0x%x"),hr));
pFileName = &FileName[0]; }
FileHandle = FindFirstFile(pFileName, &FileData); if (FileHandle != INVALID_HANDLE_VALUE) { ((DrFSFile *)pFile)->SetSearchHandle(FileHandle); rc = TRUE; } else { rc = FALSE; } } } else { ulRetCode = ERROR_FILE_NOT_FOUND; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query directory information failed, %ld."), ulRetCode)); goto SendPacket; }
switch (pIoRequest->Parameters.QueryDir.FileInformationClass) { case RdpFileDirectoryInformation: if (rc) { PRDP_FILE_DIRECTORY_INFORMATION pFileDirInfo = (PRDP_FILE_DIRECTORY_INFORMATION) Buffer;
pFileDirInfo->NextEntryOffset = 0; pFileDirInfo->FileIndex = 0; pFileDirInfo->CreationTime.LowPart = FileData.ftCreationTime.dwLowDateTime; pFileDirInfo->CreationTime.HighPart = FileData.ftCreationTime.dwHighDateTime; pFileDirInfo->LastAccessTime.LowPart = FileData.ftLastAccessTime.dwLowDateTime; pFileDirInfo->LastAccessTime.HighPart = FileData.ftLastAccessTime.dwHighDateTime; pFileDirInfo->LastWriteTime.LowPart = FileData.ftLastWriteTime.dwLowDateTime; pFileDirInfo->LastWriteTime.HighPart = FileData.ftLastWriteTime.dwHighDateTime; pFileDirInfo->ChangeTime.QuadPart = 0; pFileDirInfo->EndOfFile.HighPart = FileData.nFileSizeHigh; pFileDirInfo->EndOfFile.LowPart = FileData.nFileSizeLow;
// TODO Do we need to set the allocation size? and what should it be?
pFileDirInfo->AllocationSize.HighPart = FileData.nFileSizeHigh; pFileDirInfo->AllocationSize.LowPart = FileData.nFileSizeLow; pFileDirInfo->FileAttributes = FileData.dwFileAttributes;
pFileDirInfo->FileNameLength = _tcslen(FileData.cFileName) * sizeof(WCHAR); #ifdef UNICODE
memcpy(&pFileDirInfo->FileName[0], FileData.cFileName, pFileDirInfo->FileNameLength); #else
RDPConvertToUnicode(FileData.cFileName, (LPWSTR)FileNameBuffer, MAX_PATH); memcpy(&pFileDirInfo->FileName[0], FileNameBuffer, pFileDirInfo->FileNameLength);
#endif
ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_DIRECTORY_INFORMATION, FileName) + pFileDirInfo->FileNameLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query directory information failed, %ld."), ulRetCode)); }
break;
case RdpFileFullDirectoryInformation: if (rc) { PRDP_FILE_FULL_DIR_INFORMATION pFileDirInfo = (PRDP_FILE_FULL_DIR_INFORMATION) Buffer;
pFileDirInfo->NextEntryOffset = 0; pFileDirInfo->FileIndex = 0; pFileDirInfo->CreationTime.LowPart = FileData.ftCreationTime.dwLowDateTime; pFileDirInfo->CreationTime.HighPart = FileData.ftCreationTime.dwHighDateTime; pFileDirInfo->LastAccessTime.LowPart = FileData.ftLastAccessTime.dwLowDateTime; pFileDirInfo->LastAccessTime.HighPart = FileData.ftLastAccessTime.dwHighDateTime; pFileDirInfo->LastWriteTime.LowPart = FileData.ftLastWriteTime.dwLowDateTime; pFileDirInfo->LastWriteTime.HighPart = FileData.ftLastWriteTime.dwHighDateTime; pFileDirInfo->ChangeTime.QuadPart = 0; pFileDirInfo->EndOfFile.HighPart = FileData.nFileSizeHigh; pFileDirInfo->EndOfFile.LowPart = FileData.nFileSizeLow; pFileDirInfo->AllocationSize.HighPart = FileData.nFileSizeHigh; pFileDirInfo->AllocationSize.LowPart = FileData.nFileSizeLow; pFileDirInfo->FileAttributes = FileData.dwFileAttributes; pFileDirInfo->FileNameLength = _tcslen(FileData.cFileName) * sizeof(WCHAR); #ifdef UNICODE
memcpy(&pFileDirInfo->FileName[0], FileData.cFileName, pFileDirInfo->FileNameLength); #else
RDPConvertToUnicode(FileData.cFileName, (LPWSTR)FileNameBuffer, MAX_PATH); memcpy(&pFileDirInfo->FileName[0], FileNameBuffer, pFileDirInfo->FileNameLength);
#endif
pFileDirInfo->EaSize = 0;
ulRetCode = ERROR_SUCCESS;
BufferLength = FIELD_OFFSET(RDP_FILE_FULL_DIR_INFORMATION, FileName) + pFileDirInfo->FileNameLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query full directory information failed, %ld."), ulRetCode)); }
break;
case RdpFileBothDirectoryInformation: if (rc) { PRDP_FILE_BOTH_DIR_INFORMATION pFileDirInfo = (PRDP_FILE_BOTH_DIR_INFORMATION) Buffer;
pFileDirInfo->NextEntryOffset = 0; pFileDirInfo->FileIndex = 0; pFileDirInfo->CreationTime.LowPart = FileData.ftCreationTime.dwLowDateTime; pFileDirInfo->CreationTime.HighPart = FileData.ftCreationTime.dwHighDateTime; pFileDirInfo->LastAccessTime.LowPart = FileData.ftLastAccessTime.dwLowDateTime; pFileDirInfo->LastAccessTime.HighPart = FileData.ftLastAccessTime.dwHighDateTime; pFileDirInfo->LastWriteTime.LowPart = FileData.ftLastWriteTime.dwLowDateTime; pFileDirInfo->LastWriteTime.HighPart = FileData.ftLastWriteTime.dwHighDateTime; pFileDirInfo->ChangeTime.QuadPart = 0; pFileDirInfo->EndOfFile.HighPart = FileData.nFileSizeHigh; pFileDirInfo->EndOfFile.LowPart = FileData.nFileSizeLow; pFileDirInfo->AllocationSize.HighPart = FileData.nFileSizeHigh; pFileDirInfo->AllocationSize.LowPart = FileData.nFileSizeLow; pFileDirInfo->FileAttributes = FileData.dwFileAttributes; pFileDirInfo->EaSize = 0; #ifndef OS_WINCE
pFileDirInfo->ShortNameLength = (CCHAR)(_tcslen(FileData.cAlternateFileName) * sizeof(WCHAR)); #else
pFileDirInfo->ShortNameLength = sizeof(WCHAR); #endif
#ifndef OS_WINCE
#ifdef UNICODE
memcpy(&pFileDirInfo->ShortName[0], FileData.cAlternateFileName, pFileDirInfo->ShortNameLength); #else
RDPConvertToUnicode(FileData.cAlternateFileName, (LPWSTR)ShortName, sizeof(ShortName) / sizeof(WCHAR)); memcpy(&pFileDirInfo->ShortName[0], ShortName, pFileDirInfo->ShortNameLength); #endif
#else
pFileDirInfo->ShortName[0] = L'\0'; #endif
pFileDirInfo->FileNameLength = _tcslen(FileData.cFileName) * sizeof(WCHAR);
#ifdef UNICODE
memcpy(&pFileDirInfo->FileName[0], FileData.cFileName, pFileDirInfo->FileNameLength); #else
RDPConvertToUnicode(FileData.cFileName, FileNameBuffer, MAX_PATH); memcpy(&pFileDirInfo->FileName[0], FileNameBuffer, pFileDirInfo->FileNameLength); #endif
ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_BOTH_DIR_INFORMATION, FileName) + pFileDirInfo->FileNameLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query both directory info failed, %ld."), ulRetCode)); } break;
case RdpFileNamesInformation: if (rc) { PRDP_FILE_NAMES_INFORMATION pFileDirInfo = (PRDP_FILE_NAMES_INFORMATION) Buffer;
pFileDirInfo->NextEntryOffset = 0; pFileDirInfo->FileIndex = 0; pFileDirInfo->FileNameLength = _tcslen(FileData.cFileName) * sizeof(WCHAR); #ifdef UNICODE
memcpy(&pFileDirInfo->FileName[0], FileData.cFileName, pFileDirInfo->FileNameLength); #else
RDPConvertToUnicode(FileData.cFileName, FileNameBuffer, MAX_PATH); memcpy(&pFileDirInfo->FileName[0], FileNameBuffer, pFileDirInfo->FileNameLength); #endif
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_NAMES_INFORMATION) + pFileDirInfo->FileNameLength - sizeof(WCHAR); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query file names failed, %ld."), ulRetCode)); }
break;
default: TRC_ERR((TB, _T("Unsupported QueryDirectory class %x"), pIoRequest->Parameters.QueryDir.FileInformationClass)); ulRetCode = ERROR_INVALID_FUNCTION; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); break; } SendPacket:
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result; pReplyPacket->IoCompletion.Parameters.QueryDir.Length = BufferLength;
if (BufferLength) memcpy(pReplyPacket->IoCompletion.Parameters.QueryDir.Buffer, Buffer, BufferLength);
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup:
//
// Clean up the request packet.
//
delete pIoRequestPacket;
if (pFileName && (DriveLen + PathLen >= MAX_PATH)) { delete pFileName; }
DC_END_FN(); }
VOID W32Drive::MsgIrpDirectoryControl( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Queries the directory information for this drive device.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - length of the packet
Return Value:
NA
--*/ { W32DRDEV_ASYNCIO_PARAMS *params; DrFile* pFile; DWORD status; DC_BEGIN_FN("W32DrDeviceAsync::MsgIrpDirectoryControl");
TRC_NRM((TB, _T("Request Directory Control")));
//
// Leave the query directory in the forground thread as it is
//
if (pIoRequestPacket->IoRequest.MinorFunction == IRP_MN_QUERY_DIRECTORY || pIoRequestPacket->IoRequest.MinorFunction == 0) { MsgIrpQueryDirectory(pIoRequestPacket, packetLen); return; }
//
// Get File Object and reference it
//
pFile = _FileMgr->GetObject(pIoRequestPacket->IoRequest.FileId); if (pFile) { pFile->AddRef(); } else { DefaultIORequestMsgHandle(pIoRequestPacket, STATUS_UNSUCCESSFUL); return; }
//
// Allocate and dispatch an asynchronous IO request.
//
params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket); if (params != NULL ) {
TRC_NRM((TB, _T("Async IO operation")));
status = ProcessObject()->DispatchAsyncIORequest( (RDPAsyncFunc_StartIO)W32Drive::_StartFSFunc, (RDPAsyncFunc_IOComplete)W32DrDeviceAsync::_CompleteIOFunc, (RDPAsyncFunc_IOCancel)W32DrDeviceAsync::_CancelIOFunc, params ); } else { TRC_ERR((TB, _T("Memory alloc failed."))); status = ERROR_NOT_ENOUGH_MEMORY; }
//
// Clean up on error.
//
if (status != ERROR_SUCCESS) { pFile->Release();
if (params != NULL) { delete params; } delete pIoRequestPacket; }
DC_END_FN(); }
DWORD W32Drive::AsyncDirCtrlFunc( IN W32DRDEV_ASYNCIO_PARAMS *params, IN HANDLE cancelEvent ) /*++
Routine Description:
Asynchrous Directory Control Function
Arguments:
params - Context for the IO request.
Return Value:
Always returns 0.
--*/ { PRDPDR_DEVICE_IOREQUEST pIoRequest; DC_BEGIN_FN("W32Drive::AsyncDirCtrlFunc");
//
// Get the IO request pointer
//
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
if (pIoRequest->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) { #if (!defined (OS_WINCE)) || (!defined (WINCE_SDKBUILD))
return AsyncNotifyChangeDir(params, cancelEvent); #else
DrFile* pFile; pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) pFile->Release(); return STATUS_NOT_SUPPORTED; #endif
} else { TRC_ASSERT((FALSE), (TB, _T("Invalid Minor Function: %x"), pIoRequest->MinorFunction)); return ERROR_INVALID_PARAMETER; } }
DWORD W32Drive::_AsyncDirCtrlFunc( IN PVOID params, IN HANDLE cancelEvent ) { return ((W32Drive*)(((W32DRDEV_ASYNCIO_PARAMS *)params)->pObject))->AsyncDirCtrlFunc( (W32DRDEV_ASYNCIO_PARAMS *)params, cancelEvent); }
#if (!defined (OS_WINCE)) || (!defined (WINCE_SDKBUILD))
DWORD W32Drive::AsyncNotifyChangeDir( IN W32DRDEV_ASYNCIO_PARAMS *params, IN HANDLE cancelEvent ) /*++
Routine Description:
Directory change notification Function
Arguments:
params - Context for the IO request.
Return Value:
Always returns 0.
--*/ { DWORD status; ULONG replyPacketSize = 0; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket = NULL; DrFile* pFile; HANDLE FileHandle; HANDLE NotifyHandle; HANDLE waitableEvents[2]; HRESULT hr; DC_BEGIN_FN("W32Drive::AsyncNotifyChangeDir");
//
// Get the IO request pointer
//
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
//
// Get File Object
//
pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) { FileHandle = pFile->GetFileHandle(); NotifyHandle = ((DrFSFile*)pFile)->GetNotifyHandle(); } else { status = ERROR_CANCELLED; TRC_ERR((TB, _T("File object already cancelled"))); goto Cleanup; }
//
// 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;
//
// If we don't yet have a notification handle.
//
if (NotifyHandle == INVALID_HANDLE_VALUE) { TRC_ASSERT((((DrFSFile*)pFile)->GetFileName() != NULL), (TB, _T("FileName is empty")));
//
// Setup the notification handle
//
NotifyHandle = FindFirstChangeNotification(((DrFSFile*)pFile)->GetFileName(), pIoRequest->Parameters.NotifyChangeDir.WatchTree, pIoRequest->Parameters.NotifyChangeDir.CompletionFilter); if (NotifyHandle == INVALID_HANDLE_VALUE) { status = GetLastError(); TRC_ERR((TB, _T("FindFirstChangeNotification: %08X"), status)); goto Cleanup; }
if (((DrFSFile*)pFile)->SetNotifyHandle(NotifyHandle) == FALSE) { FindCloseChangeNotification(NotifyHandle); NotifyHandle = INVALID_HANDLE_VALUE; status = ERROR_CANCELLED; goto Cleanup; } } else { //
// Notification handle already setup. Find next change notification.
//
if (!FindNextChangeNotification(NotifyHandle)) { status = GetLastError(); TRC_ERR((TB, _T("FindNextChangeNotification: %08X"), status)); goto Cleanup; } }
//
// Wait for the cancel or notify event to be signaled.
//
waitableEvents[0] = NotifyHandle; waitableEvents[1] = cancelEvent; status = WaitForMultipleObjects(2, waitableEvents, FALSE, INFINITE); if (status == WAIT_FAILED) { status = GetLastError(); TRC_ERR((TB, _T("Error %ld."), status)); } else if (status == WAIT_OBJECT_0){ status = ERROR_SUCCESS; } else if (status == WAIT_OBJECT_0 + 1) { TRC_ERR((TB, _T("Client got disconnected/logoff"))); status = ERROR_CANCELLED; }
Cleanup: if (pFile) pFile->Release();
DC_END_FN(); return status; } #endif
VOID W32Drive::MsgIrpQueryVolumeInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
This routine handles drive volume level information query 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; TCHAR DeviceName[MAX_PATH + 2]; #ifndef OS_WINCE
TCHAR NameBuffer[MAX_PATH]; WCHAR TempBuffer[MAX_PATH + 1]; #endif
ULONG BufferLength = 0; #ifndef OS_WINCE
DECLSPEC_ALIGN(8) BYTE Buffer[RDP_FILE_VOLUME_INFO_MAXLENGTH + MAX_PATH]; #else
BYTE Buffer[RDP_FILE_VOLUME_INFO_MAXLENGTH + MAX_PATH]; #endif
HRESULT hr;
DC_BEGIN_FN("W32Drive::MsgIrpQueryVolumeInfo");
TRC_ASSERT((_tcslen(_devicePath) != 0), (TB, _T("Empty devicePath")));
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
//
// DriveName needs to end with \ //
#ifndef OS_WINCE
hr = StringCchPrintf(DeviceName, SIZE_TCHARS(DeviceName), TEXT("%s\\"), _devicePath); #else
hr = StringCchPrintf(DeviceName, SIZE_TCHARS(DeviceName), TEXT("\\")); #endif
TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str printf failed for pre-checked len: 0x%x"),hr));
memset(Buffer, 0, sizeof(Buffer));
switch (pIoRequest->Parameters.QueryVolume.FsInformationClass) { case RdpFsVolumeInformation: { RDP_FILE_FS_VOLUME_INFORMATION *pVolumeInfo = (RDP_FILE_FS_VOLUME_INFORMATION *) Buffer; #ifndef OS_WINCE
if (GetVolumeInformation(DeviceName, NameBuffer, MAX_PATH, &pVolumeInfo->VolumeSerialNumber, NULL, NULL, NULL, 0 )) {
pVolumeInfo->VolumeCreationTime.QuadPart = 0; pVolumeInfo->SupportsObjects = FALSE; pVolumeInfo->VolumeLabelLength = _tcslen(NameBuffer) * sizeof(WCHAR); #ifdef UNICODE
memcpy(&pVolumeInfo->VolumeLabel[0], NameBuffer, pVolumeInfo->VolumeLabelLength); #else
RDPConvertToUnicode(NameBuffer, (LPWSTR)TempBuffer, MAX_PATH); memcpy(&pVolumeInfo->VolumeLabel[0], TempBuffer, pVolumeInfo->VolumeLabelLength); #endif
ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_FS_VOLUME_INFORMATION, VolumeLabel) + pVolumeInfo->VolumeLabelLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query volume information failed, %ld."), ulRetCode)); } #else
pVolumeInfo->VolumeCreationTime.QuadPart = 0; pVolumeInfo->SupportsObjects = FALSE; pVolumeInfo->VolumeLabelLength = sizeof(WCHAR); pVolumeInfo->VolumeLabel[0] = L'\0'; pVolumeInfo->VolumeSerialNumber = 0;
ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_FS_VOLUME_INFORMATION, VolumeLabel) + pVolumeInfo->VolumeLabelLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1;
#endif
break; }
case RdpFsSizeInformation: { RDP_FILE_FS_SIZE_INFORMATION *pFsSizeInfo = (RDP_FILE_FS_SIZE_INFORMATION *) Buffer; #ifndef OS_WINCE
if (GetDiskFreeSpace(DeviceName, &pFsSizeInfo->SectorsPerAllocationUnit, &pFsSizeInfo->BytesPerSector, &pFsSizeInfo->AvailableAllocationUnits.LowPart, &pFsSizeInfo->TotalAllocationUnits.LowPart)) { ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_FS_SIZE_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query volume size failed, %ld."), ulRetCode)); } #else
ULARGE_INTEGER FreeBytesAvailableToCaller; if (GetDiskFreeSpaceEx(DeviceName, &FreeBytesAvailableToCaller, (PULARGE_INTEGER)&pFsSizeInfo->AvailableAllocationUnits, (PULARGE_INTEGER)&pFsSizeInfo->TotalAllocationUnits)) { pFsSizeInfo->SectorsPerAllocationUnit = 1; pFsSizeInfo->BytesPerSector = 1; ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_FS_SIZE_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query volume size failed, %ld."), ulRetCode));
} #endif
break; }
case RdpFsFullSizeInformation: { RDP_FILE_FS_FULL_SIZE_INFORMATION *pFsSizeInfo = (RDP_FILE_FS_FULL_SIZE_INFORMATION *) Buffer;
#ifndef OS_WINCE
if (GetDiskFreeSpace(DeviceName, &pFsSizeInfo->SectorsPerAllocationUnit, &pFsSizeInfo->BytesPerSector, &pFsSizeInfo->CallerAvailableAllocationUnits.LowPart, &pFsSizeInfo->TotalAllocationUnits.LowPart)) { //
// TODO what's the difference between actual and caller
// available allocation units?
//
pFsSizeInfo->ActualAvailableAllocationUnits.QuadPart = pFsSizeInfo->CallerAvailableAllocationUnits.QuadPart; ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_FS_FULL_SIZE_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query volume full size failed, %ld."), ulRetCode)); } #else
if (GetDiskFreeSpaceEx(DeviceName, (PULARGE_INTEGER)&pFsSizeInfo->CallerAvailableAllocationUnits, (PULARGE_INTEGER)&pFsSizeInfo->ActualAvailableAllocationUnits, (PULARGE_INTEGER)&pFsSizeInfo->TotalAllocationUnits)) { pFsSizeInfo->SectorsPerAllocationUnit = 1; pFsSizeInfo->BytesPerSector = 1;
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_FS_FULL_SIZE_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query volume size failed, %ld."), ulRetCode));
}
#endif
break; }
case RdpFsAttributeInformation: { RDP_FILE_FS_ATTRIBUTE_INFORMATION *pFsAttribInfo = (RDP_FILE_FS_ATTRIBUTE_INFORMATION *) Buffer;
#ifndef OS_WINCE
if (GetVolumeInformation(DeviceName, NULL, NULL, NULL, (ULONG*)&pFsAttribInfo->MaximumComponentNameLength, &pFsAttribInfo->FileSystemAttributes, NameBuffer, MAX_PATH )) { pFsAttribInfo->FileSystemNameLength = _tcslen(NameBuffer) * sizeof(WCHAR); #ifdef UNICODE
memcpy(&pFsAttribInfo->FileSystemName[0], NameBuffer, pFsAttribInfo->FileSystemNameLength); #else
RDPConvertToUnicode(NameBuffer, (LPWSTR)TempBuffer, MAX_PATH); memcpy(&pFsAttribInfo->FileSystemName[0], TempBuffer, pFsAttribInfo->FileSystemNameLength); #endif
ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) + pFsAttribInfo->FileSystemNameLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query file system attributes failed, %ld."), ulRetCode)); } #else
pFsAttribInfo->MaximumComponentNameLength = MAX_PATH; pFsAttribInfo->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK; wcscpy(&pFsAttribInfo->FileSystemName[0], L"FAT"); pFsAttribInfo->FileSystemNameLength = _tcslen(pFsAttribInfo->FileSystemName) * sizeof(WCHAR); ulRetCode = ERROR_SUCCESS; BufferLength = FIELD_OFFSET(RDP_FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) + pFsAttribInfo->FileSystemNameLength; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1;
#endif
break; } default: TRC_ERR((TB, _T("Unsupported QueryVolume class %x"), pIoRequest->Parameters.QueryVolume.FsInformationClass)); ulRetCode = ERROR_INVALID_FUNCTION; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); break; }
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result; pReplyPacket->IoCompletion.Parameters.QueryVolume.Length = BufferLength;
if (BufferLength) memcpy(pReplyPacket->IoCompletion.Parameters.QueryVolume.Buffer, Buffer, BufferLength);
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup:
//
// Clean up the request packet.
//
delete pIoRequestPacket;
DC_END_FN(); }
VOID W32Drive::MsgIrpSetVolumeInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
This routine sets drive volume information.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; TCHAR DeviceName[MAX_PATH + 2]; PBYTE pDataBuffer; HRESULT hr;
DC_BEGIN_FN("W32Drive::MsgIrpSetVolumeInfo");
TRC_ASSERT((_tcslen(_devicePath) != 0), (TB, _T("Empty devicePath")));
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); //
// DriveName needs to end with \ //
hr = StringCchPrintf(DeviceName, SIZE_TCHARS(DeviceName), TEXT("%s\\"), _devicePath); TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str printf failed for pre-checked len: 0x%x"),hr));
pDataBuffer = (PBYTE)(pIoRequest + 1);
switch (pIoRequest->Parameters.SetVolume.FsInformationClass) { case RdpFsLabelInformation: { PRDP_FILE_FS_LABEL_INFORMATION pLabelInfo = (PRDP_FILE_FS_LABEL_INFORMATION) pDataBuffer; // To conform with the redirector, we will not allow
// user to change the volume label info
ulRetCode = ERROR_ACCESS_DENIED; break;
#if 0
NameBuffer[0] = TEXT('\0');
RDPConvertToAnsi(pLabelInfo->VolumeLabel, NameBuffer, MAX_PATH);
if (SetVolumeLabel(DeviceName, NameBuffer)) { ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("Set Volume label failed, %ld."), ulRetCode)); } #endif
} break; default: TRC_ERR((TB, _T("Unsupported SetVolume class %x"), pIoRequest->Parameters.SetVolume.FsInformationClass)); ulRetCode = ERROR_INVALID_FUNCTION; break; }
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result; pReplyPacket->IoCompletion.Parameters.SetVolume.Length = pIoRequest->Parameters.SetVolume.Length;
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup:
//
// Clean up the request packet.
//
delete pIoRequestPacket;
DC_END_FN(); }
VOID W32Drive::MsgIrpQueryFileInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
This routine handles query file information
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; BOOL rc; ULONG BufferLength = 0; BYTE Buffer[RDP_FILE_INFORMATION_MAXLENGTH]; DrFile* pFile; HANDLE FileHandle = INVALID_HANDLE_VALUE; BY_HANDLE_FILE_INFORMATION FileInformation;
DC_BEGIN_FN("W32Drive::MsgIrpQueryFileInfo");
TRC_ASSERT((_tcslen(_devicePath) != 0), (TB, _T("Empty device path")));
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
memset(Buffer, 0, sizeof(Buffer));
//
// Get file handle
//
pFile = _FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); if (pFile) {
if (!((DrFSFile *)pFile)->IsDirectory()) {
TRC_ASSERT((FileHandle != INVALID_TS_FILEHANDLE), (TB, _T("Invalid FileHandle"))); #ifndef OS_WINCE
rc = GetFileInformationByHandle(FileHandle, &FileInformation); #else
rc = CEGetFileInformationByHandle(FileHandle, &FileInformation); #endif
} else { //
// This is a directory, we can only get attributes info
//
memset(&FileInformation, 0, sizeof(FileInformation));
FileInformation.dwFileAttributes = GetFileAttributes(((DrFSFile*)pFile)->GetFileName());
if (FileInformation.dwFileAttributes != -1) { rc = TRUE; } else { rc = FALSE; } }
switch (pIoRequest->Parameters.QueryFile.FileInformationClass) { case RdpFileBasicInformation: if (rc) { PRDP_FILE_BASIC_INFORMATION pFileInfo = (PRDP_FILE_BASIC_INFORMATION) Buffer;
pFileInfo->CreationTime.LowPart = FileInformation.ftCreationTime.dwLowDateTime; pFileInfo->CreationTime.HighPart = FileInformation.ftCreationTime.dwHighDateTime; pFileInfo->LastAccessTime.LowPart = FileInformation.ftLastAccessTime.dwLowDateTime; pFileInfo->LastAccessTime.HighPart = FileInformation.ftLastAccessTime.dwHighDateTime; pFileInfo->LastWriteTime.LowPart = FileInformation.ftLastWriteTime.dwLowDateTime; pFileInfo->LastWriteTime.HighPart = FileInformation.ftLastWriteTime.dwHighDateTime; pFileInfo->ChangeTime.QuadPart = 0; pFileInfo->FileAttributes = FileInformation.dwFileAttributes;
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_BASIC_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query basic file information failed, %ld."), ulRetCode)); }
break;
case RdpFileStandardInformation: if (rc) { PRDP_FILE_STANDARD_INFORMATION pFileInfo = (PRDP_FILE_STANDARD_INFORMATION) Buffer;
// TODO: AllocationSize same as EndOfFile Size?
pFileInfo->AllocationSize.HighPart = FileInformation.nFileSizeHigh; pFileInfo->AllocationSize.LowPart = FileInformation.nFileSizeLow; pFileInfo->EndOfFile.HighPart = FileInformation.nFileSizeHigh; pFileInfo->EndOfFile.LowPart = FileInformation.nFileSizeLow; pFileInfo->NumberOfLinks = FileInformation.nNumberOfLinks; pFileInfo->DeletePending = 0; pFileInfo->Directory = !!(FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_STANDARD_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query standard file information failed, %ld."), ulRetCode)); }
break;
case RdpFileAttributeTagInformation: if (rc) { PRDP_FILE_ATTRIBUTE_TAG_INFORMATION pFileInfo = (PRDP_FILE_ATTRIBUTE_TAG_INFORMATION) Buffer;
// TODO: What's ReparseTag?
pFileInfo->FileAttributes = FileInformation.dwFileAttributes; pFileInfo->ReparseTag = 0;
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_ATTRIBUTE_TAG_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Query attribute tag file information failed, %ld."), ulRetCode)); }
break;
case RdpFileInternalInformation: if (rc) { PRDP_FILE_INTERNAL_INFORMATION pFileInfo = (PRDP_FILE_INTERNAL_INFORMATION) Buffer;
// TODO: should we use this index number?
pFileInfo->IndexNumber.HighPart = FileInformation.nFileIndexHigh; pFileInfo->IndexNumber.LowPart = FileInformation.nFileIndexLow;
ulRetCode = ERROR_SUCCESS; BufferLength = sizeof(RDP_FILE_INTERNAL_INFORMATION); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("CreateFile failed, %ld."), ulRetCode)); }
break;
default: TRC_ERR((TB, _T("Unsupported QueryFile class %x"), pIoRequest->Parameters.QueryFile.FileInformationClass)); ulRetCode = ERROR_INVALID_FUNCTION; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); break; } } else { ulRetCode = ERROR_FILE_NOT_FOUND; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); }
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ; if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result; pReplyPacket->IoCompletion.Parameters.QueryFile.Length = BufferLength;
if (BufferLength) memcpy(pReplyPacket->IoCompletion.Parameters.QueryFile.Buffer, Buffer, BufferLength);
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup:
//
// Clean up the request packet.
//
delete pIoRequestPacket;
DC_END_FN(); }
VOID W32Drive::MsgIrpSetFileInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
This routine handles set file information Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; PBYTE pDataBuffer; DrFSFile* pFile; HANDLE FileHandle = INVALID_HANDLE_VALUE; HRESULT hr;
DC_BEGIN_FN("W32Drive::MsgIrpSetFileInfo");
TRC_ASSERT((_tcslen(_devicePath) != 0), (TB, _T("Empty devicePath")));
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET);
//
// Make sure packetLen is right
//
if (packetLen < sizeof(RDPDR_IOREQUEST_PACKET) + pIoRequest->Parameters.SetFile.Length) { // VirtualChannelClose
ProcessObject()->GetVCMgr().ChannelClose(); TRC_ASSERT(FALSE, (TB, _T("Packet Length Error"))); goto Cleanup; }
//
// Get file handle
//
pFile = (DrFSFile *)_FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); pDataBuffer = (PBYTE)(pIoRequest + 1);
if (pFile) { switch (pIoRequest->Parameters.SetFile.FileInformationClass) { case RdpFileBasicInformation: { PRDP_FILE_BASIC_INFORMATION pFileInfo = (PRDP_FILE_BASIC_INFORMATION) pDataBuffer; FILETIME CreationTime, LastAccessTime, LastWriteTime; FILETIME *pCreationTime, *pLastAccessTime, *pLastWriteTime; //
// Set the file attributes if the attributes field is nonzero
//
if (pFileInfo->FileAttributes != 0) { TRC_ASSERT((pFile->GetFileName() != NULL), (TB, _T("Empty FileName")));
if (SetFileAttributes(pFile->GetFileName(), pFileInfo->FileAttributes)) {
ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetFileAttributes failed, %ld."), ulRetCode)); } break; }
//
// Set the file time
//
if (pFileInfo->CreationTime.QuadPart != 0) { CreationTime.dwLowDateTime = pFileInfo->CreationTime.LowPart; CreationTime.dwHighDateTime = pFileInfo->CreationTime.HighPart; pCreationTime = &CreationTime; } else{ pCreationTime = NULL; }
if (pFileInfo->LastAccessTime.QuadPart != 0) { LastAccessTime.dwLowDateTime = pFileInfo->LastAccessTime.LowPart; LastAccessTime.dwHighDateTime = pFileInfo->LastAccessTime.HighPart; pLastAccessTime = &LastAccessTime; } else { pLastAccessTime = NULL; }
if (pFileInfo->LastWriteTime.QuadPart != 0) { LastWriteTime.dwLowDateTime = pFileInfo->LastWriteTime.LowPart; LastWriteTime.dwHighDateTime = pFileInfo->LastWriteTime.HighPart; pLastWriteTime = &LastWriteTime; } else { pLastWriteTime = NULL; }
if (FileHandle != INVALID_HANDLE_VALUE) { #ifndef OS_WINCE
if (SetFileTime(FileHandle, pCreationTime, pLastAccessTime, pLastWriteTime)) { #else
if (CESetFileTime(FileHandle, pCreationTime, pLastAccessTime, pLastWriteTime)) { #endif
ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetFileTime failed, %ld."), ulRetCode)); } } else { ulRetCode = ERROR_SUCCESS; TRC_NRM((TB, _T("Can't set filetime for directory"))); } } break;
case RdpFileEndOfFileInformation: { PRDP_FILE_END_OF_FILE_INFORMATION pFileInfo = (PRDP_FILE_END_OF_FILE_INFORMATION) pDataBuffer; LONG OffsetLow; LONG OffsetHigh;
if (FileHandle != INVALID_HANDLE_VALUE) { OffsetLow = pFileInfo->EndOfFile.LowPart; OffsetHigh = pFileInfo->EndOfFile.HighPart;
#ifndef OS_WINCE
if (SetFilePointer(FileHandle, #else
if (CESetFilePointer(FileHandle, #endif
OffsetLow, &OffsetHigh, FILE_BEGIN) != INVALID_SET_FILE_POINTER) { ulRetCode = NO_ERROR; } else { ulRetCode = GetLastError();
if (ulRetCode != NO_ERROR) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetFilePointer failed, %ld."), ulRetCode)); } } if (ulRetCode == NO_ERROR) { #ifndef OS_WINCE
if (SetEndOfFile(FileHandle)) { #else
if (CESetEndOfFile(FileHandle)) { #endif
ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetEndOfFile failed, %ld."), ulRetCode)); } } } else { ulRetCode = ERROR_FILE_NOT_FOUND; TRC_ERR((TB, _T("SetEndOfFile failed, %ld."), ulRetCode)); } } break;
case RdpFileDispositionInformation: { if (pFile->GetFileName()) { if (!pFile->IsDirectory()) { pFile->Close(); if (DeleteFile(pFile->GetFileName())) { ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("DeleteFile failed, %ld."), ulRetCode)); } } else { if (RemoveDirectory(pFile->GetFileName())) { ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("RemoveDirectory failed, %ld."), ulRetCode)); } } } else { ulRetCode = ERROR_FILE_NOT_FOUND; TRC_ERR((TB, _T("DeleteFile/RemoveDirectory failed, %ld."), ulRetCode)); } } break;
case RdpFileRenameInformation: { PRDP_FILE_RENAME_INFORMATION pFileInfo = (PRDP_FILE_RENAME_INFORMATION) pDataBuffer; TCHAR NewFileName[MAX_PATH];
if (pFile->GetFileName()) { pFile->Close();
if (pFileInfo->RootDirectory == 0) { //
// Copy the devicePath, the filename path
// below is relative to our device path
//
#ifndef OS_WINCE
hr = StringCchCopy(NewFileName, SIZE_TCHARS(NewFileName), _devicePath); TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Str copy failed for pre-checked len: 0x%x"),hr));
#else
NewFileName[0] = TEXT('\0'); #endif
} else { // The File name passed to us has already contained
// the root directory path
NewFileName[0] = TEXT('\0'); }
#ifdef UNICODE
UINT cchLenRemain = SIZE_TCHARS(NewFileName) - (_tcslen(NewFileName) + 1); hr = StringCchCopy(NewFileName + _tcslen(NewFileName), cchLenRemain, pFileInfo->FileName); if (FAILED(hr)) { TRC_ERR((TB,_T("Fail to copy filename info: 0x%x"),hr)); ulRetCode = ERROR_INSUFFICIENT_BUFFER; goto SendPacket; }
#else
RDPConvertToAnsi(pFileInfo->FileName, NewFileName + _tcslen(NewFileName), MAX_PATH - _tcslen(NewFileName)); #endif
if (pFileInfo->ReplaceIfExists) { DeleteFile(NewFileName); }
if (MoveFile(pFile->GetFileName(), NewFileName)) { ulRetCode = ERROR_SUCCESS; } else { ulRetCode = GetLastError(); TRC_ERR((TB, _T("MoveFile failed, %ld."), ulRetCode)); } } else { ulRetCode = ERROR_FILE_NOT_FOUND; TRC_ERR((TB, _T("MoveFile failed, %ld."), ulRetCode)); } } break;
case RdpFileAllocationInformation: { PRDP_FILE_ALLOCATION_INFORMATION pFileAllocationInfo = (PRDP_FILE_ALLOCATION_INFORMATION) pDataBuffer;
ulRetCode = ERROR_SUCCESS;
TRC_NRM((TB, _T("Get RdpFileAllocationInformation")));
// If server side call CreateFile with TRUNCATE_EXISTING flag
// server will send FileAllocationInformation with
// AllocationSize.QuadPart is 0, we need to truncate the file
// Currently we don't support other QuadPart value
if (0 == pFileAllocationInfo->AllocationSize.QuadPart) { if (FileHandle != INVALID_HANDLE_VALUE) { if (INVALID_SET_FILE_POINTER != SetFilePointer(FileHandle, 0, 0, FILE_BEGIN)) { if (!SetEndOfFile(FileHandle)) { TRC_ERR((TB, _T("SetEndOfFile failed with %x"), GetLastError())); ulRetCode = GetLastError(); } } else { TRC_ERR((TB, _T("SetFilePointer failed with %x"), GetLastError())); ulRetCode = GetLastError(); } } else { TRC_ERR((TB, _T("File handle invalid in setting FileAllocationInfo"))); ulRetCode = ERROR_FILE_NOT_FOUND; } } else { TRC_ASSERT(FALSE, (TB, _T("Get FileAllocationInformation with unsupported %d"), pFileAllocationInfo->AllocationSize.QuadPart)); // Still return success here to avoid regression
} }
break;
default: TRC_ERR((TB, _T("Unsupported SetFile class %x"), pIoRequest->Parameters.SetFile.FileInformationClass)); ulRetCode = ERROR_INVALID_FUNCTION; break; } } else { ulRetCode = ERROR_FILE_NOT_FOUND; }
SendPacket: //
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result; pReplyPacket->IoCompletion.Parameters.SetFile.Length = pIoRequest->Parameters.SetFile.Length;
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup: //
// Clean up the request packet.
//
delete pIoRequestPacket;
DC_END_FN(); }
VOID W32Drive::MsgIrpDeviceControl( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Handle a file system control request from the server.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { DC_BEGIN_FN("W32Drive::MsgIrpDeviceControl");
DispatchIOCTLDirectlyToDriver(pIoRequestPacket);
DC_END_FN(); }
VOID W32Drive::MsgIrpLockControl( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Handle a file system lock control request from the server.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; DrFSFile* pFile; HANDLE FileHandle; PRDP_LOCK_INFO LockInfo; DC_BEGIN_FN("W32Drive::MsgIrpLockControl");
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
//
// Make sure the packetlength is right
//
if (packetLen < sizeof(RDPDR_IOREQUEST_PACKET) + sizeof(RDP_LOCK_INFO) * pIoRequest->Parameters.Locks.NumLocks) { // Call VirtualChannelClose
ProcessObject()->GetVCMgr().ChannelClose(); TRC_ASSERT(FALSE, (TB, _T("Packet Length Error"))); goto Cleanup; }
//
// Get file lock info
//
LockInfo = (PRDP_LOCK_INFO) (pIoRequest + 1);
//
// Get file handle
//
pFile = (DrFSFile *)_FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE;
TRC_ASSERT((FileHandle != INVALID_HANDLE_VALUE), (TB, _T("Invalid FileHandle")));
ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET);
if (FileHandle != INVALID_HANDLE_VALUE) { switch (pIoRequest->Parameters.Locks.Operation) { //
// Share lock request
//
case RDP_LOWIO_OP_SHAREDLOCK: { OVERLAPPED Overlapped;
Overlapped.hEvent = 0; Overlapped.Internal = 0; Overlapped.InternalHigh = 0; Overlapped.Offset = LockInfo->OffsetLow; Overlapped.OffsetHigh = LockInfo->OffsetHigh; #ifndef OS_WINCE
if (!LockFileEx(FileHandle, #else
if (!CELockFileEx(FileHandle, #endif
(pIoRequest->Parameters.Locks.Flags & SL_FAIL_IMMEDIATELY) ? LOCKFILE_FAIL_IMMEDIATELY : 0, 0, LockInfo->LengthLow, LockInfo->LengthHigh, &Overlapped)) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("Lock File failed, %ld."), ulRetCode)); } break; }
//
// Exclusive lock request
//
case RDP_LOWIO_OP_EXCLUSIVELOCK: #ifndef OS_WINCE
if (!LockFile(FileHandle, #else
if (!CELockFile(FileHandle, #endif
LockInfo->OffsetLow, LockInfo->OffsetHigh, LockInfo->LengthLow, LockInfo->LengthHigh)) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("Lock File failed, %ld."), ulRetCode)); } break;
//
// Unlock request
//
case RDP_LOWIO_OP_UNLOCK: { for (unsigned i = 0; i < pIoRequest->Parameters.Locks.NumLocks; i++) { #ifndef OS_WINCE
if (!UnlockFile(FileHandle, #else
if (!CEUnlockFile(FileHandle, #endif
LockInfo->OffsetLow, LockInfo->OffsetHigh, LockInfo->LengthLow, LockInfo->LengthHigh)) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("Unlock File failed, %ld."), ulRetCode)); break; }
LockInfo++; } break; }
default: ulRetCode = ERROR_INVALID_FUNCTION; TRC_ERR((TB, _T("Invalid lock operation %x"), pIoRequest->Parameters.Locks.Operation)); } } else { ulRetCode = ERROR_FILE_NOT_FOUND; TRC_ERR((TB, _T("Lock File failed, %ld."), ulRetCode)); }
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
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.
//
delete pIoRequestPacket;
DC_END_FN(); }
#ifndef OS_WINCE
BOOL SetPrivilege( HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL fEnablePrivilege // TRUE to enable. FALSE to disable
) { BOOL rc = TRUE; TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); HMODULE hModule = NULL; typedef BOOL (FNLOOKUP_PRIVILEGE_VALUE)(LPCTSTR, LPCTSTR, PLUID); FNLOOKUP_PRIVILEGE_VALUE *pfnLookupPrivilegeValue; typedef BOOL (FNADJUST_TOKEN_PRIVILEGES)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); FNADJUST_TOKEN_PRIVILEGES *pfnAdjustTokenPrivileges;
// get the handle to advapi32.dll library
hModule = LoadLibrary(TEXT("ADVAPI32.DLL")); if (hModule != NULL) { // get the proc address for LookupPrivilegeValue
#ifdef UNICODE
pfnLookupPrivilegeValue = (FNLOOKUP_PRIVILEGE_VALUE *)GetProcAddress(hModule, "LookupPrivilegeValueW"); #else
pfnLookupPrivilegeValue = (FNLOOKUP_PRIVILEGE_VALUE *)GetProcAddress(hModule, "LookupPrivilegeValueA"); #endif
if (pfnLookupPrivilegeValue) { if (!pfnLookupPrivilegeValue(NULL, Privilege, &luid)) { rc = FALSE; goto EXIT; } } else { // Let it return true.
goto EXIT; }
pfnAdjustTokenPrivileges = (FNADJUST_TOKEN_PRIVILEGES *)GetProcAddress(hModule, "AdjustTokenPrivileges");
if (pfnAdjustTokenPrivileges) { //
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0; pfnAdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious); if (GetLastError() != ERROR_SUCCESS) { rc = FALSE; goto EXIT; } //
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; if (fEnablePrivilege) { tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); } else { tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); } pfnAdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL); if (GetLastError() != ERROR_SUCCESS) { rc = FALSE; goto EXIT; } } }
EXIT: if (hModule) { FreeLibrary(hModule); } return rc; } #endif
VOID W32Drive::MsgIrpQuerySdInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Handle a file system control request from the server.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; DrFSFile* pFile; HANDLE FileHandle; BYTE* pSecurityDescriptor = NULL; ULONG LengthNeeded = 0; ULONG BufferLength = 0; HANDLE hProcessToken = NULL; HMODULE hModule = NULL; DC_BEGIN_FN("W32Drive::MsgIrpQuerySd");
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
//
// Get file handle
//
pFile = (DrFSFile *)_FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE;
if (pFile) { #ifndef OS_WINCE
if (pIoRequest->Parameters.QuerySd.SecurityInformation & SACL_SECURITY_INFORMATION) { typedef BOOL (FNOPEN_PROCESS_TOKEN)(HANDLE, DWORD, PHANDLE); FNOPEN_PROCESS_TOKEN *pfnOpenProcessToken; // get the handle to advapi32.dll library
hModule = LoadLibrary(TEXT("ADVAPI32.DLL")); if (hModule != NULL) { // get the proc address for OpenProcessToken
pfnOpenProcessToken = (FNOPEN_PROCESS_TOKEN *)GetProcAddress(hModule, "OpenProcessToken"); if (pfnOpenProcessToken) { //
// Get the process token for this process. We'll
// need it in just a second ....
//
if (!pfnOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("OpenProcessToken failed, error %d."), ulRetCode)); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); goto SendPacket; } //
// Turn on SeSecurityPrivilege (by name that's SE_SECURITY_NAME). This allows
// us to read SACLs
//
if (!SetPrivilege(hProcessToken, SE_SECURITY_NAME, TRUE)) { ulRetCode = GetLastError(); TRC_ERR((TB, _T("SetPrivilege failed. %d."), ulRetCode)); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); goto SendPacket; } } } }
GetFileSecurity(pFile->GetFileName(), pIoRequest->Parameters.QuerySd.SecurityInformation, NULL, 0, &LengthNeeded);
if (LengthNeeded > 0) { pSecurityDescriptor = new BYTE[LengthNeeded]; if (pSecurityDescriptor != NULL) { if (GetFileSecurity(pFile->GetFileName(), pIoRequest->Parameters.QuerySd.SecurityInformation, pSecurityDescriptor, LengthNeeded, &LengthNeeded)) { BufferLength = GetSecurityDescriptorLength( (PSECURITY_DESCRIPTOR)pSecurityDescriptor); ulRetCode = ERROR_SUCCESS; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("GetFileSecurity failed, %ld."), ulRetCode)); } } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Failed to allocate memory for security descriptor"))); } } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("GetFileSecurity failed, %ld."), ulRetCode)); } #else
BYTE bSecDescr[sizeof(SECURITY_DESCRIPTOR) + (2*sizeof(SID))]; BufferLength = sizeof(bSecDescr); pSecurityDescriptor = bSecDescr;
SECURITY_DESCRIPTOR sd; if (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) && SetSecurityDescriptorGroup(&sd, NULL, FALSE) && SetSecurityDescriptorOwner(&sd, NULL, FALSE) && SetSecurityDescriptorDacl(&sd, (pIoRequest->Parameters.QuerySd.SecurityInformation & DACL_SECURITY_INFORMATION), NULL, FALSE) && SetSecurityDescriptorSacl(&sd, (pIoRequest->Parameters.QuerySd.SecurityInformation & SACL_SECURITY_INFORMATION), NULL, FALSE) && MakeSelfRelativeSD(&sd, pSecurityDescriptor, &BufferLength)) { ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) + BufferLength - 1; ulRetCode = ERROR_SUCCESS; } else { ulRetCode = ERROR_INVALID_PARAMETER; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Failed to construct a security descriptor, %ld."), ulRetCode)); } #endif
} else { ulRetCode = ERROR_FILE_NOT_FOUND; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); }
SendPacket:
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
result = TranslateWinError(ulRetCode);
pReplyPacket->IoCompletion.IoStatus = result;
pReplyPacket->IoCompletion.Parameters.QuerySd.Length = BufferLength;
if (BufferLength) memcpy(pReplyPacket->IoCompletion.Parameters.QuerySd.Buffer, pSecurityDescriptor, BufferLength);
ProcessObject()->GetVCMgr().ChannelWrite( (PVOID)pReplyPacket, (UINT)ulReplyPacketSize); } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes."),ulReplyPacketSize)); }
Cleanup:
//
// Clean up the request packet.
//
delete pIoRequestPacket;
#ifndef OS_WINCE
//
// Clean up the security descriptor buffer
//
if (pSecurityDescriptor != NULL) { delete pSecurityDescriptor; } #endif
if (hModule) { FreeLibrary(hModule); }
if (hProcessToken) { CloseHandle(hProcessToken); }
DC_END_FN(); }
VOID W32Drive::MsgIrpSetSdInfo( IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket, IN UINT32 packetLen ) /*++
Routine Description:
Handle a file system set security request from the server.
Arguments:
pIoRequestPacket - Server IO request packet. packetLen - Length of the packet
Return Value:
NA
--*/ { ULONG ulRetCode = ERROR_SUCCESS; DWORD result; PRDPDR_DEVICE_IOREQUEST pIoRequest; PRDPDR_IOCOMPLETION_PACKET pReplyPacket; ULONG ulReplyPacketSize = 0; DrFSFile* pFile; HANDLE FileHandle; #ifndef OS_WINCE
PSECURITY_DESCRIPTOR SecurityDescriptor; #endif
DC_BEGIN_FN("W32Drive::MsgIrpQuerySd");
//
// Get IO request pointer.
//
pIoRequest = &pIoRequestPacket->IoRequest;
//
// Make sure the packetLen is right
//
if (packetLen < sizeof(RDPDR_IOREQUEST_PACKET) + pIoRequest->Parameters.SetSd.Length) { // VirtualChannelClose
ProcessObject()->GetVCMgr().ChannelClose(); TRC_ASSERT(FALSE, (TB, _T("Packet Length Error"))); goto Cleanup; }
//
// Get file handle
//
pFile = (DrFSFile *)_FileMgr->GetObject(pIoRequest->FileId); if (pFile) FileHandle = pFile->GetFileHandle(); else FileHandle = INVALID_HANDLE_VALUE;
#ifndef OS_WINCE
//
// Set the file security
//
SecurityDescriptor = (PSECURITY_DESCRIPTOR)(pIoRequest + 1); #endif
if (pFile) { #ifndef OS_WINCE
if (SetFileSecurity(pFile->GetFileName(), pIoRequest->Parameters.SetSd.SecurityInformation, SecurityDescriptor)) { ulRetCode = ERROR_SUCCESS; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET) ; } else { ulRetCode = GetLastError(); ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); TRC_ERR((TB, _T("Lock File failed, %ld."), ulRetCode)); } #else
ulRetCode = ERROR_SUCCESS; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); #endif
} else { ulRetCode = ERROR_FILE_NOT_FOUND; ulReplyPacketSize = sizeof(RDPDR_IOCOMPLETION_PACKET); }
//
// Allocate reply buffer.
//
pReplyPacket = DrUTL_AllocIOCompletePacket(pIoRequestPacket, ulReplyPacketSize) ;
if (pReplyPacket) { //
// Send the result to the server.
//
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.
//
delete pIoRequestPacket;
DC_END_FN(); }
|