Blame channels/drive/client/drive_main.c

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