return 0;
}
- RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
+ static void rdpdr_server_write_device_iorequest(
+ wStream* s,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId,
+ UINT32 majorFunction,
+ UINT32 minorFunction
+ )
{
- RdpdrServerContext* context;
- context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext));
+ Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
+ Stream_Write_UINT16(s, PAKID_CORE_DEVICE_IOREQUEST); /* PacketId (2 bytes) */
+ Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */
+ Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */
+ Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */
+ Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */
+ }
- if (context)
- {
- ZeroMemory(context, sizeof(RdpdrServerContext));
- context->vcm = vcm;
- context->Start = rdpdr_server_start;
- context->Stop = rdpdr_server_stop;
- context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate));
+ static BOOL rdpdr_server_read_file_directory_information(wStream* s, FILE_DIRECTORY_INFORMATION* fdi)
+ {
+ UINT32 fileNameLength;
- if (context->priv)
- {
- ZeroMemory(context->priv, sizeof(RdpdrServerPrivate));
- context->priv->VersionMajor = RDPDR_VERSION_MAJOR;
- context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
- context->priv->ClientId = g_ClientId++;
- context->priv->UserLoggedOnPdu = TRUE;
- }
- }
+ ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION));
- return context;
+ Stream_Read_UINT32(s, fdi->NextEntryOffset); /* NextEntryOffset (4 bytes) */
+ Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */
+ Stream_Read_UINT64(s, fdi->CreationTime); /* CreationTime (8 bytes) */
+ Stream_Read_UINT64(s, fdi->LastAccessTime); /* LastAccessTime (8 bytes) */
+ Stream_Read_UINT64(s, fdi->LastWriteTime); /* LastWriteTime (8 bytes) */
+ Stream_Read_UINT64(s, fdi->ChangeTime); /* ChangeTime (8 bytes) */
+ Stream_Read_UINT64(s, fdi->EndOfFile); /* EndOfFile (8 bytes) */
+ Stream_Read_UINT64(s, fdi->AllocationSize); /* AllocationSize (8 bytes) */
+ Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */
+ Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */
+
+ WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) Stream_Pointer(s), fileNameLength / 2, fdi->FileName, sizeof(fdi->FileName), NULL, NULL);
+ Stream_Seek(s, fileNameLength);
+
+ return TRUE;
}
- void rdpdr_server_context_free(RdpdrServerContext* context)
+ static BOOL rdpdr_server_send_device_create_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 completionId,
+ const char* path,
+ UINT32 desiredAccess,
+ UINT32 createOptions,
+ UINT32 createDisposition
+ )
{
- if (context)
- {
- free(context->priv);
- free(context);
- }
+ int pathLength;
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, path=%s, desiredAccess=0x%x createOptions=0x%x createDisposition=0x%x",
+ __FUNCTION__, deviceId, path, desiredAccess, createOptions, createDisposition);
+
+ /* Compute the required Unicode size. */
+ pathLength = (strlen(path) + 1) * sizeof(WCHAR);
+
+ s = Stream_New(NULL, 256 + pathLength);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, 0);
+
+ Stream_Write_UINT32(s, desiredAccess); /* DesiredAccess (4 bytes) */
+ Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */
+ Stream_Write_UINT32(s, 0);
+ Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */
+ Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */
+ Stream_Write_UINT32(s, createDisposition); /* CreateDisposition (4 bytes) */
+ Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */
+ Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */
+
+ /* Convert the path to Unicode. */
+ MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), pathLength);
+ Stream_Seek(s, pathLength);
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
+ }
+
+ static BOOL rdpdr_server_send_device_close_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId
+ )
+ {
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, fileId=%d", __FUNCTION__, deviceId, fileId);
+
+ s = Stream_New(NULL, 128);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_CLOSE, 0);
+
+ Stream_Zero(s, 32); /* Padding (32 bytes) */
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
+ }
+
+ static BOOL rdpdr_server_send_device_read_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId,
+ UINT32 length,
+ UINT32 offset
+ )
+ {
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, fileId=%d, length=%d, offset=%d", __FUNCTION__, deviceId, fileId, length, offset);
+
+ s = Stream_New(NULL, 128);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_READ, 0);
+
+ Stream_Write_UINT32(s, length); /* Length (4 bytes) */
+ Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
+ Stream_Write_UINT32(s, 0);
+ Stream_Zero(s, 20); /* Padding (20 bytes) */
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
}
+
+ static BOOL rdpdr_server_send_device_write_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId,
+ const char* data,
+ UINT32 length,
+ UINT32 offset
+ )
+ {
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, fileId=%d, length=%d, offset=%d", __FUNCTION__, deviceId, fileId, length, offset);
+
+ s = Stream_New(NULL, 64 + length);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_WRITE, 0);
+
+ Stream_Write_UINT32(s, length); /* Length (4 bytes) */
+ Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
+ Stream_Write_UINT32(s, 0);
+ Stream_Zero(s, 20); /* Padding (20 bytes) */
+ Stream_Write(s, data, length); /* WriteData (variable) */
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
+ }
+
+ static BOOL rdpdr_server_send_device_query_directory_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId,
+ const char* path
+ )
+ {
+ int pathLength;
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, fileId=%d, path=%s", __FUNCTION__, deviceId, fileId, path);
+
+ /* Compute the required Unicode size. */
+ pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
+
+ s = Stream_New(NULL, 64 + pathLength);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY);
+
+ Stream_Write_UINT32(s, FileDirectoryInformation); /* FsInformationClass (4 bytes) */
+ Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */
+ Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */
+ Stream_Zero(s, 23); /* Padding (23 bytes) */
+
+ /* Convert the path to Unicode. */
+ if (pathLength > 0)
+ {
+ MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), pathLength);
+ Stream_Seek(s, pathLength);
+ }
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
+ }
+
+ static BOOL rdpdr_server_send_device_file_rename_request(
+ RdpdrServerContext* context,
+ UINT32 deviceId,
+ UINT32 fileId,
+ UINT32 completionId,
+ const char* path
+ )
+ {
+ int pathLength;
+ ULONG written;
+ BOOL status;
+ wStream* s;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, fileId=%d, path=%s", __FUNCTION__, deviceId, fileId, path);
+
+ /* Compute the required Unicode size. */
+ pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
+
+ s = Stream_New(NULL, 64 + pathLength);
+
+ rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_SET_INFORMATION, 0);
+
+ Stream_Write_UINT32(s, FileRenameInformation); /* FsInformationClass (4 bytes) */
+ Stream_Write_UINT32(s, pathLength + 6); /* Length (4 bytes) */
+ Stream_Zero(s, 24); /* Padding (24 bytes) */
+
+ /* RDP_FILE_RENAME_INFORMATION */
+ Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */
+ Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */
+ Stream_Write_UINT32(s, pathLength); /* FileNameLength (4 bytes) */
+
+ /* Convert the path to Unicode. */
+ if (pathLength > 0)
+ {
+ MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), pathLength);
+ Stream_Seek(s, pathLength);
+ }
+
+ Stream_SealLength(s);
+
+ status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
+
+ Stream_Free(s, TRUE);
+
+ return status;
+ }
+
+ static void rdpdr_server_convert_slashes(char* path, int size)
+ {
+ int i;
+
+ for (i = 0; (i < size) && (path[i] != '\0'); i++)
+ {
+ if (path[i] == '/')
+ path[i] = '\\';
+ }
+ }
+
+ /*************************************************
+ * Drive Create Directory
+ ************************************************/
+
+ static void rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ /* Invoke the create directory completion routine. */
+ context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static void rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+ UINT8 information;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ if (ioStatus != STATUS_SUCCESS)
+ {
+ /* Invoke the create directory completion routine. */
+ context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+
+ return;
+ }
+
+ Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Read_UINT8(s, information); /* Information (1 byte) */
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_create_directory_callback2;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to close the file */
+ rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
+ }
+
+ static BOOL rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* path)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_create_directory_callback1;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, path, sizeof(irp->PathName));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the file. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ FILE_READ_DATA | SYNCHRONIZE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_CREATE);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Delete Directory
+ ************************************************/
+
+ static void rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ /* Invoke the delete directory completion routine. */
+ context->OnDriveDeleteDirectoryComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static void rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+ UINT8 information;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ if (ioStatus != STATUS_SUCCESS)
+ {
+ /* Invoke the delete directory completion routine. */
+ context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+
+ return;
+ }
+
+ Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Read_UINT8(s, information); /* Information (1 byte) */
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_delete_directory_callback2;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to close the file */
+ rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
+ }
+
+ static BOOL rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* path)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_delete_directory_callback1;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, path, sizeof(irp->PathName));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the file. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ DELETE | SYNCHRONIZE,
+ FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_OPEN);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Query Directory
+ ************************************************/
+
+ static void rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ FILE_DIRECTORY_INFORMATION fdi;
+ UINT32 length;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ Stream_Read_UINT32(s, length); /* Length (4 bytes) */
+
+ if (length > 0)
+ {
+ rdpdr_server_read_file_directory_information(s, &fdi);
+ }
+ else
+ {
+ Stream_Seek(s, 1); /* Padding (1 byte) */
+ }
+
+ if (ioStatus == STATUS_SUCCESS)
+ {
+ /* Invoke the query directory completion routine. */
+ context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, length > 0 ? &fdi : NULL);
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_query_directory_callback2;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to query the directory. */
+ rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, irp->FileId, irp->CompletionId, NULL);
+ }
+ else
+ {
+ /* Invoke the query directory completion routine. */
+ context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+ }
+
+ static void rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ if (ioStatus != STATUS_SUCCESS)
+ {
+ /* Invoke the query directory completion routine. */
+ context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+
+ return;
+ }
+
+ Stream_Read_UINT32(s, fileId);
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_query_directory_callback2;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ strcat(irp->PathName, "\\*.*");
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to query the directory. */
+ rdpdr_server_send_device_query_directory_request(context, deviceId, fileId, irp->CompletionId, irp->PathName);
+ }
+
+ static BOOL rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* path)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_query_directory_callback1;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, path, sizeof(irp->PathName));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the directory. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ FILE_READ_DATA | SYNCHRONIZE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_OPEN);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Open File
+ ************************************************/
+
+ static void rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+ UINT8 information;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Read_UINT8(s, information); /* Information (1 byte) */
+
+ /* Invoke the open file completion routine. */
+ context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, fileId);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static BOOL rdpdr_server_drive_open_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* path, UINT32 desiredAccess, UINT32 createDisposition)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_open_file_callback;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, path, sizeof(irp->PathName));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the file. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ desiredAccess | SYNCHRONIZE,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ createDisposition);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Read File
+ ************************************************/
+
+ static void rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 length;
+ char* buffer = NULL;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ Stream_Read_UINT32(s, length); /* Length (4 bytes) */
+ if (length > 0)
+ {
+ buffer = (char*) Stream_Pointer(s);
+ Stream_Seek(s, length);
+ }
+
+ /* Invoke the read file completion routine. */
+ context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, length);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static BOOL rdpdr_server_drive_read_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, UINT32 fileId, UINT32 length, UINT32 offset)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_read_file_callback;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the directory. */
+ rdpdr_server_send_device_read_request(context, deviceId, fileId, irp->CompletionId, length, offset);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Write File
+ ************************************************/
+
+ static void rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 length;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ Stream_Read_UINT32(s, length); /* Length (4 bytes) */
+ Stream_Seek(s, 1); /* Padding (1 byte) */
+
+ /* Invoke the write file completion routine. */
+ context->OnDriveWriteFileComplete(context, irp->CallbackData, ioStatus, length);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static BOOL rdpdr_server_drive_write_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, UINT32 fileId, const char* buffer, UINT32 length, UINT32 offset)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_write_file_callback;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the directory. */
+ rdpdr_server_send_device_write_request(context, deviceId, fileId, irp->CompletionId, buffer, length, offset);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Close File
+ ************************************************/
+
+ static void rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ /* Invoke the close file completion routine. */
+ context->OnDriveCloseFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static BOOL rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, UINT32 fileId)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_close_file_callback;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the directory. */
+ rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Delete File
+ ************************************************/
+
+ static void rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ /* Invoke the delete file completion routine. */
+ context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static void rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+ UINT8 information;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ if (ioStatus != STATUS_SUCCESS)
+ {
+ /* Invoke the close file completion routine. */
+ context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+
+ return;
+ }
+
+ Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Read_UINT8(s, information); /* Information (1 byte) */
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_delete_file_callback2;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to close the file */
+ rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
+ }
+
+ static BOOL rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* path)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_delete_file_callback1;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, path, sizeof(irp->PathName));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the file. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ FILE_READ_DATA | SYNCHRONIZE,
+ FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_OPEN);
+
+ return TRUE;
+ }
+
+ /*************************************************
+ * Drive Rename File
+ ************************************************/
+
+ static void rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+ }
+
+ static void rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 length;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ Stream_Read_UINT32(s, length); /* Length (4 bytes) */
+ Stream_Seek(s, 1); /* Padding (1 byte) */
+
+ /* Invoke the rename file completion routine. */
+ context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_rename_file_callback3;
+ irp->DeviceId = deviceId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to close the file */
+ rdpdr_server_send_device_close_request(context, deviceId, irp->FileId, irp->CompletionId);
+ }
+
+ static void rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus)
+ {
+ UINT32 fileId;
+ UINT8 information;
+
+ WLog_DBG(TAG, "%s: deviceId=%d, completionId=%d, ioStatus=0x%x", __FUNCTION__, deviceId, completionId, ioStatus);
+
+ if (ioStatus != STATUS_SUCCESS)
+ {
+ /* Invoke the rename file completion routine. */
+ context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
+
+ /* Destroy the IRP. */
+ rdpdr_server_irp_free(irp);
+
+ return;
+ }
+
+ Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */
+ Stream_Read_UINT8(s, information); /* Information (1 byte) */
+
+ printf("%s: FileId=%u\n", __FUNCTION__, fileId); fflush(stdout);
+
+ /* Setup the IRP. */
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_rename_file_callback2;
+ irp->DeviceId = deviceId;
+ irp->FileId = fileId;
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to rename the file */
+ rdpdr_server_send_device_file_rename_request(context, deviceId, fileId, irp->CompletionId, irp->ExtraBuffer);
+ }
+
+ static BOOL rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* callbackData, UINT32 deviceId, const char* oldPath, const char* newPath)
+ {
+ RDPDR_IRP* irp;
+
+ /* Create an IRP. */
+ irp = rdpdr_server_irp_new();
+ if (irp == NULL) return FALSE;
+
+ irp->CompletionId = context->priv->NextCompletionId++;
+ irp->Callback = rdpdr_server_drive_rename_file_callback1;
+ irp->CallbackData = callbackData;
+ irp->DeviceId = deviceId;
+ strncpy(irp->PathName, oldPath, sizeof(irp->PathName));
+ strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer));
+
+ rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
+ rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer));
+
+ printf("PathName=%s\n", irp->PathName); fflush(stdout);
+ printf("ExtraBuffer=%s\n", irp->ExtraBuffer); fflush(stdout);
+
+ rdpdr_server_enqueue_irp(context, irp);
+
+ /* Send a request to open the file. */
+ rdpdr_server_send_device_create_request(
+ context, deviceId, irp->CompletionId, irp->PathName,
+ FILE_READ_DATA | SYNCHRONIZE,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_OPEN);
+
+ return TRUE;
+ }
+
+ RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
+ {
+ RdpdrServerContext* context;
+ context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext));
+
+ if (context)
+ {
+ ZeroMemory(context, sizeof(RdpdrServerContext));
+
+ context->vcm = vcm;
+
+ context->Start = rdpdr_server_start;
+ context->Stop = rdpdr_server_stop;
+
+ context->DriveCreateDirectory = rdpdr_server_drive_create_directory;
+ context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory;
+ context->DriveQueryDirectory = rdpdr_server_drive_query_directory;
+ context->DriveOpenFile = rdpdr_server_drive_open_file;
+ context->DriveReadFile = rdpdr_server_drive_read_file;
+ context->DriveWriteFile = rdpdr_server_drive_write_file;
+ context->DriveCloseFile = rdpdr_server_drive_close_file;
+ context->DriveDeleteFile = rdpdr_server_drive_delete_file;
+ context->DriveRenameFile = rdpdr_server_drive_rename_file;
+
+ context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate));
+
+ if (context->priv)
+ {
+ ZeroMemory(context->priv, sizeof(RdpdrServerPrivate));
+ context->priv->VersionMajor = RDPDR_VERSION_MAJOR;
+ context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
+ context->priv->ClientId = g_ClientId++;
+ context->priv->UserLoggedOnPdu = TRUE;
+
+ context->priv->IrpList = ListDictionary_New(TRUE);
+ context->priv->NextCompletionId = 1;
+ }
+ }
+
+ return context;
+ }
+
+ void rdpdr_server_context_free(RdpdrServerContext* context)
+ {
+ if (context)
+ {
+ if (context->priv)
+ {
+ ListDictionary_Free(context->priv->IrpList);
+
+ free(context->priv);
+ }
+
+ free(context);
+ }
+ }
++