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.
2977 lines
92 KiB
2977 lines
92 KiB
/*++
|
|
|
|
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();
|
|
}
|
|
|