Blame channels/drive/client/drive_main.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * File System Virtual Channel
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/file.h>
Packit 1fb8d4
#include <winpr/string.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/thread.h>
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
#include <winpr/environment.h>
Packit 1fb8d4
#include <winpr/interlocked.h>
Packit 1fb8d4
#include <winpr/collections.h>
Packit 1fb8d4
#include <winpr/shell.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/channels/rdpdr.h>
Packit 1fb8d4
Packit 1fb8d4
#include "drive_file.h"
Packit 1fb8d4
Packit 1fb8d4
typedef struct _DRIVE_DEVICE DRIVE_DEVICE;
Packit 1fb8d4
Packit 1fb8d4
struct _DRIVE_DEVICE
Packit 1fb8d4
{
Packit 1fb8d4
	DEVICE device;
Packit 1fb8d4
Packit 1fb8d4
	WCHAR* path;
Packit 1fb8d4
	BOOL automount;
Packit 1fb8d4
	UINT32 PathLength;
Packit 1fb8d4
	wListDictionary* files;
Packit 1fb8d4
Packit 1fb8d4
	HANDLE thread;
Packit 1fb8d4
	wMessageQueue* IrpQueue;
Packit 1fb8d4
Packit 1fb8d4
	DEVMAN* devman;
Packit 1fb8d4
Packit 1fb8d4
	rdpContext* rdpcontext;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static UINT sys_code_page = 0;
Packit 1fb8d4
Packit 1fb8d4
static DWORD drive_map_windows_err(DWORD fs_errno)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD rc;
Packit 1fb8d4
Packit 1fb8d4
	/* try to return NTSTATUS version of error code */
Packit 1fb8d4
Packit 1fb8d4
	switch (fs_errno)
Packit 1fb8d4
	{
Packit 1fb8d4
		case STATUS_SUCCESS:
Packit 1fb8d4
			rc = STATUS_SUCCESS;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_ACCESS_DENIED:
Packit 1fb8d4
		case ERROR_SHARING_VIOLATION:
Packit 1fb8d4
			rc = STATUS_ACCESS_DENIED;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_FILE_NOT_FOUND:
Packit 1fb8d4
			rc = STATUS_NO_SUCH_FILE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_BUSY_DRIVE:
Packit 1fb8d4
			rc = STATUS_DEVICE_BUSY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_INVALID_DRIVE:
Packit 1fb8d4
			rc = STATUS_NO_SUCH_DEVICE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_NOT_READY:
Packit 1fb8d4
			rc = STATUS_NO_SUCH_DEVICE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_FILE_EXISTS:
Packit 1fb8d4
		case ERROR_ALREADY_EXISTS:
Packit 1fb8d4
			rc  = STATUS_OBJECT_NAME_COLLISION;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_INVALID_NAME:
Packit 1fb8d4
			rc = STATUS_NO_SUCH_FILE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_INVALID_HANDLE:
Packit 1fb8d4
			rc = STATUS_INVALID_HANDLE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_NO_MORE_FILES:
Packit 1fb8d4
			rc = STATUS_NO_MORE_FILES;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_DIRECTORY:
Packit 1fb8d4
			rc = STATUS_NOT_A_DIRECTORY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_PATH_NOT_FOUND:
Packit 1fb8d4
			rc = STATUS_OBJECT_PATH_NOT_FOUND;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			rc = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
			WLog_ERR(TAG, "Error code not found: %"PRIu32"", fs_errno);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file = NULL;
Packit 1fb8d4
	void* key = (void*)(size_t) id;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	file = (DRIVE_FILE*) ListDictionary_GetItemValue(drive->files, key);
Packit 1fb8d4
	return file;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 FileId;
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	BYTE Information;
Packit 1fb8d4
	UINT32 FileAttributes;
Packit 1fb8d4
	UINT32 SharedAccess;
Packit 1fb8d4
	UINT32 DesiredAccess;
Packit 1fb8d4
	UINT32 CreateDisposition;
Packit 1fb8d4
	UINT32 CreateOptions;
Packit 1fb8d4
	UINT32 PathLength;
Packit 1fb8d4
	UINT64 allocationSize;
Packit 1fb8d4
	const WCHAR* path;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->devman || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 6 * 4 + 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, DesiredAccess);
Packit 1fb8d4
	Stream_Read_UINT64(irp->input, allocationSize);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FileAttributes);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, SharedAccess);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, CreateDisposition);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, CreateOptions);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, PathLength);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < PathLength)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	path = (WCHAR*) Stream_Pointer(irp->input);
