Blame winpr/libwinpr/io/device.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Asynchronous I/O Functions
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/io.h>
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
Packit 1fb8d4
#include "io.h"
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_UNISTD_H
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <sys/types.h>
Packit 1fb8d4
#include <sys/stat.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/file.h>
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * I/O Manager Routines
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff551797/
Packit 1fb8d4
 *
Packit 1fb8d4
 * These routines are only accessible to kernel drivers, but we need
Packit 1fb8d4
 * similar functionality in WinPR in user space.
Packit 1fb8d4
 *
Packit 1fb8d4
 * This is a best effort non-conflicting port of this API meant for
Packit 1fb8d4
 * non-Windows, WinPR usage only.
Packit 1fb8d4
 *
Packit 1fb8d4
 * References:
Packit 1fb8d4
 *
Packit 1fb8d4
 * Device Objects and Device Stacks:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff543153/
Packit 1fb8d4
 *
Packit 1fb8d4
 * Driver Development Part 1: Introduction to Drivers:
Packit 1fb8d4
 * http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
#define DEVICE_FILE_PREFIX_PATH "\\Device\\"
Packit 1fb8d4
Packit Service 5a9772
static char* GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)
Packit 1fb8d4
{
Packit 1fb8d4
	char* lpFileName;
Packit 1fb8d4
Packit 1fb8d4
	if (!lpName)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (strncmp(lpName, DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH) - 1) != 0)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	lpFileName =
Packit Service 5a9772
	    _strdup(&lpName[strnlen(DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH))]);
Packit 1fb8d4
	return lpFileName;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static char* GetDeviceFileUnixDomainSocketBaseFilePathA(void)
Packit 1fb8d4
{
Packit 1fb8d4
	char* lpTempPath;
Packit 1fb8d4
	char* lpPipePath;
Packit 1fb8d4
	lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
Packit 1fb8d4
Packit 1fb8d4
	if (!lpTempPath)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	lpPipePath = GetCombinedPath(lpTempPath, ".device");
Packit 1fb8d4
	free(lpTempPath);
Packit 1fb8d4
	return lpPipePath;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static char* GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)
Packit 1fb8d4
{
Packit 1fb8d4
	char* lpPipePath = NULL;
Packit 1fb8d4
	char* lpFileName = NULL;
Packit 1fb8d4
	char* lpFilePath = NULL;
Packit 1fb8d4
	lpPipePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
Packit 1fb8d4
Packit 1fb8d4
	if (!lpPipePath)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	lpFileName = GetDeviceFileNameWithoutPrefixA(lpName);
Packit 1fb8d4
Packit 1fb8d4
	if (!lpFileName)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(lpPipePath);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName);
Packit 1fb8d4
	free(lpPipePath);
Packit 1fb8d4
	free(lpFileName);
Packit 1fb8d4
	return lpFilePath;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * IoCreateDevice:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548397/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtensionSize,
Packit Service 5a9772
                           PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType,
Packit Service 5a9772
                           ULONG DeviceCharacteristics, BOOLEAN Exclusive,
Packit 1fb8d4
                           PDEVICE_OBJECT_EX* DeviceObject)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	char* DeviceBasePath;
Packit 1fb8d4
	DEVICE_OBJECT_EX* pDeviceObjectEx;
Packit 1fb8d4
	DeviceBasePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
Packit 1fb8d4
Packit 1fb8d4
	if (!DeviceBasePath)
Packit 1fb8d4
		return STATUS_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	if (!PathFileExistsA(DeviceBasePath))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(DeviceBasePath);
Packit 1fb8d4
			return STATUS_ACCESS_DENIED;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(DeviceBasePath);
Packit Service 5a9772
	pDeviceObjectEx = (DEVICE_OBJECT_EX*)calloc(1, sizeof(DEVICE_OBJECT_EX));
Packit 1fb8d4
Packit 1fb8d4
	if (!pDeviceObjectEx)
Packit 1fb8d4
		return STATUS_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	ConvertFromUnicode(CP_UTF8, 0, DeviceName->Buffer, DeviceName->Length / 2,
Packit 1fb8d4
	                   &(pDeviceObjectEx->DeviceName), 0, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (!pDeviceObjectEx->DeviceName)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(pDeviceObjectEx);
Packit 1fb8d4
		return STATUS_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pDeviceObjectEx->DeviceFileName =
Packit Service 5a9772
	    GetDeviceFileUnixDomainSocketFilePathA(pDeviceObjectEx->DeviceName);
Packit 1fb8d4
Packit 1fb8d4
	if (!pDeviceObjectEx->DeviceFileName)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(pDeviceObjectEx->DeviceName);
Packit 1fb8d4
		free(pDeviceObjectEx);
Packit 1fb8d4
		return STATUS_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (PathFileExistsA(pDeviceObjectEx->DeviceFileName))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (unlink(pDeviceObjectEx->DeviceFileName) == -1)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(pDeviceObjectEx->DeviceName);
Packit 1fb8d4
			free(pDeviceObjectEx->DeviceFileName);
Packit 1fb8d4
			free(pDeviceObjectEx);
Packit 1fb8d4
			return STATUS_ACCESS_DENIED;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = mkfifo(pDeviceObjectEx->DeviceFileName, 0666);
Packit 1fb8d4
Packit 1fb8d4
	if (status != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(pDeviceObjectEx->DeviceName);
Packit 1fb8d4
		free(pDeviceObjectEx->DeviceFileName);
Packit 1fb8d4
		free(pDeviceObjectEx);
Packit 1fb8d4
Packit 1fb8d4
		switch (errno)
Packit 1fb8d4
		{
Packit 1fb8d4
			case EACCES:
Packit 1fb8d4
				return STATUS_ACCESS_DENIED;
Packit 1fb8d4
Packit 1fb8d4
			case EEXIST:
Packit 1fb8d4
				return STATUS_OBJECT_NAME_EXISTS;
Packit 1fb8d4
Packit 1fb8d4
			case ENAMETOOLONG:
Packit 1fb8d4
				return STATUS_NAME_TOO_LONG;
Packit 1fb8d4
Packit 1fb8d4
			case ENOENT:
Packit 1fb8d4
			case ENOTDIR:
Packit 1fb8d4
				return STATUS_NOT_A_DIRECTORY;
Packit 1fb8d4
Packit 1fb8d4
			case ENOSPC:
Packit 1fb8d4
				return STATUS_DISK_FULL;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				return STATUS_INTERNAL_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	*((ULONG_PTR*)(DeviceObject)) = (ULONG_PTR)pDeviceObjectEx;
Packit 1fb8d4
	return STATUS_SUCCESS;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * IoDeleteDevice:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff549083/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
VOID _IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)
Packit 1fb8d4
{
Packit 1fb8d4
	DEVICE_OBJECT_EX* pDeviceObjectEx;
Packit Service 5a9772
	pDeviceObjectEx = (DEVICE_OBJECT_EX*)DeviceObject;
Packit 1fb8d4
Packit 1fb8d4
	if (!pDeviceObjectEx)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	unlink(pDeviceObjectEx->DeviceFileName);
Packit 1fb8d4
	free(pDeviceObjectEx->DeviceName);
Packit 1fb8d4
	free(pDeviceObjectEx->DeviceFileName);
Packit 1fb8d4
	free(pDeviceObjectEx);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif