1 /**
2  * WinPR: Windows Portable Runtime
3  * Asynchronous I/O Functions
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <winpr/io.h>
25 
26 #ifndef _WIN32
27 
28 #include "io.h"
29 
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #include <winpr/crt.h>
43 #include <winpr/path.h>
44 #include <winpr/file.h>
45 
46 /**
47  * I/O Manager Routines
48  * http://msdn.microsoft.com/en-us/library/windows/hardware/ff551797/
49  *
50  * These routines are only accessible to kernel drivers, but we need
51  * similar functionality in WinPR in user space.
52  *
53  * This is a best effort non-conflicting port of this API meant for
54  * non-Windows, WinPR usage only.
55  *
56  * References:
57  *
58  * Device Objects and Device Stacks:
59  * http://msdn.microsoft.com/en-us/library/windows/hardware/ff543153/
60  *
61  * Driver Development Part 1: Introduction to Drivers:
62  * http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers/
63  */
64 
65 #define DEVICE_FILE_PREFIX_PATH "\\Device\\"
66 
GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)67 static char* GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)
68 {
69 	char* lpFileName;
70 
71 	if (!lpName)
72 		return NULL;
73 
74 	if (strncmp(lpName, DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH) - 1) != 0)
75 		return NULL;
76 
77 	lpFileName =
78 	    _strdup(&lpName[strnlen(DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH))]);
79 	return lpFileName;
80 }
81 
GetDeviceFileUnixDomainSocketBaseFilePathA(void)82 static char* GetDeviceFileUnixDomainSocketBaseFilePathA(void)
83 {
84 	char* lpTempPath;
85 	char* lpPipePath;
86 	lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
87 
88 	if (!lpTempPath)
89 		return NULL;
90 
91 	lpPipePath = GetCombinedPath(lpTempPath, ".device");
92 	free(lpTempPath);
93 	return lpPipePath;
94 }
95 
GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)96 static char* GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)
97 {
98 	char* lpPipePath = NULL;
99 	char* lpFileName = NULL;
100 	char* lpFilePath = NULL;
101 	lpPipePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
102 
103 	if (!lpPipePath)
104 		return NULL;
105 
106 	lpFileName = GetDeviceFileNameWithoutPrefixA(lpName);
107 
108 	if (!lpFileName)
109 	{
110 		free(lpPipePath);
111 		return NULL;
112 	}
113 
114 	lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName);
115 	free(lpPipePath);
116 	free(lpFileName);
117 	return lpFilePath;
118 }
119 
120 /**
121  * IoCreateDevice:
122  * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548397/
123  */
124 
_IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject,ULONG DeviceExtensionSize,PUNICODE_STRING DeviceName,DEVICE_TYPE DeviceType,ULONG DeviceCharacteristics,BOOLEAN Exclusive,PDEVICE_OBJECT_EX * DeviceObject)125 NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtensionSize,
126                            PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType,
127                            ULONG DeviceCharacteristics, BOOLEAN Exclusive,
128                            PDEVICE_OBJECT_EX* DeviceObject)
129 {
130 	int status;
131 	char* DeviceBasePath;
132 	DEVICE_OBJECT_EX* pDeviceObjectEx;
133 	DeviceBasePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
134 
135 	if (!DeviceBasePath)
136 		return STATUS_NO_MEMORY;
137 
138 	if (!winpr_PathFileExists(DeviceBasePath))
139 	{
140 		if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
141 		{
142 			free(DeviceBasePath);
143 			return STATUS_ACCESS_DENIED;
144 		}
145 	}
146 
147 	free(DeviceBasePath);
148 	pDeviceObjectEx = (DEVICE_OBJECT_EX*)calloc(1, sizeof(DEVICE_OBJECT_EX));
149 
150 	if (!pDeviceObjectEx)
151 		return STATUS_NO_MEMORY;
152 
153 	ConvertFromUnicode(CP_UTF8, 0, DeviceName->Buffer, DeviceName->Length / 2,
154 	                   &(pDeviceObjectEx->DeviceName), 0, NULL, NULL);
155 
156 	if (!pDeviceObjectEx->DeviceName)
157 	{
158 		free(pDeviceObjectEx);
159 		return STATUS_NO_MEMORY;
160 	}
161 
162 	pDeviceObjectEx->DeviceFileName =
163 	    GetDeviceFileUnixDomainSocketFilePathA(pDeviceObjectEx->DeviceName);
164 
165 	if (!pDeviceObjectEx->DeviceFileName)
166 	{
167 		free(pDeviceObjectEx->DeviceName);
168 		free(pDeviceObjectEx);
169 		return STATUS_NO_MEMORY;
170 	}
171 
172 	if (winpr_PathFileExists(pDeviceObjectEx->DeviceFileName))
173 	{
174 		if (unlink(pDeviceObjectEx->DeviceFileName) == -1)
175 		{
176 			free(pDeviceObjectEx->DeviceName);
177 			free(pDeviceObjectEx->DeviceFileName);
178 			free(pDeviceObjectEx);
179 			return STATUS_ACCESS_DENIED;
180 		}
181 	}
182 
183 	status = mkfifo(pDeviceObjectEx->DeviceFileName, 0666);
184 
185 	if (status != 0)
186 	{
187 		free(pDeviceObjectEx->DeviceName);
188 		free(pDeviceObjectEx->DeviceFileName);
189 		free(pDeviceObjectEx);
190 
191 		switch (errno)
192 		{
193 			case EACCES:
194 				return STATUS_ACCESS_DENIED;
195 
196 			case EEXIST:
197 				return STATUS_OBJECT_NAME_EXISTS;
198 
199 			case ENAMETOOLONG:
200 				return STATUS_NAME_TOO_LONG;
201 
202 			case ENOENT:
203 			case ENOTDIR:
204 				return STATUS_NOT_A_DIRECTORY;
205 
206 			case ENOSPC:
207 				return STATUS_DISK_FULL;
208 
209 			default:
210 				return STATUS_INTERNAL_ERROR;
211 		}
212 	}
213 
214 	*((ULONG_PTR*)(DeviceObject)) = (ULONG_PTR)pDeviceObjectEx;
215 	return STATUS_SUCCESS;
216 }
217 
218 /**
219  * IoDeleteDevice:
220  * http://msdn.microsoft.com/en-us/library/windows/hardware/ff549083/
221  */
222 
_IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)223 VOID _IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)
224 {
225 	DEVICE_OBJECT_EX* pDeviceObjectEx;
226 	pDeviceObjectEx = (DEVICE_OBJECT_EX*)DeviceObject;
227 
228 	if (!pDeviceObjectEx)
229 		return;
230 
231 	unlink(pDeviceObjectEx->DeviceFileName);
232 	free(pDeviceObjectEx->DeviceName);
233 	free(pDeviceObjectEx->DeviceFileName);
234 	free(pDeviceObjectEx);
235 }
236 
237 #endif
238