Packit 1fb8d4
	FileId = irp->devman->id_sequence++;
Packit 1fb8d4
	file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition,
Packit 1fb8d4
	                      CreateOptions, FileAttributes, SharedAccess);
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
		FileId = 0;
Packit 1fb8d4
		Information = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		void* key = (void*)(size_t) file->id;
Packit 1fb8d4
Packit 1fb8d4
		if (!ListDictionary_Add(drive->files, key, file))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "ListDictionary_Add failed!");
Packit 1fb8d4
			return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		switch (CreateDisposition)
Packit 1fb8d4
		{
Packit 1fb8d4
			case FILE_SUPERSEDE:
Packit 1fb8d4
			case FILE_OPEN:
Packit 1fb8d4
			case FILE_CREATE:
Packit 1fb8d4
			case FILE_OVERWRITE:
Packit 1fb8d4
				Information = FILE_SUPERSEDED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OPEN_IF:
Packit 1fb8d4
				Information = FILE_OPENED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OVERWRITE_IF:
Packit 1fb8d4
				Information = FILE_OVERWRITTEN;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				Information = 0;
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(irp->output, FileId);
Packit 1fb8d4
	Stream_Write_UINT8(irp->output, Information);
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	void* key;
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->Complete || !irp->output)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
	key = (void*)(size_t) irp->FileId;
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		ListDictionary_Remove(drive->files, key);
Packit 1fb8d4
Packit 1fb8d4
		if (drive_file_free(file))
Packit 1fb8d4
			irp->IoStatus = STATUS_SUCCESS;
Packit 1fb8d4
		else
Packit 1fb8d4
			irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Zero(irp->output, 5); /* Padding(5) */
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	UINT32 Length;
Packit 1fb8d4
	UINT64 Offset;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->output || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 12)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, Length);
Packit 1fb8d4
	Stream_Read_UINT64(irp->input, Offset);
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
		Length = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_seek(file, Offset))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
		Length = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (Length == 0)
Packit 1fb8d4
		Stream_Write_UINT32(irp->output, 0);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		BYTE* buffer = Stream_Pointer(irp->output) + sizeof(UINT32);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive_file_read(file, buffer, &Length))
Packit 1fb8d4
		{
Packit 1fb8d4
			irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
			Stream_Write_UINT32(irp->output, 0);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Write_UINT32(irp->output, Length);
Packit 1fb8d4
			Stream_Seek(irp->output, Length);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	UINT32 Length;
Packit 1fb8d4
	UINT64 Offset;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 32)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, Length);
Packit 1fb8d4
	Stream_Read_UINT64(irp->input, Offset);
Packit 1fb8d4
	Stream_Seek(irp->input, 20); /* Padding */
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
		Length = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_seek(file, Offset))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
		Length = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_write(file, Stream_Pointer(irp->input), Length))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
		Length = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(irp->output, Length);
Packit 1fb8d4
	Stream_Write_UINT8(irp->output, 0); /* Padding */
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	UINT32 FsInformationClass;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FsInformationClass);
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_query_information(file, FsInformationClass, irp->output))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	UINT32 FsInformationClass;
Packit 1fb8d4
	UINT32 Length;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 32)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FsInformationClass);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, Length);
Packit 1fb8d4
	Stream_Seek(irp->input, 24); /* Padding */
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_set_information(file, FsInformationClass, Length,
Packit 1fb8d4
	                                     irp->input))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
Packit 1fb8d4
		irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(irp->output, Length);
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
Packit 1fb8d4
        IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 FsInformationClass;
Packit 1fb8d4
	wStream* output = NULL;
Packit 1fb8d4
	char* volumeLabel = {"FREERDP"};
Packit 1fb8d4
	char* diskType = {"FAT32"};
Packit 1fb8d4
	WCHAR* outStr = NULL;
Packit 1fb8d4
	int length;
Packit 1fb8d4
	DWORD lpSectorsPerCluster;
Packit 1fb8d4
	DWORD lpBytesPerSector;
Packit 1fb8d4
	DWORD lpNumberOfFreeClusters;
Packit 1fb8d4
	DWORD lpTotalNumberOfClusters;
Packit 1fb8d4
	WIN32_FILE_ATTRIBUTE_DATA wfad;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	output = irp->output;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FsInformationClass);
Packit 1fb8d4
	GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
Packit 1fb8d4
	                  &lpTotalNumberOfClusters);
