freerdp/winpr/libwinpr/io/device.c

238 lines
5.4 KiB
C

/**
* WinPR: Windows Portable Runtime
* Asynchronous I/O Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/io.h>
#ifndef _WIN32
#include "io.h"
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
/**
* I/O Manager Routines
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551797/
*
* These routines are only accessible to kernel drivers, but we need
* similar functionality in WinPR in user space.
*
* This is a best effort non-conflicting port of this API meant for
* non-Windows, WinPR usage only.
*
* References:
*
* Device Objects and Device Stacks:
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff543153/
*
* Driver Development Part 1: Introduction to Drivers:
* http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers/
*/
#define DEVICE_FILE_PREFIX_PATH "\\Device\\"
static char* GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName;
if (!lpName)
return NULL;
if (strncmp(lpName, DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH) - 1) != 0)
return NULL;
lpFileName =
_strdup(&lpName[strnlen(DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH))]);
return lpFileName;
}
static char* GetDeviceFileUnixDomainSocketBaseFilePathA(void)
{
char* lpTempPath;
char* lpPipePath;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
if (!lpTempPath)
return NULL;
lpPipePath = GetCombinedPath(lpTempPath, ".device");
free(lpTempPath);
return lpPipePath;
}
static char* GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath = NULL;
char* lpFileName = NULL;
char* lpFilePath = NULL;
lpPipePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
if (!lpPipePath)
return NULL;
lpFileName = GetDeviceFileNameWithoutPrefixA(lpName);
if (!lpFileName)
{
free(lpPipePath);
return NULL;
}
lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
/**
* IoCreateDevice:
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff548397/
*/
NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtensionSize,
PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType,
ULONG DeviceCharacteristics, BOOLEAN Exclusive,
PDEVICE_OBJECT_EX* DeviceObject)
{
int status;
char* DeviceBasePath;
DEVICE_OBJECT_EX* pDeviceObjectEx;
DeviceBasePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
if (!DeviceBasePath)
return STATUS_NO_MEMORY;
if (!winpr_PathFileExists(DeviceBasePath))
{
if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
{
free(DeviceBasePath);
return STATUS_ACCESS_DENIED;
}
}
free(DeviceBasePath);
pDeviceObjectEx = (DEVICE_OBJECT_EX*)calloc(1, sizeof(DEVICE_OBJECT_EX));
if (!pDeviceObjectEx)
return STATUS_NO_MEMORY;
ConvertFromUnicode(CP_UTF8, 0, DeviceName->Buffer, DeviceName->Length / 2,
&(pDeviceObjectEx->DeviceName), 0, NULL, NULL);
if (!pDeviceObjectEx->DeviceName)
{
free(pDeviceObjectEx);
return STATUS_NO_MEMORY;
}
pDeviceObjectEx->DeviceFileName =
GetDeviceFileUnixDomainSocketFilePathA(pDeviceObjectEx->DeviceName);
if (!pDeviceObjectEx->DeviceFileName)
{
free(pDeviceObjectEx->DeviceName);
free(pDeviceObjectEx);
return STATUS_NO_MEMORY;
}
if (winpr_PathFileExists(pDeviceObjectEx->DeviceFileName))
{
if (unlink(pDeviceObjectEx->DeviceFileName) == -1)
{
free(pDeviceObjectEx->DeviceName);
free(pDeviceObjectEx->DeviceFileName);
free(pDeviceObjectEx);
return STATUS_ACCESS_DENIED;
}
}
status = mkfifo(pDeviceObjectEx->DeviceFileName, 0666);
if (status != 0)
{
free(pDeviceObjectEx->DeviceName);
free(pDeviceObjectEx->DeviceFileName);
free(pDeviceObjectEx);
switch (errno)
{
case EACCES:
return STATUS_ACCESS_DENIED;
case EEXIST:
return STATUS_OBJECT_NAME_EXISTS;
case ENAMETOOLONG:
return STATUS_NAME_TOO_LONG;
case ENOENT:
case ENOTDIR:
return STATUS_NOT_A_DIRECTORY;
case ENOSPC:
return STATUS_DISK_FULL;
default:
return STATUS_INTERNAL_ERROR;
}
}
*((ULONG_PTR*)(DeviceObject)) = (ULONG_PTR)pDeviceObjectEx;
return STATUS_SUCCESS;
}
/**
* IoDeleteDevice:
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff549083/
*/
VOID _IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)
{
DEVICE_OBJECT_EX* pDeviceObjectEx;
pDeviceObjectEx = (DEVICE_OBJECT_EX*)DeviceObject;
if (!pDeviceObjectEx)
return;
unlink(pDeviceObjectEx->DeviceFileName);
free(pDeviceObjectEx->DeviceName);
free(pDeviceObjectEx->DeviceFileName);
free(pDeviceObjectEx);
}
#endif