Packit 1fb8d4
Packit 1fb8d4
	switch (FsInformationClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		case FileFsVolumeInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232108.aspx */
Packit 1fb8d4
			if ((length = ConvertToUnicode(sys_code_page, 0, volumeLabel, -1, &outStr, 0) * 2) <= 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "ConvertToUnicode failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 17 + length); /* Length */
Packit 1fb8d4
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 17 + length))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				free(outStr);
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
Packit 1fb8d4
			Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* VolumeLabelLength */
Packit 1fb8d4
			Stream_Write_UINT8(output, 0); /* SupportsObjects */
Packit 1fb8d4
			/* Reserved(1), MUST NOT be added! */
Packit 1fb8d4
			Stream_Write(output, outStr, length); /* VolumeLabel (Unicode) */
Packit 1fb8d4
			free(outStr);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileFsSizeInformation:
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232107.aspx */
Packit 1fb8d4
			Stream_Write_UINT32(output, 24); /* Length */
Packit 1fb8d4
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 24))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
Packit 1fb8d4
			Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
Packit 1fb8d4
			Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Packit 1fb8d4
			Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileFsAttributeInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232101.aspx */
Packit 1fb8d4
			if ((length = ConvertToUnicode(sys_code_page, 0, diskType, -1, &outStr, 0) * 2) <= 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "ConvertToUnicode failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 12 + length); /* Length */
Packit 1fb8d4
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 12 + length))
Packit 1fb8d4
			{
Packit 1fb8d4
				free(outStr);
Packit 1fb8d4
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output,
Packit 1fb8d4
			                    FILE_CASE_SENSITIVE_SEARCH |
Packit 1fb8d4
			                    FILE_CASE_PRESERVED_NAMES |
Packit 1fb8d4
			                    FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
Packit 1fb8d4
			Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* FileSystemNameLength */
Packit 1fb8d4
			Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */
Packit 1fb8d4
			free(outStr);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileFsFullSizeInformation:
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232104.aspx */
Packit 1fb8d4
			Stream_Write_UINT32(output, 32); /* Length */
Packit 1fb8d4
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 32))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
Packit 1fb8d4
			Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */
Packit 1fb8d4
			Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
Packit 1fb8d4
			Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Packit 1fb8d4
			Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileFsDeviceInformation:
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232109.aspx */
Packit 1fb8d4
			Stream_Write_UINT32(output, 8); /* Length */
Packit 1fb8d4
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 8))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, FILE_DEVICE_DISK); /* DeviceType */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* Characteristics */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* Length */
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* http://msdn.microsoft.com/en-us/library/cc241518.aspx */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 FsInformationClass;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->output || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FsInformationClass);
Packit 1fb8d4
	Stream_Write_UINT32(irp->output, 0); /* Length */
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	const WCHAR* path;
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
	BYTE InitialQuery;
Packit 1fb8d4
	UINT32 PathLength;
Packit 1fb8d4
	UINT32 FsInformationClass;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp || !irp->Complete)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(irp->input) < 32)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, FsInformationClass);
Packit 1fb8d4
	Stream_Read_UINT8(irp->input, InitialQuery);
Packit 1fb8d4
	Stream_Read_UINT32(irp->input, PathLength);
Packit 1fb8d4
	Stream_Seek(irp->input, 23); /* Padding */
Packit 1fb8d4
	path = (WCHAR*) Stream_Pointer(irp->input);
Packit 1fb8d4
	file = drive_get_file_by_id(drive, irp->FileId);
Packit 1fb8d4
Packit 1fb8d4
	if (file == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = STATUS_UNSUCCESSFUL;
Packit 1fb8d4
		Stream_Write_UINT32(irp->output, 0); /* Length */
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength,
Packit 1fb8d4
	                                     irp->output))
Packit 1fb8d4
	{
Packit 1fb8d4
		irp->IoStatus = drive_map_windows_err(GetLastError());
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!drive || !irp)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	switch (irp->MinorFunction)
Packit 1fb8d4
	{
Packit 1fb8d4
		case IRP_MN_QUERY_DIRECTORY:
Packit 1fb8d4
			return drive_process_irp_query_directory(drive, irp);
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
Packit 1fb8d4
			return irp->Discard(irp);
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			irp->IoStatus = STATUS_NOT_SUPPORTED;
Packit 1fb8d4
			Stream_Write_UINT32(irp->output, 0); /* Length */
Packit 1fb8d4
			return irp->Complete(irp);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!drive || !irp)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
Packit 1fb8d4
	return irp->Complete(irp);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive || !irp)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	irp->IoStatus = STATUS_SUCCESS;
Packit 1fb8d4
Packit 1fb8d4
	switch (irp->MajorFunction)
Packit 1fb8d4
	{
Packit 1fb8d4
		case IRP_MJ_CREATE:
Packit 1fb8d4
			error = drive_process_irp_create(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_CLOSE:
Packit 1fb8d4
			error = drive_process_irp_close(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_READ:
Packit 1fb8d4
			error = drive_process_irp_read(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_WRITE:
Packit 1fb8d4
			error = drive_process_irp_write(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_QUERY_INFORMATION:
Packit 1fb8d4
			error = drive_process_irp_query_information(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_SET_INFORMATION:
Packit 1fb8d4
			error = drive_process_irp_set_information(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_QUERY_VOLUME_INFORMATION:
Packit 1fb8d4
			error = drive_process_irp_query_volume_information(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_LOCK_CONTROL:
Packit 1fb8d4
			error = drive_process_irp_silent_ignore(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_DIRECTORY_CONTROL:
Packit 1fb8d4
			error = drive_process_irp_directory_control(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case IRP_MJ_DEVICE_CONTROL:
Packit 1fb8d4
			error = drive_process_irp_device_control(drive, irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			irp->IoStatus = STATUS_NOT_SUPPORTED;
Packit 1fb8d4
			error = irp->Complete(irp);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI drive_thread_func(LPVOID arg)
Packit 1fb8d4
{
Packit 1fb8d4
	IRP* irp;
Packit 1fb8d4
	wMessage message;
Packit 1fb8d4
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive)
Packit 1fb8d4
	{
Packit 1fb8d4
		error = ERROR_INVALID_PARAMETER;
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!MessageQueue_Wait(drive->IrpQueue))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "MessageQueue_Wait failed!");
Packit 1fb8d4
			error = ERROR_INTERNAL_ERROR;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "MessageQueue_Peek failed!");
Packit 1fb8d4
			error = ERROR_INTERNAL_ERROR;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (message.id == WMQ_QUIT)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		irp = (IRP*) message.wParam;
Packit 1fb8d4
Packit 1fb8d4
		if (irp)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((error = drive_process_irp(drive, irp)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "drive_process_irp failed with error %"PRIu32"!", error);
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
fail:
Packit 1fb8d4
Packit 1fb8d4
	if (error && drive && drive->rdpcontext)
Packit 1fb8d4
		setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error");
Packit 1fb8d4
Packit 1fb8d4
	ExitThread(error);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_irp_request(DEVICE* device, IRP* irp)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*) irp, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "MessageQueue_Post failed!");
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT drive_free_int(DRIVE_DEVICE* drive)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	CloseHandle(drive->thread);
Packit 1fb8d4
	ListDictionary_Free(drive->files);
Packit 1fb8d4
	MessageQueue_Free(drive->IrpQueue);
Packit 1fb8d4
	Stream_Free(drive->device.data, TRUE);
Packit 1fb8d4
	free(drive->path);
Packit 1fb8d4
	free(drive);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_free(DEVICE* device)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!drive)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (MessageQueue_PostQuit(drive->IrpQueue, 0)
Packit 1fb8d4
	    && (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
Packit 1fb8d4
	{
Packit 1fb8d4
		error = GetLastError();
Packit 1fb8d4
		WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return drive_free_int(drive);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Helper function used for freeing list dictionary value object
Packit 1fb8d4
 */
Packit 1fb8d4
static void drive_file_objfree(void* obj)
Packit 1fb8d4
{
Packit 1fb8d4
	drive_file_free((DRIVE_FILE*) obj);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
Packit 1fb8d4
                                      const char* name, const char* path, BOOL automount)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t i, length;
Packit 1fb8d4
	DRIVE_DEVICE* drive;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
Packit 1fb8d4
	if (name[0] && path[0])
Packit 1fb8d4
	{
Packit 1fb8d4
		size_t pathLength = strnlen(path, MAX_PATH);
Packit 1fb8d4
		drive = (DRIVE_DEVICE*) calloc(1, sizeof(DRIVE_DEVICE));
Packit 1fb8d4
Packit 1fb8d4
		if (!drive)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		drive->device.type = RDPDR_DTYP_FILESYSTEM;
Packit 1fb8d4
		drive->device.name = name;
Packit 1fb8d4
		drive->device.IRPRequest = drive_irp_request;
Packit 1fb8d4
		drive->device.Free = drive_free;
Packit 1fb8d4
		drive->rdpcontext = pEntryPoints->rdpcontext;
Packit 1fb8d4
		drive->automount = automount;
Packit 1fb8d4
		length = strlen(name);
Packit 1fb8d4
		drive->device.data = Stream_New(NULL, length + 1);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->device.data)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
			error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i <= length; i++)
Packit 1fb8d4
			Stream_Write_UINT8(drive->device.data, name[i] < 0 ? '_' : name[i]);
Packit 1fb8d4
Packit 1fb8d4
		if ((pathLength > 1) && (path[pathLength - 1] == '/'))
Packit 1fb8d4
			pathLength --;
Packit 1fb8d4
Packit 1fb8d4
		if (ConvertToUnicode(sys_code_page, 0, path, pathLength, &drive->path, 0) <= 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "ConvertToUnicode failed!");
Packit 1fb8d4
			error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		drive->files = ListDictionary_New(TRUE);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->files)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "ListDictionary_New failed!");
Packit 1fb8d4
			error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree;
Packit 1fb8d4
		drive->IrpQueue = MessageQueue_New(NULL);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->IrpQueue)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "ListDictionary_New failed!");
Packit 1fb8d4
			error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman,
Packit 1fb8d4
		             (DEVICE*) drive)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error);
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!(drive->thread = CreateThread(NULL, 0, drive_thread_func, drive,
Packit 1fb8d4
		                                   CREATE_SUSPENDED, NULL)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "CreateThread failed!");
Packit 1fb8d4
			goto out_error;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ResumeThread(drive->thread);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
out_error:
Packit 1fb8d4
	drive_free_int(drive);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILTIN_CHANNELS
Packit 1fb8d4
#define DeviceServiceEntry	drive_DeviceServiceEntry
Packit 1fb8d4
#else
Packit 1fb8d4
#define DeviceServiceEntry	FREERDP_API DeviceServiceEntry
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	RDPDR_DRIVE* drive;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
#ifdef WIN32
Packit 1fb8d4
	char* dev;
Packit 1fb8d4
	int len;
Packit 1fb8d4
	char devlist[512], buf[512];
Packit 1fb8d4
	char* bufdup;
Packit 1fb8d4
	char* devdup;
Packit 1fb8d4
#endif
Packit 1fb8d4
	drive = (RDPDR_DRIVE*) pEntryPoints->device;
Packit 1fb8d4
#ifndef WIN32
Packit 1fb8d4
	sys_code_page = CP_UTF8;
Packit 1fb8d4
Packit 1fb8d4
	if (strcmp(drive->Path, "*") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* all drives */
Packit 1fb8d4
		free(drive->Path);
Packit 1fb8d4
		drive->Path = _strdup("/");
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->Path)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "_strdup failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(drive->Path, "%") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(drive->Path);
Packit 1fb8d4
		drive->Path = GetKnownPath(KNOWN_PATH_HOME);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->Path)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "_strdup failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
Packit 1fb8d4
#else
Packit 1fb8d4
	sys_code_page = GetACP();
Packit 1fb8d4
Packit 1fb8d4
	/* Special case: path[0] == '*' -> export all drives */
Packit 1fb8d4
	/* Special case: path[0] == '%' -> user home dir */
Packit 1fb8d4
	if (strcmp(drive->Path, "%") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		GetEnvironmentVariableA("USERPROFILE", buf, sizeof(buf));
Packit 1fb8d4
		PathCchAddBackslashA(buf, sizeof(buf));
Packit 1fb8d4
		free(drive->Path);
Packit 1fb8d4
		drive->Path = _strdup(buf);
Packit 1fb8d4
Packit 1fb8d4
		if (!drive->Path)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "_strdup failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(drive->Path, "*") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		int i;
Packit 1fb8d4
		/* Enumerate all devices: */
Packit 1fb8d4
		GetLogicalDriveStringsA(sizeof(devlist) - 1, devlist);
Packit 1fb8d4
Packit 1fb8d4
		for (dev = devlist, i = 0; *dev; dev += 4, i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (*dev > 'B')
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Suppress disk drives A and B to avoid pesty messages */
Packit 1fb8d4
				len = sprintf_s(buf, sizeof(buf) - 4, "%s", drive->Name);
Packit 1fb8d4
				buf[len] = '_';
Packit 1fb8d4
				buf[len + 1] = dev[0];
Packit 1fb8d4
				buf[len + 2] = 0;
Packit 1fb8d4
				buf[len + 3] = 0;
Packit 1fb8d4
Packit 1fb8d4
				if (!(bufdup = _strdup(buf)))
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "_strdup failed!");
Packit 1fb8d4
					return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!(devdup = _strdup(dev)))
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "_strdup failed!");
Packit 1fb8d4
					return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE)))
Packit 1fb8d4
				{
Packit 1fb8d4
					break;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return error;
Packit 1fb8d4
}